diff options
Diffstat (limited to 'deps')
57 files changed, 962 insertions, 386 deletions
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index d016b794ff..d42a2f1564 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,34 @@ +2015-01-07: Version 3.32.3 + + Performance and stability improvements on all platforms. + + +2015-01-07: Version 3.32.2 + + Performance and stability improvements on all platforms. + + +2015-01-07: Version 3.32.1 + + [turbofan] Don't crash when typing load from a Uint8ClampedArray + (Chromium issue 446156). + + [turbofan] Truncation of Bit/Word8/16 to Word32 is a no-op (Chromium + issue 445859). + + [x64] Rearrange code for OOB integer loads (Chromium issue 445858). + + Fix %NeverOptimizeFunction() intrinsic (Chromium issue 445732). + + [turbofan] Fix invalid bounds check with overflowing offset (Chromium + issue 445267). + + [turbofan] Raise max virtual registers and call parameter limit (issue + 3786). + + Performance and stability improvements on all platforms. + + 2014-12-23: Version 3.31.74 [turbofan] Turn DCHECK for fixed slot index into a CHECK (Chromium issue diff --git a/deps/v8/DEPS b/deps/v8/DEPS index e85604b0b7..a81c7ecc38 100644 --- a/deps/v8/DEPS +++ b/deps/v8/DEPS @@ -18,7 +18,7 @@ deps = { "v8/testing/gmock": Var("git_url") + "/external/googlemock.git" + "@" + "29763965ab52f24565299976b936d1265cb6a271", # from svn revision 501 "v8/tools/clang": - Var("git_url") + "/chromium/src/tools/clang.git" + "@" + "90fb65e7a9a5c9d6d9613dfb0e78921c52ca9cfc", + Var("git_url") + "/chromium/src/tools/clang.git" + "@" + "c945be21f6485fa177b43814f910b76cce921653", } deps_os = { diff --git a/deps/v8/build/features.gypi b/deps/v8/build/features.gypi index 25041ce42f..465eba9148 100644 --- a/deps/v8/build/features.gypi +++ b/deps/v8/build/features.gypi @@ -117,7 +117,7 @@ 'Release': { 'variables': { 'v8_enable_extra_checks%': 0, - 'v8_enable_handle_zapping%': 1, + 'v8_enable_handle_zapping%': 0, }, 'conditions': [ ['v8_enable_extra_checks==1', { diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 61e565f97b..88d3c889b9 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -1780,6 +1780,7 @@ Local<Script> ScriptCompiler::Compile(Isolate* v8_isolate, // Do the parsing tasks which need to be done on the main thread. This will // also handle parse errors. source->parser->Internalize(); + source->parser->HandleSourceURLComments(); i::Handle<i::SharedFunctionInfo> result = i::Handle<i::SharedFunctionInfo>::null(); diff --git a/deps/v8/src/base/platform/platform-freebsd.cc b/deps/v8/src/base/platform/platform-freebsd.cc index 58316f8bc1..507b946f69 100644 --- a/deps/v8/src/base/platform/platform-freebsd.cc +++ b/deps/v8/src/base/platform/platform-freebsd.cc @@ -141,7 +141,7 @@ std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() { if (bytes_read < 8) break; unsigned end = StringToLong(addr_buffer); char buffer[MAP_LENGTH]; - bytes_read = -1; + int bytes_read = -1; do { bytes_read++; if (bytes_read >= MAP_LENGTH - 1) diff --git a/deps/v8/src/base/platform/platform-posix.cc b/deps/v8/src/base/platform/platform-posix.cc index 64aed2b8d1..c2fa26a9ea 100644 --- a/deps/v8/src/base/platform/platform-posix.cc +++ b/deps/v8/src/base/platform/platform-posix.cc @@ -261,7 +261,7 @@ int OS::GetCurrentThreadId() { #elif V8_OS_ANDROID return static_cast<int>(gettid()); #else - return static_cast<int>(reinterpret_cast<intptr_t>(pthread_self())); + return static_cast<int>(pthread_self()); #endif } diff --git a/deps/v8/src/compiler/control-reducer.cc b/deps/v8/src/compiler/control-reducer.cc index e738ccf24e..eef8a49fb1 100644 --- a/deps/v8/src/compiler/control-reducer.cc +++ b/deps/v8/src/compiler/control-reducer.cc @@ -196,6 +196,9 @@ class ControlReducerImpl { merge = graph()->NewNode(common_->Merge(2), merge, loop); end->ReplaceInput(0, merge); to_add = merge; + // Mark the node as visited so that we can revisit later. + EnsureStateSize(merge->id()); + state_[merge->id()] = kVisited; } else { // Append a new input to the final merge at the end. merge->AppendInput(graph()->zone(), loop); @@ -293,14 +296,17 @@ class ControlReducerImpl { if (replacement != node) Recurse(replacement); } + void EnsureStateSize(size_t id) { + if (id >= state_.size()) { + state_.resize((3 * id) / 2, kUnvisited); + } + } + // Push a node onto the stack if its state is {kUnvisited} or {kRevisit}. bool Recurse(Node* node) { size_t id = static_cast<size_t>(node->id()); - if (id < state_.size()) { - if (state_[id] != kRevisit && state_[id] != kUnvisited) return false; - } else { - state_.resize((3 * id) / 2, kUnvisited); - } + EnsureStateSize(id); + if (state_[id] != kRevisit && state_[id] != kUnvisited) return false; Push(node); return true; } @@ -403,6 +409,14 @@ class ControlReducerImpl { if (n <= 1) return dead(); // No non-control inputs. if (n == 2) return node->InputAt(0); // Only one non-control input. + // Never remove an effect phi from a (potentially non-terminating) loop. + // Otherwise, we might end up eliminating effect nodes, such as calls, + // before the loop. + if (node->opcode() == IrOpcode::kEffectPhi && + NodeProperties::GetControlInput(node)->opcode() == IrOpcode::kLoop) { + return node; + } + Node* replacement = NULL; Node::Inputs inputs = node->inputs(); for (InputIter it = inputs.begin(); n > 1; --n, ++it) { diff --git a/deps/v8/src/compiler/js-typed-lowering.cc b/deps/v8/src/compiler/js-typed-lowering.cc index 2338866d6d..761837576b 100644 --- a/deps/v8/src/compiler/js-typed-lowering.cc +++ b/deps/v8/src/compiler/js-typed-lowering.cc @@ -490,124 +490,34 @@ Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { } -Reduction JSTypedLowering::ReduceJSToBooleanInput(Node* input) { - if (input->opcode() == IrOpcode::kJSToBoolean) { - // Recursively try to reduce the input first. - Reduction result = ReduceJSToBoolean(input); - if (result.Changed()) return result; - return Changed(input); // JSToBoolean(JSToBoolean(x)) => JSToBoolean(x) - } - // Check if we have a cached conversion. - Node* conversion = FindConversion<IrOpcode::kJSToBoolean>(input); - if (conversion) return Replace(conversion); +Reduction JSTypedLowering::ReduceJSUnaryNot(Node* node) { + Node* input = node->InputAt(0); Type* input_type = NodeProperties::GetBounds(input).upper; if (input_type->Is(Type::Boolean())) { - return Changed(input); // JSToBoolean(x:boolean) => x - } - if (input_type->Is(Type::Undefined())) { - // JSToBoolean(undefined) => #false - return Replace(jsgraph()->FalseConstant()); - } - if (input_type->Is(Type::Null())) { - // JSToBoolean(null) => #false - return Replace(jsgraph()->FalseConstant()); - } - if (input_type->Is(Type::DetectableReceiver())) { - // JSToBoolean(x:detectable) => #true - return Replace(jsgraph()->TrueConstant()); - } - if (input_type->Is(Type::Undetectable())) { - // JSToBoolean(x:undetectable) => #false - return Replace(jsgraph()->FalseConstant()); - } - if (input_type->Is(Type::OrderedNumber())) { - // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0)) - Node* cmp = graph()->NewNode(simplified()->NumberEqual(), input, - jsgraph()->ZeroConstant()); - Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp); - return Replace(inv); - } - if (input_type->Is(Type::String())) { - // JSToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0)) - FieldAccess access = AccessBuilder::ForStringLength(); - Node* length = graph()->NewNode(simplified()->LoadField(access), input, - graph()->start(), graph()->start()); - Node* cmp = graph()->NewNode(simplified()->NumberEqual(), length, - jsgraph()->ZeroConstant()); - Node* inv = graph()->NewNode(simplified()->BooleanNot(), cmp); - return Replace(inv); + // JSUnaryNot(x:boolean,context) => BooleanNot(x) + node->set_op(simplified()->BooleanNot()); + node->TrimInputCount(1); + return Changed(node); } - return NoChange(); + // JSUnaryNot(x,context) => BooleanNot(AnyToBoolean(x)) + node->set_op(simplified()->BooleanNot()); + node->ReplaceInput(0, graph()->NewNode(simplified()->AnyToBoolean(), input)); + node->TrimInputCount(1); + return Changed(node); } Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) { - // Try to reduce the input first. - Node* const input = node->InputAt(0); - Reduction reduction = ReduceJSToBooleanInput(input); - if (reduction.Changed()) return reduction; - if (input->opcode() == IrOpcode::kPhi) { - // JSToBoolean(phi(x1,...,xn,control),context) - // => phi(JSToBoolean(x1,no-context),...,JSToBoolean(xn,no-context)) - int const input_count = input->InputCount() - 1; - Node* const control = input->InputAt(input_count); - DCHECK_LE(0, input_count); - DCHECK(NodeProperties::IsControl(control)); - DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Boolean())); - DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Boolean())); - node->set_op(common()->Phi(kMachAnyTagged, input_count)); - for (int i = 0; i < input_count; ++i) { - // We must be very careful not to introduce cycles when pushing - // operations into phis. It is safe for {value}, since it appears - // as input to the phi that we are replacing, but it's not safe - // to simply reuse the context of the {node}. However, ToBoolean() - // does not require a context anyways, so it's safe to discard it - // here and pass the dummy context. - Node* const value = ConvertToBoolean(input->InputAt(i)); - if (i < node->InputCount()) { - node->ReplaceInput(i, value); - } else { - node->AppendInput(graph()->zone(), value); - } - } - if (input_count < node->InputCount()) { - node->ReplaceInput(input_count, control); - } else { - node->AppendInput(graph()->zone(), control); - } - node->TrimInputCount(input_count + 1); - return Changed(node); - } - if (input->opcode() == IrOpcode::kSelect) { - // JSToBoolean(select(c,x1,x2),context) - // => select(c,JSToBoolean(x1,no-context),...,JSToBoolean(x2,no-context)) - int const input_count = input->InputCount(); - BranchHint const input_hint = SelectParametersOf(input->op()).hint(); - DCHECK_EQ(3, input_count); - DCHECK(NodeProperties::GetBounds(node).upper->Is(Type::Boolean())); - DCHECK(!NodeProperties::GetBounds(input).upper->Is(Type::Boolean())); - node->set_op(common()->Select(kMachAnyTagged, input_hint)); - node->InsertInput(graph()->zone(), 0, input->InputAt(0)); - for (int i = 1; i < input_count; ++i) { - // We must be very careful not to introduce cycles when pushing - // operations into selects. It is safe for {value}, since it appears - // as input to the select that we are replacing, but it's not safe - // to simply reuse the context of the {node}. However, ToBoolean() - // does not require a context anyways, so it's safe to discard it - // here and pass the dummy context. - Node* const value = ConvertToBoolean(input->InputAt(i)); - node->ReplaceInput(i, value); - } - DCHECK_EQ(3, node->InputCount()); - return Changed(node); - } - InsertConversion(node); - if (node->InputAt(1) != jsgraph()->NoContextConstant()) { - // JSToBoolean(x,context) => JSToBoolean(x,no-context) - node->ReplaceInput(1, jsgraph()->NoContextConstant()); - return Changed(node); + Node* input = node->InputAt(0); + Type* input_type = NodeProperties::GetBounds(input).upper; + if (input_type->Is(Type::Boolean())) { + // JSToBoolean(x:boolean,context) => x + return Replace(input); } - return NoChange(); + // JSToBoolean(x,context) => AnyToBoolean(x) + node->set_op(simplified()->AnyToBoolean()); + node->TrimInputCount(1); + return Changed(node); } @@ -927,14 +837,36 @@ Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) { Reduction JSTypedLowering::Reduce(Node* node) { // Check if the output type is a singleton. In that case we already know the - // result value and can simply replace the node unless there are effects. + // result value and can simply replace the node if it's eliminable. if (NodeProperties::IsTyped(node) && - NodeProperties::GetBounds(node).upper->IsConstant() && !IrOpcode::IsLeafOpcode(node->opcode()) && - node->op()->EffectOutputCount() == 0) { - return ReplaceEagerly(node, jsgraph()->Constant( - NodeProperties::GetBounds(node).upper->AsConstant()->Value())); - // TODO(neis): Extend this to Range(x,x), NaN, MinusZero, ...? + node->op()->HasProperty(Operator::kEliminatable)) { + Type* upper = NodeProperties::GetBounds(node).upper; + if (upper->IsConstant()) { + Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value()); + NodeProperties::ReplaceWithValue(node, replacement); + return Changed(replacement); + } else if (upper->Is(Type::MinusZero())) { + Node* replacement = jsgraph()->Constant(factory()->minus_zero_value()); + NodeProperties::ReplaceWithValue(node, replacement); + return Changed(replacement); + } else if (upper->Is(Type::NaN())) { + Node* replacement = jsgraph()->NaNConstant(); + NodeProperties::ReplaceWithValue(node, replacement); + return Changed(replacement); + } else if (upper->Is(Type::Null())) { + Node* replacement = jsgraph()->NullConstant(); + NodeProperties::ReplaceWithValue(node, replacement); + return Changed(replacement); + } else if (upper->Is(Type::PlainNumber()) && upper->Min() == upper->Max()) { + Node* replacement = jsgraph()->Constant(upper->Min()); + NodeProperties::ReplaceWithValue(node, replacement); + return Changed(replacement); + } else if (upper->Is(Type::Undefined())) { + Node* replacement = jsgraph()->UndefinedConstant(); + NodeProperties::ReplaceWithValue(node, replacement); + return Changed(replacement); + } } switch (node->opcode()) { case IrOpcode::kJSEqual: @@ -972,18 +904,8 @@ Reduction JSTypedLowering::Reduce(Node* node) { return ReduceNumberBinop(node, simplified()->NumberDivide()); case IrOpcode::kJSModulus: return ReduceNumberBinop(node, simplified()->NumberModulus()); - case IrOpcode::kJSUnaryNot: { - Reduction result = ReduceJSToBooleanInput(node->InputAt(0)); - if (result.Changed()) { - // JSUnaryNot(x:boolean) => BooleanNot(x) - node = result.replacement(); - } else { - // JSUnaryNot(x) => BooleanNot(JSToBoolean(x)) - node->set_op(javascript()->ToBoolean()); - } - Node* value = graph()->NewNode(simplified()->BooleanNot(), node); - return Replace(value); - } + case IrOpcode::kJSUnaryNot: + return ReduceJSUnaryNot(node); case IrOpcode::kJSToBoolean: return ReduceJSToBoolean(node); case IrOpcode::kJSToNumber: @@ -1005,17 +927,6 @@ Reduction JSTypedLowering::Reduce(Node* node) { } -Node* JSTypedLowering::ConvertToBoolean(Node* input) { - // Avoid inserting too many eager ToBoolean() operations. - Reduction const reduction = ReduceJSToBooleanInput(input); - if (reduction.Changed()) return reduction.replacement(); - Node* const conversion = graph()->NewNode(javascript()->ToBoolean(), input, - jsgraph()->NoContextConstant()); - InsertConversion(conversion); - return conversion; -} - - Node* JSTypedLowering::ConvertToNumber(Node* input) { DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive())); // Avoid inserting too many eager ToNumber() operations. @@ -1043,8 +954,7 @@ Node* JSTypedLowering::FindConversion(Node* input) { void JSTypedLowering::InsertConversion(Node* conversion) { - DCHECK(conversion->opcode() == IrOpcode::kJSToBoolean || - conversion->opcode() == IrOpcode::kJSToNumber); + DCHECK(conversion->opcode() == IrOpcode::kJSToNumber); size_t const input_id = conversion->InputAt(0)->id(); if (input_id >= conversions_.size()) { conversions_.resize(2 * input_id + 1); diff --git a/deps/v8/src/compiler/js-typed-lowering.h b/deps/v8/src/compiler/js-typed-lowering.h index aa7510bb0e..838085e40c 100644 --- a/deps/v8/src/compiler/js-typed-lowering.h +++ b/deps/v8/src/compiler/js-typed-lowering.h @@ -41,7 +41,7 @@ class JSTypedLowering FINAL : public Reducer { Reduction ReduceJSStoreContext(Node* node); Reduction ReduceJSEqual(Node* node, bool invert); Reduction ReduceJSStrictEqual(Node* node, bool invert); - Reduction ReduceJSToBooleanInput(Node* input); + Reduction ReduceJSUnaryNot(Node* node); Reduction ReduceJSToBoolean(Node* node); Reduction ReduceJSToNumberInput(Node* input); Reduction ReduceJSToNumber(Node* node); @@ -52,7 +52,6 @@ class JSTypedLowering FINAL : public Reducer { Reduction ReduceUI32Shift(Node* node, Signedness left_signedness, const Operator* shift_op); - Node* ConvertToBoolean(Node* input); Node* ConvertToNumber(Node* input); template <IrOpcode::Value> Node* FindConversion(Node* input); diff --git a/deps/v8/src/compiler/opcodes.h b/deps/v8/src/compiler/opcodes.h index 3f00e6a178..d229b6da99 100644 --- a/deps/v8/src/compiler/opcodes.h +++ b/deps/v8/src/compiler/opcodes.h @@ -132,6 +132,7 @@ // Opcodes for VirtuaMachine-level operators. #define SIMPLIFIED_OP_LIST(V) \ + V(AnyToBoolean) \ V(BooleanNot) \ V(BooleanToNumber) \ V(NumberEqual) \ diff --git a/deps/v8/src/compiler/pipeline.cc b/deps/v8/src/compiler/pipeline.cc index 0e806238f1..c7432c6ea5 100644 --- a/deps/v8/src/compiler/pipeline.cc +++ b/deps/v8/src/compiler/pipeline.cc @@ -441,7 +441,7 @@ struct SimplifiedLoweringPhase { void Run(PipelineData* data, Zone* temp_zone) { SourcePositionTable::Scope pos(data->source_positions(), SourcePosition::Unknown()); - SimplifiedLowering lowering(data->jsgraph()); + SimplifiedLowering lowering(data->jsgraph(), temp_zone); lowering.LowerAllNodes(); ValueNumberingReducer vn_reducer(temp_zone); SimplifiedOperatorReducer simple_reducer(data->jsgraph()); diff --git a/deps/v8/src/compiler/simplified-lowering.cc b/deps/v8/src/compiler/simplified-lowering.cc index bb5761469d..1461709dab 100644 --- a/deps/v8/src/compiler/simplified-lowering.cc +++ b/deps/v8/src/compiler/simplified-lowering.cc @@ -77,6 +77,9 @@ class RepresentationSelector { memset(info_, 0, sizeof(NodeInfo) * count_); Factory* f = zone->isolate()->factory(); + safe_bit_range_ = + Type::Union(Type::Boolean(), + Type::Range(f->NewNumber(0), f->NewNumber(1), zone), zone); safe_int_additive_range_ = Type::Range(f->NewNumber(-std::pow(2.0, 52.0)), f->NewNumber(std::pow(2.0, 52.0)), zone); @@ -304,8 +307,8 @@ class RepresentationSelector { if ((use & kRepMask) == kRepTagged) { // only tagged uses. return kRepTagged; - } else if (IsSafeIntAdditiveOperand(node)) { - // Integer within [-2^52, 2^52] range. + } else if (upper->Is(Type::Integral32())) { + // Integer within [-2^31, 2^32[ range. if ((use & kRepMask) == kRepFloat64) { // only float64 uses. return kRepFloat64; @@ -315,12 +318,12 @@ class RepresentationSelector { } else if ((use & kRepMask) == kRepWord32 || (use & kTypeMask) == kTypeInt32 || (use & kTypeMask) == kTypeUint32) { - // The type is a safe integer, but we only use 32 bits. + // We only use 32 bits or we use the result consistently. return kRepWord32; } else { return kRepFloat64; } - } else if (upper->Is(Type::Boolean())) { + } else if (IsSafeBitOperand(node)) { // multiple uses => pick kRepBit. return kRepBit; } else if (upper->Is(Type::Number())) { @@ -414,6 +417,11 @@ class RepresentationSelector { return BothInputsAre(node, Type::Signed32()) && !CanObserveNonInt32(use); } + bool IsSafeBitOperand(Node* node) { + Type* type = NodeProperties::GetBounds(node).upper; + return type->Is(safe_bit_range_); + } + bool IsSafeIntAdditiveOperand(Node* node) { Type* type = NodeProperties::GetBounds(node).upper; // TODO(jarin): Unfortunately, bitset types are not subtypes of larger @@ -521,6 +529,28 @@ class RepresentationSelector { //------------------------------------------------------------------ // Simplified operators. //------------------------------------------------------------------ + case IrOpcode::kAnyToBoolean: { + if (IsSafeBitOperand(node->InputAt(0))) { + VisitUnop(node, kRepBit, kRepBit); + if (lower()) DeferReplacement(node, node->InputAt(0)); + } else { + VisitUnop(node, kMachAnyTagged, kTypeBool | kRepTagged); + if (lower()) { + // AnyToBoolean(x) => Call(ToBooleanStub, x, no-context) + Operator::Properties properties = node->op()->properties(); + Callable callable = CodeFactory::ToBoolean( + jsgraph_->isolate(), ToBooleanStub::RESULT_AS_ODDBALL); + CallDescriptor::Flags flags = CallDescriptor::kPatchableCallSite; + CallDescriptor* desc = Linkage::GetStubCallDescriptor( + callable.descriptor(), 0, flags, properties, jsgraph_->zone()); + node->set_op(jsgraph_->common()->Call(desc)); + node->InsertInput(jsgraph_->zone(), 0, + jsgraph_->HeapConstant(callable.code())); + node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant()); + } + } + break; + } case IrOpcode::kBooleanNot: { if (lower()) { MachineTypeUnion input = GetInfo(node->InputAt(0))->output; @@ -1034,6 +1064,7 @@ class RepresentationSelector { Phase phase_; // current phase of algorithm RepresentationChanger* changer_; // for inserting representation changes ZoneQueue<Node*> queue_; // queue for traversing the graph + Type* safe_bit_range_; Type* safe_int_additive_range_; NodeInfo* GetInfo(Node* node) { @@ -1058,7 +1089,7 @@ void SimplifiedLowering::LowerAllNodes() { SimplifiedOperatorBuilder simplified(graph()->zone()); RepresentationChanger changer(jsgraph(), &simplified, graph()->zone()->isolate()); - RepresentationSelector selector(jsgraph(), zone(), &changer); + RepresentationSelector selector(jsgraph(), zone_, &changer); selector.Run(this); } diff --git a/deps/v8/src/compiler/simplified-lowering.h b/deps/v8/src/compiler/simplified-lowering.h index 852ac7eaa0..b21cf21ffd 100644 --- a/deps/v8/src/compiler/simplified-lowering.h +++ b/deps/v8/src/compiler/simplified-lowering.h @@ -20,7 +20,8 @@ class RepresentationChanger; class SimplifiedLowering FINAL { public: - explicit SimplifiedLowering(JSGraph* jsgraph) : jsgraph_(jsgraph) {} + SimplifiedLowering(JSGraph* jsgraph, Zone* zone) + : jsgraph_(jsgraph), zone_(zone) {} ~SimplifiedLowering() {} void LowerAllNodes(); @@ -41,7 +42,8 @@ class SimplifiedLowering FINAL { void DoStringLessThanOrEqual(Node* node); private: - JSGraph* jsgraph_; + JSGraph* const jsgraph_; + Zone* const zone_; Node* SmiTag(Node* node); Node* IsTagged(Node* node); diff --git a/deps/v8/src/compiler/simplified-operator-reducer.cc b/deps/v8/src/compiler/simplified-operator-reducer.cc index 0868cab3fc..9d45e5b192 100644 --- a/deps/v8/src/compiler/simplified-operator-reducer.cc +++ b/deps/v8/src/compiler/simplified-operator-reducer.cc @@ -2,10 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/compiler/simplified-operator-reducer.h" + +#include "src/compiler/access-builder.h" #include "src/compiler/js-graph.h" #include "src/compiler/machine-operator.h" #include "src/compiler/node-matchers.h" -#include "src/compiler/simplified-operator-reducer.h" +#include "src/compiler/node-properties-inl.h" namespace v8 { namespace internal { @@ -20,6 +23,8 @@ SimplifiedOperatorReducer::~SimplifiedOperatorReducer() {} Reduction SimplifiedOperatorReducer::Reduce(Node* node) { switch (node->opcode()) { + case IrOpcode::kAnyToBoolean: + return ReduceAnyToBoolean(node); case IrOpcode::kBooleanNot: { HeapObjectMatcher<HeapObject> m(node->InputAt(0)); if (m.Is(Unique<HeapObject>::CreateImmovable(factory()->false_value()))) { @@ -105,8 +110,36 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) { } +Reduction SimplifiedOperatorReducer::ReduceAnyToBoolean(Node* node) { + Node* const input = NodeProperties::GetValueInput(node, 0); + Type* const input_type = NodeProperties::GetBounds(input).upper; + if (input_type->Is(Type::Boolean())) { + // AnyToBoolean(x:boolean) => x + return Replace(input); + } + if (input_type->Is(Type::OrderedNumber())) { + // AnyToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0)) + Node* compare = graph()->NewNode(simplified()->NumberEqual(), input, + jsgraph()->ZeroConstant()); + return Change(node, simplified()->BooleanNot(), compare); + } + if (input_type->Is(Type::String())) { + // AnyToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0)) + FieldAccess const access = AccessBuilder::ForStringLength(); + Node* length = graph()->NewNode(simplified()->LoadField(access), input, + graph()->start(), graph()->start()); + Node* compare = graph()->NewNode(simplified()->NumberEqual(), length, + jsgraph()->ZeroConstant()); + return Change(node, simplified()->BooleanNot(), compare); + } + return NoChange(); +} + + Reduction SimplifiedOperatorReducer::Change(Node* node, const Operator* op, Node* a) { + DCHECK_EQ(node->InputCount(), OperatorProperties::GetTotalInputCount(op)); + DCHECK_LE(1, node->InputCount()); node->set_op(op); node->ReplaceInput(0, a); return Changed(node); @@ -141,6 +174,11 @@ Factory* SimplifiedOperatorReducer::factory() const { } +CommonOperatorBuilder* SimplifiedOperatorReducer::common() const { + return jsgraph()->common(); +} + + MachineOperatorBuilder* SimplifiedOperatorReducer::machine() const { return jsgraph()->machine(); } diff --git a/deps/v8/src/compiler/simplified-operator-reducer.h b/deps/v8/src/compiler/simplified-operator-reducer.h index 8f6c9aa807..1e565b8b13 100644 --- a/deps/v8/src/compiler/simplified-operator-reducer.h +++ b/deps/v8/src/compiler/simplified-operator-reducer.h @@ -17,6 +17,7 @@ class Heap; namespace compiler { // Forward declarations. +class CommonOperatorBuilder; class JSGraph; class MachineOperatorBuilder; @@ -28,6 +29,8 @@ class SimplifiedOperatorReducer FINAL : public Reducer { Reduction Reduce(Node* node) FINAL; private: + Reduction ReduceAnyToBoolean(Node* node); + Reduction Change(Node* node, const Operator* op, Node* a); Reduction ReplaceFloat64(double value); Reduction ReplaceInt32(int32_t value); @@ -40,6 +43,7 @@ class SimplifiedOperatorReducer FINAL : public Reducer { Graph* graph() const; Factory* factory() const; JSGraph* jsgraph() const { return jsgraph_; } + CommonOperatorBuilder* common() const; MachineOperatorBuilder* machine() const; SimplifiedOperatorBuilder* simplified() { return &simplified_; } diff --git a/deps/v8/src/compiler/simplified-operator.cc b/deps/v8/src/compiler/simplified-operator.cc index e082a4b30a..9d88d12301 100644 --- a/deps/v8/src/compiler/simplified-operator.cc +++ b/deps/v8/src/compiler/simplified-operator.cc @@ -158,6 +158,7 @@ const ElementAccess& ElementAccessOf(const Operator* op) { #define PURE_OP_LIST(V) \ + V(AnyToBoolean, Operator::kNoProperties, 1) \ V(BooleanNot, Operator::kNoProperties, 1) \ V(BooleanToNumber, Operator::kNoProperties, 1) \ V(NumberEqual, Operator::kCommutative, 2) \ diff --git a/deps/v8/src/compiler/simplified-operator.h b/deps/v8/src/compiler/simplified-operator.h index 72608eee8c..22664fa8f7 100644 --- a/deps/v8/src/compiler/simplified-operator.h +++ b/deps/v8/src/compiler/simplified-operator.h @@ -128,6 +128,8 @@ class SimplifiedOperatorBuilder FINAL { public: explicit SimplifiedOperatorBuilder(Zone* zone); + const Operator* AnyToBoolean(); + const Operator* BooleanNot(); const Operator* BooleanToNumber(); diff --git a/deps/v8/src/compiler/typer.cc b/deps/v8/src/compiler/typer.cc index a170a71512..137829e92d 100644 --- a/deps/v8/src/compiler/typer.cc +++ b/deps/v8/src/compiler/typer.cc @@ -33,10 +33,11 @@ enum LazyCachedType { kImulFunc, kClz32Func, kArrayBufferFunc, -#define NATIVE_TYPE_CASE(Type) k##Type, k##Type##Array, k##Type##ArrayFunc, - NATIVE_TYPES(NATIVE_TYPE_CASE) -#undef NATIVE_TYPE_CASE - kNumLazyCachedTypes +#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + k##Type, k##Type##Array, k##Type##ArrayFunc, + TYPED_ARRAYS(TYPED_ARRAY_CASE) +#undef TYPED_ARRAY_CASE + kNumLazyCachedTypes }; @@ -75,6 +76,8 @@ class LazyTypeCache FINAL : public ZoneObject { return CreateNative(Type::Number(), Type::UntaggedFloat32()); case kFloat64: return CreateNative(Type::Number(), Type::UntaggedFloat64()); + case kUint8Clamped: + return Get(kUint8); case kNumberFunc0: return Type::Function(Type::Number(), zone()); case kNumberFunc1: @@ -89,13 +92,13 @@ class LazyTypeCache FINAL : public ZoneObject { return Type::Function(CreateRange(0, 32), Type::Number(), zone()); case kArrayBufferFunc: return Type::Function(Type::Object(zone()), Type::Unsigned32(), zone()); -#define NATIVE_TYPE_CASE(Type) \ - case k##Type##Array: \ - return CreateArray(Get(k##Type)); \ - case k##Type##ArrayFunc: \ +#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case k##Type##Array: \ + return CreateArray(Get(k##Type)); \ + case k##Type##ArrayFunc: \ return CreateArrayFunction(Get(k##Type##Array)); - NATIVE_TYPES(NATIVE_TYPE_CASE) -#undef NATIVE_TYPE_CASE + TYPED_ARRAYS(TYPED_ARRAY_CASE) +#undef TYPED_ARRAY_CASE case kNumLazyCachedTypes: break; } @@ -1438,6 +1441,11 @@ Bounds Typer::Visitor::TypeJSDebugger(Node* node) { // Simplified operators. +Bounds Typer::Visitor::TypeAnyToBoolean(Node* node) { + return TypeUnaryOp(node, ToBoolean); +} + + Bounds Typer::Visitor::TypeBooleanNot(Node* node) { return Bounds(Type::None(zone()), Type::Boolean(zone())); } @@ -1615,13 +1623,11 @@ Bounds Typer::Visitor::TypeLoadBuffer(Node* node) { // TODO(bmeurer): This typing is not yet correct. Since we can still access // out of bounds, the type in the general case has to include Undefined. switch (BufferAccessOf(node->op()).external_array_type()) { -#define NATIVE_TYPE_CASE(Type) \ - case kExternal##Type##Array: \ +#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case kExternal##Type##Array: \ return Bounds(typer_->cache_->Get(k##Type)); - NATIVE_TYPES(NATIVE_TYPE_CASE) -#undef NATIVE_TYPE_CASE - case kExternalUint8ClampedArray: - break; + TYPED_ARRAYS(TYPED_ARRAY_CASE) +#undef TYPED_ARRAY_CASE } UNREACHABLE(); return Bounds(); @@ -2088,14 +2094,11 @@ Type* Typer::Visitor::TypeConstant(Handle<Object> value) { } } else if (value->IsJSTypedArray()) { switch (JSTypedArray::cast(*value)->type()) { -#define NATIVE_TYPE_CASE(Type) \ - case kExternal##Type##Array: \ +#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case kExternal##Type##Array: \ return typer_->cache_->Get(k##Type##Array); - NATIVE_TYPES(NATIVE_TYPE_CASE) -#undef NATIVE_TYPE_CASE - case kExternalUint8ClampedArray: - // TODO(rossberg): Do we want some ClampedArray type to express this? - break; + TYPED_ARRAYS(TYPED_ARRAY_CASE) +#undef TYPED_ARRAY_CASE } } return Type::Constant(value, zone()); diff --git a/deps/v8/src/compiler/verifier.cc b/deps/v8/src/compiler/verifier.cc index 84b060f92a..693b414650 100644 --- a/deps/v8/src/compiler/verifier.cc +++ b/deps/v8/src/compiler/verifier.cc @@ -482,6 +482,10 @@ void Verifier::Visitor::Pre(Node* node) { // Simplified operators // ------------------------------- + case IrOpcode::kAnyToBoolean: + // Type is Boolean. + CheckUpperIs(node, Type::Boolean()); + break; case IrOpcode::kBooleanNot: // Boolean -> Boolean CheckValueInputIs(node, 0, Type::Boolean()); diff --git a/deps/v8/src/d8.cc b/deps/v8/src/d8.cc index 132891e2b8..7157cb81ac 100644 --- a/deps/v8/src/d8.cc +++ b/deps/v8/src/d8.cc @@ -1577,7 +1577,7 @@ class StartupDataHandler { const char* last_slash = strrchr(exec_path, '/'); if (last_slash) { int after_slash = last_slash - exec_path + 1; - int name_length = strlen(name); + int name_length = static_cast<int>(strlen(name)); *buffer = reinterpret_cast<char*>(calloc(after_slash + name_length + 1, 1)); strncpy(*buffer, exec_path, after_slash); diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc index cdcb0a759f..93ef1cfc09 100644 --- a/deps/v8/src/debug.cc +++ b/deps/v8/src/debug.cc @@ -573,7 +573,7 @@ void Debug::ThreadInit() { thread_local_.step_out_fp_ = 0; // TODO(isolates): frames_are_dropped_? base::NoBarrier_Store(&thread_local_.current_debug_scope_, - static_cast<base::AtomicWord>(0)); + static_cast<base::AtomicWord>(NULL)); thread_local_.restarter_frame_function_pointer_ = NULL; } diff --git a/deps/v8/src/deoptimizer.cc b/deps/v8/src/deoptimizer.cc index 554ba8e7b1..748f95eff7 100644 --- a/deps/v8/src/deoptimizer.cc +++ b/deps/v8/src/deoptimizer.cc @@ -637,7 +637,7 @@ Code* Deoptimizer::FindOptimizedCode(JSFunction* function, void Deoptimizer::PrintFunctionName() { if (function_->IsJSFunction()) { - function_->PrintName(trace_scope_->file()); + function_->ShortPrint(trace_scope_->file()); } else { PrintF(trace_scope_->file(), "%s", Code::Kind2String(compiled_code_->kind())); @@ -761,10 +761,8 @@ void Deoptimizer::DoComputeOutputFrames() { if (trace_scope_ != NULL) { timer.Start(); - PrintF(trace_scope_->file(), - "[deoptimizing (DEOPT %s): begin 0x%08" V8PRIxPTR " ", - MessageFor(bailout_type_), - reinterpret_cast<intptr_t>(function_)); + PrintF(trace_scope_->file(), "[deoptimizing (DEOPT %s): begin ", + MessageFor(bailout_type_)); PrintFunctionName(); PrintF(trace_scope_->file(), " (opt #%d) @%d, FP to SP delta: %d]\n", @@ -850,11 +848,8 @@ void Deoptimizer::DoComputeOutputFrames() { if (trace_scope_ != NULL) { double ms = timer.Elapsed().InMillisecondsF(); int index = output_count_ - 1; // Index of the topmost frame. - JSFunction* function = output_[index]->GetFunction(); - PrintF(trace_scope_->file(), - "[deoptimizing (%s): end 0x%08" V8PRIxPTR " ", - MessageFor(bailout_type_), - reinterpret_cast<intptr_t>(function)); + PrintF(trace_scope_->file(), "[deoptimizing (%s): end ", + MessageFor(bailout_type_)); PrintFunctionName(); PrintF(trace_scope_->file(), " @%d => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s," diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h index 6f36199347..348a52e73a 100644 --- a/deps/v8/src/flag-definitions.h +++ b/deps/v8/src/flag-definitions.h @@ -183,16 +183,17 @@ DEFINE_IMPLICATION(es_staging, harmony) V(harmony_unicode, "harmony unicode escapes") // Features that are complete (but still behind --harmony/es-staging flag). -#define HARMONY_STAGED(V) V(harmony_tostring, "harmony toString") +#define HARMONY_STAGED(V) \ + V(harmony_tostring, "harmony toString") \ + V(harmony_classes, \ + "harmony classes (implies block scoping & object literal extension)") \ + V(harmony_object_literals, "harmony object literal extensions") // Features that are shipping (turned on by default, but internal flag remains). #define HARMONY_SHIPPING(V) \ V(harmony_numeric_literals, "harmony numeric literals") \ V(harmony_strings, "harmony string methods") \ V(harmony_scoping, "harmony block scoping") \ - V(harmony_classes, \ - "harmony classes (implies block scoping & object literal extension)") \ - V(harmony_object_literals, "harmony object literal extensions") \ V(harmony_templates, "harmony template literals") // Once a shipping feature has proved stable in the wild, it will be dropped @@ -498,7 +499,7 @@ DEFINE_BOOL(trace_stub_failures, false, "trace deoptimization of generated code stubs") DEFINE_BOOL(serialize_toplevel, true, "enable caching of toplevel scripts") -DEFINE_BOOL(serialize_inner, false, "enable caching of inner functions") +DEFINE_BOOL(serialize_inner, true, "enable caching of inner functions") DEFINE_BOOL(trace_serializer, false, "print code serializer trace") // compiler.cc diff --git a/deps/v8/src/heap/heap.cc b/deps/v8/src/heap/heap.cc index cf67dab2b4..0b817e4d6d 100644 --- a/deps/v8/src/heap/heap.cc +++ b/deps/v8/src/heap/heap.cc @@ -4611,7 +4611,7 @@ bool Heap::IdleNotification(double deadline_in_seconds) { } -bool Heap::RecentIdleNotifcationHappened() { +bool Heap::RecentIdleNotificationHappened() { return (last_idle_notification_time_ + GCIdleTimeHandler::kMaxFrameRenderingIdleTime) > MonotonicallyIncreasingTimeInMs(); diff --git a/deps/v8/src/heap/heap.h b/deps/v8/src/heap/heap.h index 30271313e9..e6ccf2eaec 100644 --- a/deps/v8/src/heap/heap.h +++ b/deps/v8/src/heap/heap.h @@ -1298,7 +1298,7 @@ class Heap { int gc_count() const { return gc_count_; } - bool RecentIdleNotifcationHappened(); + bool RecentIdleNotificationHappened(); // Completely clear the Instanceof cache (to stop it keeping objects alive // around a GC). diff --git a/deps/v8/src/heap/incremental-marking.cc b/deps/v8/src/heap/incremental-marking.cc index 33f9de0da4..aadd17c94b 100644 --- a/deps/v8/src/heap/incremental-marking.cc +++ b/deps/v8/src/heap/incremental-marking.cc @@ -891,7 +891,7 @@ intptr_t IncrementalMarking::Step(intptr_t allocated_bytes, // If an idle notification happened recently, we delay marking steps. if (marking == DO_NOT_FORCE_MARKING && - heap_->RecentIdleNotifcationHappened()) { + heap_->RecentIdleNotificationHappened()) { return 0; } diff --git a/deps/v8/src/heap/spaces.cc b/deps/v8/src/heap/spaces.cc index 37a123d91d..3802e470bd 100644 --- a/deps/v8/src/heap/spaces.cc +++ b/deps/v8/src/heap/spaces.cc @@ -140,7 +140,8 @@ bool CodeRange::SetUp(size_t requested) { base += kReservedCodeRangePages * base::OS::CommitPageSize(); } Address aligned_base = RoundUp(base, MemoryChunk::kAlignment); - size_t size = code_range_->size() - (aligned_base - base); + size_t size = code_range_->size() - (aligned_base - base) - + kReservedCodeRangePages * base::OS::CommitPageSize(); allocation_list_.Add(FreeBlock(aligned_base, size)); current_allocation_block_index_ = 0; diff --git a/deps/v8/src/ia32/assembler-ia32.cc b/deps/v8/src/ia32/assembler-ia32.cc index 2805fa0f9a..168a196449 100644 --- a/deps/v8/src/ia32/assembler-ia32.cc +++ b/deps/v8/src/ia32/assembler-ia32.cc @@ -34,7 +34,11 @@ // significantly by Google Inc. // Copyright 2012 the V8 project authors. All rights reserved. -#include "src/v8.h" +#include "src/ia32/assembler-ia32.h" + +#if V8_OS_MACOSX +#include <sys/sysctl.h> +#endif #if V8_TARGET_ARCH_IA32 @@ -42,7 +46,7 @@ #include "src/base/cpu.h" #include "src/disassembler.h" #include "src/macro-assembler.h" -#include "src/serialize.h" +#include "src/v8.h" namespace v8 { namespace internal { @@ -50,6 +54,29 @@ namespace internal { // ----------------------------------------------------------------------------- // Implementation of CpuFeatures +namespace { + +bool EnableAVX() { +#if V8_OS_MACOSX + // Mac OS X 10.9 has a bug where AVX transitions were indeed being caused by + // ISRs, so we detect Mac OS X 10.9 here and disable AVX in that case. + char buffer[128]; + size_t buffer_size = arraysize(buffer); + int ctl_name[] = { CTL_KERN , KERN_OSRELEASE }; + if (sysctl(ctl_name, 2, buffer, &buffer_size, nullptr, 0) != 0) { + V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version"); + } + // The buffer now contains a string of the form XX.YY.ZZ, where + // XX is the major kernel version component. 13.x.x (Mavericks) is + // affected by this bug, so disable AVX there. + if (memcmp(buffer, "13.", 3) == 0) return false; +#endif // V8_OS_MACOSX + return FLAG_enable_avx; +} + +} // namespace + + void CpuFeatures::ProbeImpl(bool cross_compile) { base::CPU cpu; CHECK(cpu.has_sse2()); // SSE2 support is mandatory. @@ -60,7 +87,7 @@ void CpuFeatures::ProbeImpl(bool cross_compile) { if (cpu.has_sse41() && FLAG_enable_sse4_1) supported_ |= 1u << SSE4_1; if (cpu.has_sse3() && FLAG_enable_sse3) supported_ |= 1u << SSE3; - if (cpu.has_avx() && FLAG_enable_avx) supported_ |= 1u << AVX; + if (cpu.has_avx() && EnableAVX()) supported_ |= 1u << AVX; if (cpu.has_fma3() && FLAG_enable_fma3) supported_ |= 1u << FMA3; } diff --git a/deps/v8/src/parser.h b/deps/v8/src/parser.h index 02dfe15f8e..219f1c4b21 100644 --- a/deps/v8/src/parser.h +++ b/deps/v8/src/parser.h @@ -682,6 +682,7 @@ class Parser : public ParserBase<ParserTraits> { // Handle errors detected during parsing, move statistics to Isolate, // internalize strings (move them to the heap). void Internalize(); + void HandleSourceURLComments(); private: friend class ParserTraits; @@ -879,8 +880,6 @@ class Parser : public ParserBase<ParserTraits> { const AstRawString* function_name, int pos, Variable* fvar, Token::Value fvar_init_op, bool is_generator, bool* ok); - void HandleSourceURLComments(); - void ThrowPendingError(); TemplateLiteralState OpenTemplateLiteral(int pos); diff --git a/deps/v8/src/preparser.h b/deps/v8/src/preparser.h index ad27744e9d..18004a5096 100644 --- a/deps/v8/src/preparser.h +++ b/deps/v8/src/preparser.h @@ -467,7 +467,7 @@ class ParserBase : public Traits { void ReportMessageAt(Scanner::Location location, const char* message, bool is_reference_error = false) { Traits::ReportMessageAt(location, message, - reinterpret_cast<const char*>(0), + reinterpret_cast<const char*>(NULL), is_reference_error); } diff --git a/deps/v8/src/runtime.js b/deps/v8/src/runtime.js index 79824e4e02..978429ea3b 100644 --- a/deps/v8/src/runtime.js +++ b/deps/v8/src/runtime.js @@ -672,7 +672,7 @@ function DefaultString(x) { } function ToPositiveInteger(x, rangeErrorName) { - var i = TO_INTEGER(x); + var i = TO_INTEGER_MAP_MINUS_ZERO(x); if (i < 0) throw MakeRangeError(rangeErrorName); return i; } diff --git a/deps/v8/src/unique.h b/deps/v8/src/unique.h index 321eb3683d..9232f85970 100644 --- a/deps/v8/src/unique.h +++ b/deps/v8/src/unique.h @@ -117,7 +117,7 @@ class Unique { // TODO(titzer): this is a hack to migrate to Unique<T> incrementally. static Unique<T> CreateUninitialized(Handle<T> handle) { - return Unique<T>(NULL, handle); + return Unique<T>(reinterpret_cast<Address>(NULL), handle); } static Unique<T> CreateImmovable(Handle<T> handle) { diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index e84633da5f..c71ecff342 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -32,10 +32,10 @@ // These macros define the version number for the current version. // NOTE these macros are used by some of the tool scripts and the build // system so their names cannot be changed without changing the scripts. -#define MAJOR_VERSION 3 -#define MINOR_VERSION 31 -#define BUILD_NUMBER 74 -#define PATCH_LEVEL 1 +#define MAJOR_VERSION 4 +#define MINOR_VERSION 1 +#define BUILD_NUMBER 0 +#define PATCH_LEVEL 7 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) #define IS_CANDIDATE_VERSION 0 diff --git a/deps/v8/src/x64/assembler-x64.cc b/deps/v8/src/x64/assembler-x64.cc index 469ebe9888..fd722b23bd 100644 --- a/deps/v8/src/x64/assembler-x64.cc +++ b/deps/v8/src/x64/assembler-x64.cc @@ -2,13 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "src/v8.h" +#include "src/x64/assembler-x64.h" + +#if V8_OS_MACOSX +#include <sys/sysctl.h> +#endif #if V8_TARGET_ARCH_X64 #include "src/base/bits.h" #include "src/macro-assembler.h" -#include "src/serialize.h" +#include "src/v8.h" namespace v8 { namespace internal { @@ -16,6 +20,29 @@ namespace internal { // ----------------------------------------------------------------------------- // Implementation of CpuFeatures +namespace { + +bool EnableAVX() { +#if V8_OS_MACOSX + // Mac OS X 10.9 has a bug where AVX transitions were indeed being caused by + // ISRs, so we detect Mac OS X 10.9 here and disable AVX in that case. + char buffer[128]; + size_t buffer_size = arraysize(buffer); + int ctl_name[] = { CTL_KERN , KERN_OSRELEASE }; + if (sysctl(ctl_name, 2, buffer, &buffer_size, nullptr, 0) != 0) { + V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version"); + } + // The buffer now contains a string of the form XX.YY.ZZ, where + // XX is the major kernel version component. 13.x.x (Mavericks) is + // affected by this bug, so disable AVX there. + if (memcmp(buffer, "13.", 3) == 0) return false; +#endif // V8_OS_MACOSX + return FLAG_enable_avx; +} + +} // namespace + + void CpuFeatures::ProbeImpl(bool cross_compile) { base::CPU cpu; CHECK(cpu.has_sse2()); // SSE2 support is mandatory. @@ -28,7 +55,7 @@ void CpuFeatures::ProbeImpl(bool cross_compile) { if (cpu.has_sse3() && FLAG_enable_sse3) supported_ |= 1u << SSE3; // SAHF is not generally available in long mode. if (cpu.has_sahf() && FLAG_enable_sahf) supported_ |= 1u << SAHF; - if (cpu.has_avx() && FLAG_enable_avx) supported_ |= 1u << AVX; + if (cpu.has_avx() && EnableAVX()) supported_ |= 1u << AVX; if (cpu.has_fma3() && FLAG_enable_fma3) supported_ |= 1u << FMA3; } diff --git a/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc b/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc index 70b1312cc1..3023837f4c 100644 --- a/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc +++ b/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc @@ -507,24 +507,6 @@ TEST(JSToBoolean) { CHECK_EQ(IrOpcode::kParameter, r->opcode()); } - { // ToBoolean(ordered-number) - Node* r = R.ReduceUnop(op, Type::OrderedNumber()); - CHECK_EQ(IrOpcode::kBooleanNot, r->opcode()); - Node* i = r->InputAt(0); - CHECK_EQ(IrOpcode::kNumberEqual, i->opcode()); - // ToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0)) - } - - { // ToBoolean(string) - Node* r = R.ReduceUnop(op, Type::String()); - CHECK_EQ(IrOpcode::kBooleanNot, r->opcode()); - Node* i = r->InputAt(0); - CHECK_EQ(IrOpcode::kNumberEqual, i->opcode()); - Node* j = i->InputAt(0); - CHECK_EQ(IrOpcode::kLoadField, j->opcode()); - // ToBoolean(x:string) => BooleanNot(NumberEqual(x.length, #0)) - } - { // ToBoolean(object) Node* r = R.ReduceUnop(op, Type::DetectableObject()); R.CheckTrue(r); @@ -537,30 +519,7 @@ TEST(JSToBoolean) { { // ToBoolean(object) Node* r = R.ReduceUnop(op, Type::Object()); - CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode()); - } -} - - -TEST(JSToBoolean_replacement) { - JSTypedLoweringTester R; - - Type* types[] = {Type::Null(), Type::Undefined(), - Type::Boolean(), Type::OrderedNumber(), - Type::DetectableObject(), Type::Undetectable()}; - - for (size_t i = 0; i < arraysize(types); i++) { - Node* n = R.Parameter(types[i]); - Node* c = R.graph.NewNode(R.javascript.ToBoolean(), n, R.context()); - Node* r = R.reduce(c); - - if (types[i]->Is(Type::Boolean())) { - CHECK_EQ(n, r); - } else if (types[i]->Is(Type::OrderedNumber())) { - CHECK_EQ(IrOpcode::kBooleanNot, r->opcode()); - } else { - CHECK_EQ(IrOpcode::kHeapConstant, r->opcode()); - } + CHECK_EQ(IrOpcode::kAnyToBoolean, r->opcode()); } } diff --git a/deps/v8/test/cctest/compiler/test-simplified-lowering.cc b/deps/v8/test/cctest/compiler/test-simplified-lowering.cc index d463997691..147aa323ff 100644 --- a/deps/v8/test/cctest/compiler/test-simplified-lowering.cc +++ b/deps/v8/test/cctest/compiler/test-simplified-lowering.cc @@ -39,7 +39,7 @@ class SimplifiedLoweringTester : public GraphBuilderTester<ReturnType> { typer(this->graph(), MaybeHandle<Context>()), javascript(this->zone()), jsgraph(this->graph(), this->common(), &javascript, this->machine()), - lowering(&jsgraph) {} + lowering(&jsgraph, this->zone()) {} Typer typer; JSOperatorBuilder javascript; @@ -698,9 +698,7 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders { CHECK_EQ(expected, node->opcode()); } - void Lower() { - SimplifiedLowering(&jsgraph).LowerAllNodes(); - } + void Lower() { SimplifiedLowering(&jsgraph, jsgraph.zone()).LowerAllNodes(); } // Inserts the node as the return value of the graph. Node* Return(Node* node) { @@ -789,6 +787,50 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders { }; +TEST(LowerAnyToBoolean_bit_bit) { + // AnyToBoolean(x: kRepBit) used as kRepBit + HandleAndZoneScope scope; + Factory* f = scope.main_zone()->isolate()->factory(); + Handle<Object> zero = f->NewNumber(0); + Handle<Object> one = f->NewNumber(1); + Type* singleton_zero = Type::Constant(zero, scope.main_zone()); + Type* singleton_one = Type::Constant(one, scope.main_zone()); + Type* zero_one_range = Type::Range(zero, one, scope.main_zone()); + static Type* kTypes[] = { + singleton_zero, singleton_one, zero_one_range, Type::Boolean(), + Type::Union(Type::Boolean(), singleton_zero, scope.main_zone()), + Type::Union(Type::Boolean(), singleton_one, scope.main_zone()), + Type::Union(Type::Boolean(), zero_one_range, scope.main_zone())}; + for (Type* type : kTypes) { + TestingGraph t(type); + Node* x = t.ExampleWithTypeAndRep(type, kRepBit); + Node* cnv = t.graph()->NewNode(t.simplified()->AnyToBoolean(), x); + Node* use = t.Branch(cnv); + t.Lower(); + CHECK_EQ(x, use->InputAt(0)); + } +} + + +#if V8_TURBOFAN_TARGET + +TEST(LowerAnyToBoolean_tagged_tagged) { + // AnyToBoolean(x: kRepTagged) used as kRepTagged + TestingGraph t(Type::Any()); + Node* x = t.p0; + Node* cnv = t.graph()->NewNode(t.simplified()->AnyToBoolean(), x); + Node* use = t.Use(cnv, kRepTagged); + t.Return(use); + t.Lower(); + CHECK_EQ(IrOpcode::kCall, cnv->opcode()); + CHECK_EQ(IrOpcode::kHeapConstant, cnv->InputAt(0)->opcode()); + CHECK_EQ(x, cnv->InputAt(1)); + CHECK_EQ(t.jsgraph.NoContextConstant(), cnv->InputAt(2)); +} + +#endif + + TEST(LowerBooleanNot_bit_bit) { // BooleanNot(x: kRepBit) used as kRepBit TestingGraph t(Type::Boolean()); @@ -1995,11 +2037,6 @@ TEST(PhiRepresentation) { HandleAndZoneScope scope; Zone* z = scope.main_zone(); - Factory* f = z->isolate()->factory(); - Handle<Object> range_min = f->NewNumber(-1e13); - Handle<Object> range_max = f->NewNumber(1e+15); - Type* range = Type::Range(range_min, range_max, z); - struct TestData { Type* arg1; Type* arg2; @@ -2010,7 +2047,8 @@ TEST(PhiRepresentation) { TestData test_data[] = { {Type::Signed32(), Type::Unsigned32(), kMachInt32, kRepWord32 | kTypeNumber}, - {range, range, kMachUint32, kRepWord32 | kTypeNumber}, + {Type::Signed32(), Type::Unsigned32(), kMachUint32, + kRepWord32 | kTypeNumber}, {Type::Signed32(), Type::Signed32(), kMachInt32, kMachInt32}, {Type::Unsigned32(), Type::Unsigned32(), kMachInt32, kMachUint32}, {Type::Number(), Type::Signed32(), kMachInt32, kMachFloat64}, diff --git a/deps/v8/test/cctest/test-alloc.cc b/deps/v8/test/cctest/test-alloc.cc index 54d516e13e..2e071acc73 100644 --- a/deps/v8/test/cctest/test-alloc.cc +++ b/deps/v8/test/cctest/test-alloc.cc @@ -198,7 +198,8 @@ TEST(CodeRange) { const size_t code_range_size = 32*MB; CcTest::InitializeVM(); CodeRange code_range(reinterpret_cast<Isolate*>(CcTest::isolate())); - code_range.SetUp(code_range_size); + code_range.SetUp(code_range_size + + kReservedCodeRangePages * v8::base::OS::CommitPageSize()); size_t current_allocated = 0; size_t total_allocated = 0; List< ::Block> blocks(1000); diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 5c8584d0f5..d18059cd54 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -23999,10 +23999,8 @@ TEST(ScriptNameAndLineNumber) { CHECK_EQ(13, line_number); } - -void SourceURLHelper(const char* source, const char* expected_source_url, - const char* expected_source_mapping_url) { - Local<Script> script = v8_compile(source); +void CheckMagicComments(Handle<Script> script, const char* expected_source_url, + const char* expected_source_mapping_url) { if (expected_source_url != NULL) { v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL()); CHECK_EQ(expected_source_url, *url); @@ -24018,6 +24016,12 @@ void SourceURLHelper(const char* source, const char* expected_source_url, } } +void SourceURLHelper(const char* source, const char* expected_source_url, + const char* expected_source_mapping_url) { + Local<Script> script = v8_compile(source); + CheckMagicComments(script, expected_source_url, expected_source_mapping_url); +} + TEST(ScriptSourceURLAndSourceMappingURL) { LocalContext env; @@ -24209,7 +24213,9 @@ class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream { void RunStreamingTest(const char** chunks, v8::ScriptCompiler::StreamedSource::Encoding encoding = v8::ScriptCompiler::StreamedSource::ONE_BYTE, - bool expected_success = true) { + bool expected_success = true, + const char* expected_source_url = NULL, + const char* expected_source_mapping_url = NULL) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); @@ -24238,6 +24244,8 @@ void RunStreamingTest(const char** chunks, v8::Handle<Value> result(script->Run()); // All scripts are supposed to return the fixed value 13 when ran. CHECK_EQ(13, result->Int32Value()); + CheckMagicComments(script, expected_source_url, + expected_source_mapping_url); } else { CHECK(script.IsEmpty()); CHECK(try_catch.HasCaught()); @@ -24727,3 +24735,27 @@ TEST(ClassPrototypeCreationContext) { CompileRun("'use strict'; class Example { }; Example.prototype")); CHECK(env.local() == result->CreationContext()); } + + +TEST(SimpleStreamingScriptWithSourceURL) { + const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n", + "//# sourceURL=bar2.js\n", NULL}; + RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, + "bar2.js"); +} + + +TEST(StreamingScriptWithSplitSourceURL) { + const char* chunks[] = {"function foo() { ret", "urn 13; } f", + "oo();\n//# sourceURL=b", "ar2.js\n", NULL}; + RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, + "bar2.js"); +} + + +TEST(StreamingScriptWithSourceMappingURLInTheMiddle) { + const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#", + " sourceMappingURL=bar2.js\n", "foo();", NULL}; + RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL, + "bar2.js"); +} diff --git a/deps/v8/test/mjsunit/compiler/regress-445876.js b/deps/v8/test/mjsunit/compiler/regress-445876.js new file mode 100644 index 0000000000..30e10e56c3 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-445876.js @@ -0,0 +1,12 @@ +// Copyright 2015 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 + +function f(x) { + while (1) { s++; } + while (x) { s++; } +} + +assertThrows(function () { f(1); }); diff --git a/deps/v8/test/mjsunit/compiler/regress-446156.js b/deps/v8/test/mjsunit/compiler/regress-446156.js new file mode 100644 index 0000000000..f3cd2dd94e --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-446156.js @@ -0,0 +1,11 @@ +// Copyright 2015 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. + +(function Module(stdlib, foreign, heap) { + "use asm"; + // This is not valid asm.js, but should nevertheless work. + var MEM = new Uint8ClampedArray(heap); + function foo( ) { MEM[0] ^= 1; } + return {foo: foo}; +})(this, {}, new ArrayBuffer( ) ).foo(); diff --git a/deps/v8/test/mjsunit/compiler/regress-446778.js b/deps/v8/test/mjsunit/compiler/regress-446778.js new file mode 100644 index 0000000000..a7fa3fdad8 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-446778.js @@ -0,0 +1,17 @@ +// Copyright 2015 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. + +function Module() { + "use asm"; + function f() { + var i = (140737463189505); + do { + i = i + i | 0; + x = undefined + i | 0; + } while (!i); + } + return { f: f }; +} + +Module().f(); diff --git a/deps/v8/test/mjsunit/compiler/regress-ntl-effect.js b/deps/v8/test/mjsunit/compiler/regress-ntl-effect.js new file mode 100644 index 0000000000..708fe32828 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-ntl-effect.js @@ -0,0 +1,16 @@ +// Copyright 2015 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 + +function g() { + throw 0; +} + +function f() { + g(); + while (1) {} +} + +assertThrows(function () { f(); }); diff --git a/deps/v8/test/mjsunit/regress/regress-447756.js b/deps/v8/test/mjsunit/regress/regress-447756.js new file mode 100644 index 0000000000..1fc7518c13 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-447756.js @@ -0,0 +1,48 @@ +// Copyright 2015 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 + +function TestConstructor(c) { + var a = new c(-0); + assertSame(Infinity, 1 / a.length); + assertSame(Infinity, 1 / a.byteLength); + + var ab = new ArrayBuffer(-0); + assertSame(Infinity, 1 / ab.byteLength); + + var a1 = new c(ab, -0, -0); + assertSame(Infinity, 1 / a1.length); + assertSame(Infinity, 1 / a1.byteLength); + assertSame(Infinity, 1 / a1.byteOffset); +} + +var constructors = + [ Uint8Array, Int8Array, Uint8ClampedArray, + Uint16Array, Int16Array, + Uint32Array, Int32Array, + Float32Array, Float64Array ]; +for (var i = 0; i < constructors.length; i++) { + TestConstructor(constructors[i]); +} + + +function TestOptimizedCode() { + var a = new Uint8Array(-0); + assertSame(Infinity, 1 / a.length); + assertSame(Infinity, 1 / a.byteLength); + + var ab = new ArrayBuffer(-0); + assertSame(Infinity, 1 / ab.byteLength); + + var a1 = new Uint8Array(ab, -0, -0); + assertSame(Infinity, 1 / a1.length); + assertSame(Infinity, 1 / a1.byteLength); + assertSame(Infinity, 1 / a1.byteOffset); +} + +%OptimizeFunctionOnNextCall(Uint8Array); +for (var i = 0; i < 1000; i++) { + TestOptimizedCode(); +} diff --git a/deps/v8/test/unittests/compiler/change-lowering-unittest.cc b/deps/v8/test/unittests/compiler/change-lowering-unittest.cc index 763a44352f..060b1c1842 100644 --- a/deps/v8/test/unittests/compiler/change-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/change-lowering-unittest.cc @@ -15,6 +15,7 @@ using testing::_; using testing::AllOf; +using testing::BitEq; using testing::Capture; using testing::CaptureEq; @@ -78,7 +79,8 @@ class ChangeLoweringTest : public GraphTest { const Matcher<Node*>& control_matcher) { return IsCall(_, IsHeapConstant(Unique<HeapObject>::CreateImmovable( AllocateHeapNumberStub(isolate()).GetCode())), - IsNumberConstant(0.0), effect_matcher, control_matcher); + IsNumberConstant(BitEq(0.0)), effect_matcher, + control_matcher); } Matcher<Node*> IsLoadHeapNumber(const Matcher<Node*>& value_matcher, const Matcher<Node*>& control_matcher) { diff --git a/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc b/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc index 87d1ad53b8..9c572820e7 100644 --- a/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc @@ -10,6 +10,7 @@ #include "test/unittests/compiler/node-test-utils.h" #include "testing/gmock-support.h" +using testing::BitEq; using testing::Capture; namespace v8 { @@ -83,9 +84,11 @@ TEST_F(JSBuiltinReducerTest, MathAbs) { } else { Capture<Node*> branch; ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsSelect(kMachNone, IsNumberLessThan(IsNumberConstant(0), p0), - p0, IsNumberSubtract(IsNumberConstant(0), p0))); + EXPECT_THAT( + r.replacement(), + IsSelect(kMachNone, + IsNumberLessThan(IsNumberConstant(BitEq(0.0)), p0), p0, + IsNumberSubtract(IsNumberConstant(BitEq(0.0)), p0))); } } } diff --git a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc index e4ea4a581f..97ff106329 100644 --- a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc @@ -8,10 +8,14 @@ #include "src/compiler/js-typed-lowering.h" #include "src/compiler/machine-operator.h" #include "src/compiler/node-properties-inl.h" -#include "src/compiler/typer.h" #include "test/unittests/compiler/compiler-test-utils.h" #include "test/unittests/compiler/graph-unittest.h" #include "test/unittests/compiler/node-test-utils.h" +#include "testing/gmock-support.h" + +using testing::BitEq; +using testing::IsNaN; + namespace v8 { namespace internal { @@ -25,9 +29,35 @@ const ExternalArrayType kExternalArrayTypes[] = { kExternalFloat32Array, kExternalFloat64Array}; +const double kFloat64Values[] = { + -V8_INFINITY, -4.23878e+275, -5.82632e+265, -6.60355e+220, -6.26172e+212, + -2.56222e+211, -4.82408e+201, -1.84106e+157, -1.63662e+127, -1.55772e+100, + -1.67813e+72, -2.3382e+55, -3.179e+30, -1.441e+09, -1.0647e+09, + -7.99361e+08, -5.77375e+08, -2.20984e+08, -32757, -13171, -9970, -3984, + -107, -105, -92, -77, -61, -0.000208163, -1.86685e-06, -1.17296e-10, + -9.26358e-11, -5.08004e-60, -1.74753e-65, -1.06561e-71, -5.67879e-79, + -5.78459e-130, -2.90989e-171, -7.15489e-243, -3.76242e-252, -1.05639e-263, + -4.40497e-267, -2.19666e-273, -4.9998e-276, -5.59821e-278, -2.03855e-282, + -5.99335e-283, -7.17554e-284, -3.11744e-309, -0.0, 0.0, 2.22507e-308, + 1.30127e-270, 7.62898e-260, 4.00313e-249, 3.16829e-233, 1.85244e-228, + 2.03544e-129, 1.35126e-110, 1.01182e-106, 5.26333e-94, 1.35292e-90, + 2.85394e-83, 1.78323e-77, 5.4967e-57, 1.03207e-25, 4.57401e-25, 1.58738e-05, + 2, 125, 2310, 9636, 14802, 17168, 28945, 29305, 4.81336e+07, 1.41207e+08, + 4.65962e+08, 1.40499e+09, 2.12648e+09, 8.80006e+30, 1.4446e+45, 1.12164e+54, + 2.48188e+89, 6.71121e+102, 3.074e+112, 4.9699e+152, 5.58383e+166, + 4.30654e+172, 7.08824e+185, 9.6586e+214, 2.028e+223, 6.63277e+243, + 1.56192e+261, 1.23202e+269, 5.72883e+289, 8.5798e+290, 1.40256e+294, + 1.79769e+308, V8_INFINITY}; + + const size_t kIndices[] = {0, 1, 42, 100, 1024}; +const double kIntegerValues[] = {-V8_INFINITY, INT_MIN, -1000.0, -42.0, + -1.0, 0.0, 1.0, 42.0, + 1000.0, INT_MAX, UINT_MAX, V8_INFINITY}; + + Type* const kJSTypes[] = {Type::Undefined(), Type::Null(), Type::Boolean(), Type::Number(), Type::String(), Type::Object()}; @@ -69,124 +99,264 @@ class JSTypedLoweringTest : public TypedGraphTest { // ----------------------------------------------------------------------------- -// JSToBoolean - +// JSUnaryNot -TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) { - Node* input = Parameter(Type::Boolean()); - Node* context = UndefinedConstant(); +TEST_F(JSTypedLoweringTest, JSUnaryNotWithBoolean) { + Node* input = Parameter(Type::Boolean(), 0); + Node* context = Parameter(Type::Any(), 1); Reduction r = - Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context)); + Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context)); ASSERT_TRUE(r.Changed()); - EXPECT_EQ(input, r.replacement()); + EXPECT_THAT(r.replacement(), IsBooleanNot(input)); } -TEST_F(JSTypedLoweringTest, JSToBooleanWithUndefined) { - Node* input = Parameter(Type::Undefined()); - Node* context = UndefinedConstant(); +TEST_F(JSTypedLoweringTest, JSUnaryNotWithFalsish) { + Handle<Object> zero = factory()->NewNumber(0); + Node* input = Parameter( + Type::Union( + Type::MinusZero(), + Type::Union( + Type::NaN(), + Type::Union( + Type::Null(), + Type::Union( + Type::Undefined(), + Type::Union( + Type::Undetectable(), + Type::Union( + Type::Constant(factory()->false_value(), zone()), + Type::Range(zero, zero, zone()), zone()), + zone()), + zone()), + zone()), + zone()), + zone()), + 0); + Node* context = Parameter(Type::Any(), 1); + Reduction r = + Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsTrueConstant()); +} + +TEST_F(JSTypedLoweringTest, JSUnaryNotWithTruish) { + Node* input = Parameter( + Type::Union( + Type::Constant(factory()->true_value(), zone()), + Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()), + zone()), + 0); + Node* context = Parameter(Type::Any(), 1); Reduction r = - Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context)); + Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context)); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsFalseConstant()); } -TEST_F(JSTypedLoweringTest, JSToBooleanWithNull) { - Node* input = Parameter(Type::Null()); - Node* context = UndefinedConstant(); - +TEST_F(JSTypedLoweringTest, JSUnaryNotWithNonZeroPlainNumber) { + Node* input = Parameter( + Type::Range(factory()->NewNumber(1), factory()->NewNumber(42), zone()), + 0); + Node* context = Parameter(Type::Any(), 1); Reduction r = - Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context)); + Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context)); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsFalseConstant()); } -TEST_F(JSTypedLoweringTest, JSToBooleanWithDetectableReceiver) { - Node* input = Parameter(Type::DetectableReceiver()); - Node* context = UndefinedConstant(); - +TEST_F(JSTypedLoweringTest, JSUnaryNotWithAny) { + Node* input = Parameter(Type::Any(), 0); + Node* context = Parameter(Type::Any(), 1); Reduction r = - Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context)); + Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsTrueConstant()); + EXPECT_THAT(r.replacement(), IsBooleanNot(IsAnyToBoolean(input))); +} + + +// ----------------------------------------------------------------------------- +// Constant propagation + + +TEST_F(JSTypedLoweringTest, ParameterWithMinusZero) { + { + Reduction r = Reduce( + Parameter(Type::Constant(factory()->minus_zero_value(), zone()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0)); + } + { + Reduction r = Reduce(Parameter(Type::MinusZero())); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0)); + } + { + Reduction r = Reduce(Parameter( + Type::Union(Type::MinusZero(), + Type::Constant(factory()->NewNumber(0), zone()), zone()))); + EXPECT_FALSE(r.Changed()); + } +} + + +TEST_F(JSTypedLoweringTest, ParameterWithNull) { + Handle<HeapObject> null = factory()->null_value(); + { + Reduction r = Reduce(Parameter(Type::Constant(null, zone()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsHeapConstant(Unique<HeapObject>::CreateImmovable(null))); + } + { + Reduction r = Reduce(Parameter(Type::Null())); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsHeapConstant(Unique<HeapObject>::CreateImmovable(null))); + } +} + + +TEST_F(JSTypedLoweringTest, ParameterWithNaN) { + const double kNaNs[] = {base::OS::nan_value(), + std::numeric_limits<double>::quiet_NaN(), + std::numeric_limits<double>::signaling_NaN()}; + TRACED_FOREACH(double, nan, kNaNs) { + Handle<Object> constant = factory()->NewNumber(nan); + Reduction r = Reduce(Parameter(Type::Constant(constant, zone()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN())); + } + { + Reduction r = + Reduce(Parameter(Type::Constant(factory()->nan_value(), zone()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN())); + } + { + Reduction r = Reduce(Parameter(Type::NaN())); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN())); + } +} + + +TEST_F(JSTypedLoweringTest, ParameterWithPlainNumber) { + TRACED_FOREACH(double, value, kFloat64Values) { + Handle<Object> constant = factory()->NewNumber(value); + Reduction r = Reduce(Parameter(Type::Constant(constant, zone()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(value)); + } + TRACED_FOREACH(double, value, kIntegerValues) { + Handle<Object> constant = factory()->NewNumber(value); + Reduction r = Reduce(Parameter(Type::Range(constant, constant, zone()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(value)); + } +} + + +TEST_F(JSTypedLoweringTest, ParameterWithUndefined) { + Handle<HeapObject> undefined = factory()->undefined_value(); + { + Reduction r = Reduce(Parameter(Type::Undefined())); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsHeapConstant(Unique<HeapObject>::CreateImmovable(undefined))); + } + { + Reduction r = Reduce(Parameter(Type::Constant(undefined, zone()))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsHeapConstant(Unique<HeapObject>::CreateImmovable(undefined))); + } } -TEST_F(JSTypedLoweringTest, JSToBooleanWithUndetectable) { - Node* input = Parameter(Type::Undetectable()); - Node* context = UndefinedConstant(); +// ----------------------------------------------------------------------------- +// JSToBoolean + +TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) { + Node* input = Parameter(Type::Boolean(), 0); + Node* context = Parameter(Type::Any(), 1); Reduction r = Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsFalseConstant()); + EXPECT_EQ(input, r.replacement()); } -TEST_F(JSTypedLoweringTest, JSToBooleanWithOrderedNumber) { - Node* input = Parameter(Type::OrderedNumber()); - Node* context = UndefinedConstant(); - +TEST_F(JSTypedLoweringTest, JSToBooleanWithFalsish) { + Handle<Object> zero = factory()->NewNumber(0); + Node* input = Parameter( + Type::Union( + Type::MinusZero(), + Type::Union( + Type::NaN(), + Type::Union( + Type::Null(), + Type::Union( + Type::Undefined(), + Type::Union( + Type::Undetectable(), + Type::Union( + Type::Constant(factory()->false_value(), zone()), + Type::Range(zero, zero, zone()), zone()), + zone()), + zone()), + zone()), + zone()), + zone()), + 0); + Node* context = Parameter(Type::Any(), 1); Reduction r = Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsBooleanNot(IsNumberEqual(input, IsNumberConstant(0)))); + EXPECT_THAT(r.replacement(), IsFalseConstant()); } -TEST_F(JSTypedLoweringTest, JSToBooleanWithString) { - Node* input = Parameter(Type::String()); - Node* context = UndefinedConstant(); - +TEST_F(JSTypedLoweringTest, JSToBooleanWithTruish) { + Node* input = Parameter( + Type::Union( + Type::Constant(factory()->true_value(), zone()), + Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()), + zone()), + 0); + Node* context = Parameter(Type::Any(), 1); Reduction r = Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsBooleanNot(IsNumberEqual( - IsLoadField(AccessBuilder::ForStringLength(), input, - graph()->start(), graph()->start()), - IsNumberConstant(0)))); + EXPECT_THAT(r.replacement(), IsTrueConstant()); } -TEST_F(JSTypedLoweringTest, JSToBooleanWithPhi) { - Node* p0 = Parameter(Type::OrderedNumber(), 0); - Node* p1 = Parameter(Type::Boolean(), 1); - Node* context = UndefinedConstant(); - Node* control = graph()->start(); - - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(), - graph()->NewNode(common()->Phi(kMachAnyTagged, 2), p0, p1, control), - context)); +TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) { + Node* input = + Parameter(Type::Range(factory()->NewNumber(1), + factory()->NewNumber(V8_INFINITY), zone()), + 0); + Node* context = Parameter(Type::Any(), 1); + Reduction r = + Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsPhi(kMachAnyTagged, - IsBooleanNot(IsNumberEqual(p0, IsNumberConstant(0))), p1, control)); + EXPECT_THAT(r.replacement(), IsTrueConstant()); } -TEST_F(JSTypedLoweringTest, JSToBooleanWithSelect) { - Node* p0 = Parameter(Type::Boolean(), 0); - Node* p1 = Parameter(Type::DetectableReceiver(), 1); - Node* p2 = Parameter(Type::OrderedNumber(), 2); - Node* context = UndefinedConstant(); - - Reduction r = Reduce(graph()->NewNode( - javascript()->ToBoolean(), - graph()->NewNode(common()->Select(kMachAnyTagged, BranchHint::kTrue), p0, - p1, p2), - context)); +TEST_F(JSTypedLoweringTest, JSToBooleanWithAny) { + Node* input = Parameter(Type::Any(), 0); + Node* context = Parameter(Type::Any(), 1); + Reduction r = + Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsSelect(kMachAnyTagged, p0, IsTrueConstant(), - IsBooleanNot(IsNumberEqual(p2, IsNumberConstant(0))))); + EXPECT_THAT(r.replacement(), IsAnyToBoolean(input)); } @@ -202,7 +372,7 @@ TEST_F(JSTypedLoweringTest, JSToNumberWithPlainPrimitive) { Reduction r = Reduce(graph()->NewNode(javascript()->ToNumber(), input, context, effect, control)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsToNumber(input, IsNumberConstant(0), + EXPECT_THAT(r.replacement(), IsToNumber(input, IsNumberConstant(BitEq(0.0)), graph()->start(), control)); } @@ -235,12 +405,13 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) { Node* const context = UndefinedConstant(); Node* const effect = graph()->start(); Node* const control = graph()->start(); - TRACED_FORRANGE(int32_t, rhs, 0, 31) { + TRACED_FORRANGE(double, rhs, 0, 31) { Reduction r = Reduce(graph()->NewNode(javascript()->ShiftLeft(), lhs, NumberConstant(rhs), context, effect, control)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsWord32Shl(lhs, IsNumberConstant(rhs))); + EXPECT_THAT(r.replacement(), + IsWord32Shl(lhs, IsNumberConstant(BitEq(rhs)))); } } @@ -268,12 +439,13 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) { Node* const context = UndefinedConstant(); Node* const effect = graph()->start(); Node* const control = graph()->start(); - TRACED_FORRANGE(int32_t, rhs, 0, 31) { + TRACED_FORRANGE(double, rhs, 0, 31) { Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRight(), lhs, NumberConstant(rhs), context, effect, control)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsWord32Sar(lhs, IsNumberConstant(rhs))); + EXPECT_THAT(r.replacement(), + IsWord32Sar(lhs, IsNumberConstant(BitEq(rhs)))); } } @@ -301,12 +473,13 @@ TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndConstant) { Node* const context = UndefinedConstant(); Node* const effect = graph()->start(); Node* const control = graph()->start(); - TRACED_FORRANGE(int32_t, rhs, 0, 31) { + TRACED_FORRANGE(double, rhs, 0, 31) { Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRightLogical(), lhs, NumberConstant(rhs), context, effect, control)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsWord32Shr(lhs, IsNumberConstant(rhs))); + EXPECT_THAT(r.replacement(), + IsWord32Shr(lhs, IsNumberConstant(BitEq(rhs)))); } } diff --git a/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc b/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc index b92bd28c97..6fdba35f58 100644 --- a/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc @@ -12,6 +12,7 @@ #include "testing/gmock-support.h" using testing::AllOf; +using testing::BitEq; using testing::Capture; using testing::CaptureEq; @@ -291,7 +292,7 @@ TEST_F(MachineOperatorReducerTest, ChangeFloat64ToFloat32WithConstant) { Reduction reduction = Reduce(graph()->NewNode( machine()->ChangeFloat32ToFloat64(), Float32Constant(x))); ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), IsFloat64Constant(x)); + EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq<double>(x))); } } @@ -355,7 +356,7 @@ TEST_F(MachineOperatorReducerTest, ChangeInt32ToFloat64WithConstant) { Reduction reduction = Reduce( graph()->NewNode(machine()->ChangeInt32ToFloat64(), Int32Constant(x))); ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), IsFloat64Constant(FastI2D(x))); + EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq(FastI2D(x)))); } } @@ -384,7 +385,7 @@ TEST_F(MachineOperatorReducerTest, ChangeUint32ToFloat64WithConstant) { Reduce(graph()->NewNode(machine()->ChangeUint32ToFloat64(), Int32Constant(bit_cast<int32_t>(x)))); ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), IsFloat64Constant(FastUI2D(x))); + EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq(FastUI2D(x)))); } } @@ -425,7 +426,8 @@ TEST_F(MachineOperatorReducerTest, TruncateFloat64ToFloat32WithConstant) { Reduction reduction = Reduce(graph()->NewNode( machine()->TruncateFloat64ToFloat32(), Float64Constant(x))); ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), IsFloat32Constant(DoubleToFloat32(x))); + EXPECT_THAT(reduction.replacement(), + IsFloat32Constant(BitEq(DoubleToFloat32(x)))); } } @@ -1268,13 +1270,15 @@ TEST_F(MachineOperatorReducerTest, Float64MulWithMinusOne) { Reduction r = Reduce( graph()->NewNode(machine()->Float64Mul(), p0, Float64Constant(-1.0))); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsFloat64Sub(IsFloat64Constant(-0.0), p0)); + EXPECT_THAT(r.replacement(), + IsFloat64Sub(IsFloat64Constant(BitEq(-0.0)), p0)); } { Reduction r = Reduce( graph()->NewNode(machine()->Float64Mul(), Float64Constant(-1.0), p0)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsFloat64Sub(IsFloat64Constant(-0.0), p0)); + EXPECT_THAT(r.replacement(), + IsFloat64Sub(IsFloat64Constant(BitEq(-0.0)), p0)); } } diff --git a/deps/v8/test/unittests/compiler/node-test-utils.cc b/deps/v8/test/unittests/compiler/node-test-utils.cc index 3162c548f3..74afda974a 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.cc +++ b/deps/v8/test/unittests/compiler/node-test-utils.cc @@ -1290,6 +1290,7 @@ IS_BINOP_MATCHER(Float64Sub) Matcher<Node*> Is##Name(const Matcher<Node*>& input_matcher) { \ return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \ } +IS_UNOP_MATCHER(AnyToBoolean) IS_UNOP_MATCHER(BooleanNot) IS_UNOP_MATCHER(ChangeFloat64ToInt32) IS_UNOP_MATCHER(ChangeFloat64ToUint32) diff --git a/deps/v8/test/unittests/compiler/node-test-utils.h b/deps/v8/test/unittests/compiler/node-test-utils.h index f1f20cfe19..02b6e43175 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.h +++ b/deps/v8/test/unittests/compiler/node-test-utils.h @@ -75,6 +75,7 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher, const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher); +Matcher<Node*> IsAnyToBoolean(const Matcher<Node*>& value_matcher); Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher); Matcher<Node*> IsNumberEqual(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); diff --git a/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc b/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc index 066cbe9337..e5f46c0d53 100644 --- a/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc @@ -2,22 +2,28 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/compiler/access-builder.h" #include "src/compiler/js-graph.h" +#include "src/compiler/node-properties-inl.h" #include "src/compiler/simplified-operator.h" #include "src/compiler/simplified-operator-reducer.h" #include "src/conversions.h" #include "src/types.h" #include "test/unittests/compiler/graph-unittest.h" #include "test/unittests/compiler/node-test-utils.h" +#include "testing/gmock-support.h" + +using testing::BitEq; + namespace v8 { namespace internal { namespace compiler { -class SimplifiedOperatorReducerTest : public GraphTest { +class SimplifiedOperatorReducerTest : public TypedGraphTest { public: explicit SimplifiedOperatorReducerTest(int num_parameters = 1) - : GraphTest(num_parameters), simplified_(zone()) {} + : TypedGraphTest(num_parameters), simplified_(zone()) {} ~SimplifiedOperatorReducerTest() OVERRIDE {} protected: @@ -114,11 +120,6 @@ static const uint32_t kUint32Values[] = { 0xbeb15c0d, 0xc171c53d, 0xc743dd38, 0xc8e2af50, 0xc98e2df0, 0xd9d1cdf9, 0xdcc91049, 0xe46f396d, 0xee991950, 0xef64e521, 0xf7aeefc9, 0xffffffff}; - -MATCHER(IsNaN, std::string(negation ? "isn't" : "is") + " NaN") { - return std::isnan(arg); -} - } // namespace @@ -140,6 +141,7 @@ std::ostream& operator<<(std::ostream& os, const UnaryOperator& unop) { static const UnaryOperator kUnaryOperators[] = { + {&SimplifiedOperatorBuilder::AnyToBoolean, "AnyToBoolean"}, {&SimplifiedOperatorBuilder::BooleanNot, "BooleanNot"}, {&SimplifiedOperatorBuilder::ChangeBitToBool, "ChangeBitToBool"}, {&SimplifiedOperatorBuilder::ChangeBoolToBit, "ChangeBoolToBit"}, @@ -161,8 +163,8 @@ typedef SimplifiedOperatorReducerTestWithParam<UnaryOperator> TEST_P(SimplifiedUnaryOperatorTest, Parameter) { const UnaryOperator& unop = GetParam(); - Reduction reduction = Reduce( - graph()->NewNode((simplified()->*unop.constructor)(), Parameter(0))); + Reduction reduction = Reduce(graph()->NewNode( + (simplified()->*unop.constructor)(), Parameter(Type::Any()))); EXPECT_FALSE(reduction.Changed()); } @@ -173,6 +175,39 @@ INSTANTIATE_TEST_CASE_P(SimplifiedOperatorReducerTest, // ----------------------------------------------------------------------------- +// AnyToBoolean + + +TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithBoolean) { + Node* p = Parameter(Type::Boolean()); + Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p)); + ASSERT_TRUE(r.Changed()); + EXPECT_EQ(p, r.replacement()); +} + + +TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithOrderedNumber) { + Node* p = Parameter(Type::OrderedNumber()); + Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsBooleanNot(IsNumberEqual(p, IsNumberConstant(0)))); +} + + +TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithString) { + Node* p = Parameter(Type::String()); + Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsBooleanNot( + IsNumberEqual(IsLoadField(AccessBuilder::ForStringLength(), p, + graph()->start(), graph()->start()), + IsNumberConstant(0)))); +} + + +// ----------------------------------------------------------------------------- // BooleanNot @@ -271,7 +306,7 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeFloat64ToTaggedWithConstant) { Reduction reduction = Reduce(graph()->NewNode( simplified()->ChangeFloat64ToTagged(), Float64Constant(n))); ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), IsNumberConstant(n)); + EXPECT_THAT(reduction.replacement(), IsNumberConstant(BitEq(n))); } } @@ -285,7 +320,7 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeInt32ToTaggedWithConstant) { Reduction reduction = Reduce(graph()->NewNode( simplified()->ChangeInt32ToTagged(), Int32Constant(n))); ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), IsNumberConstant(FastI2D(n))); + EXPECT_THAT(reduction.replacement(), IsNumberConstant(BitEq(FastI2D(n)))); } } @@ -332,7 +367,7 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithConstant) { Reduction reduction = Reduce(graph()->NewNode( simplified()->ChangeTaggedToFloat64(), NumberConstant(n))); ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), IsFloat64Constant(n)); + EXPECT_THAT(reduction.replacement(), IsFloat64Constant(BitEq(n))); } } @@ -342,7 +377,8 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithNaNConstant1) { Reduce(graph()->NewNode(simplified()->ChangeTaggedToFloat64(), NumberConstant(-base::OS::nan_value()))); ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), IsFloat64Constant(IsNaN())); + EXPECT_THAT(reduction.replacement(), + IsFloat64Constant(BitEq(-base::OS::nan_value()))); } @@ -351,7 +387,8 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeTaggedToFloat64WithNaNConstant2) { Reduce(graph()->NewNode(simplified()->ChangeTaggedToFloat64(), NumberConstant(base::OS::nan_value()))); ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), IsFloat64Constant(IsNaN())); + EXPECT_THAT(reduction.replacement(), + IsFloat64Constant(BitEq(base::OS::nan_value()))); } @@ -474,7 +511,7 @@ TEST_F(SimplifiedOperatorReducerTest, ChangeUint32ToTagged) { Reduce(graph()->NewNode(simplified()->ChangeUint32ToTagged(), Int32Constant(bit_cast<int32_t>(n)))); ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), IsNumberConstant(FastUI2D(n))); + EXPECT_THAT(reduction.replacement(), IsNumberConstant(BitEq(FastUI2D(n)))); } } diff --git a/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc b/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc index e7fceba47d..bc537fd952 100644 --- a/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc @@ -38,6 +38,7 @@ const PureOperator kPureOperators[] = { &SimplifiedOperatorBuilder::Name, IrOpcode::k##Name, \ Operator::kPure | properties, input_count \ } + PURE(AnyToBoolean, Operator::kNoProperties, 1), PURE(BooleanNot, Operator::kNoProperties, 1), PURE(BooleanToNumber, Operator::kNoProperties, 1), PURE(NumberEqual, Operator::kCommutative, 2), diff --git a/deps/v8/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt b/deps/v8/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt index c96c8361fd..0e00f23cad 100644 --- a/deps/v8/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt +++ b/deps/v8/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt @@ -47,7 +47,7 @@ PASS getSortedOwnPropertyNames(encodeURIComponent) is ['arguments', 'caller', 'l PASS getSortedOwnPropertyNames(Object) is ['arguments', 'caller', 'create', 'defineProperties', 'defineProperty', 'deliverChangeRecords', 'freeze', 'getNotifier', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 'getOwnPropertySymbols', 'getPrototypeOf', 'is', 'isExtensible', 'isFrozen', 'isSealed', 'keys', 'length', 'name', 'observe', 'preventExtensions', 'prototype', 'seal', 'setPrototypeOf', 'unobserve'] PASS getSortedOwnPropertyNames(Object.prototype) is ['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', '__proto__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf'] PASS getSortedOwnPropertyNames(Function) is ['arguments', 'caller', 'length', 'name', 'prototype'] -PASS getSortedOwnPropertyNames(Function.prototype) is ['apply', 'arguments', 'bind', 'call', 'caller', 'constructor', 'length', 'name', 'toMethod', 'toString'] +PASS getSortedOwnPropertyNames(Function.prototype) is ['apply', 'arguments', 'bind', 'call', 'caller', 'constructor', 'length', 'name', 'toString'] PASS getSortedOwnPropertyNames(Array) is ['arguments', 'caller', 'isArray', 'length', 'name', 'observe', 'prototype', 'unobserve'] PASS getSortedOwnPropertyNames(Array.prototype) is ['concat', 'constructor', 'entries', 'every', 'filter', 'forEach', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift'] PASS getSortedOwnPropertyNames(String) is ['arguments', 'caller', 'fromCharCode', 'fromCodePoint', 'length', 'name', 'prototype', 'raw'] diff --git a/deps/v8/test/webkit/fast/js/Object-getOwnPropertyNames.js b/deps/v8/test/webkit/fast/js/Object-getOwnPropertyNames.js index 46d7966664..72bd21b426 100644 --- a/deps/v8/test/webkit/fast/js/Object-getOwnPropertyNames.js +++ b/deps/v8/test/webkit/fast/js/Object-getOwnPropertyNames.js @@ -74,7 +74,7 @@ var expectedPropertyNamesSet = { "Object": "['arguments', 'caller', 'create', 'defineProperties', 'defineProperty', 'deliverChangeRecords', 'freeze', 'getNotifier', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 'getOwnPropertySymbols', 'getPrototypeOf', 'is', 'isExtensible', 'isFrozen', 'isSealed', 'keys', 'length', 'name', 'observe', 'preventExtensions', 'prototype', 'seal', 'setPrototypeOf', 'unobserve']", "Object.prototype": "['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', '__proto__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']", "Function": "['arguments', 'caller', 'length', 'name', 'prototype']", - "Function.prototype": "['apply', 'arguments', 'bind', 'call', 'caller', 'constructor', 'length', 'name', 'toMethod', 'toString']", + "Function.prototype": "['apply', 'arguments', 'bind', 'call', 'caller', 'constructor', 'length', 'name', 'toString']", "Array": "['arguments', 'caller', 'isArray', 'length', 'name', 'observe', 'prototype', 'unobserve']", "Array.prototype": "['concat', 'constructor', 'entries', 'every', 'filter', 'forEach', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']", "String": "['arguments', 'caller', 'fromCharCode', 'fromCodePoint', 'length', 'name', 'prototype', 'raw']", diff --git a/deps/v8/testing/gmock-support.h b/deps/v8/testing/gmock-support.h index 44348b60e0..012775b5cb 100644 --- a/deps/v8/testing/gmock-support.h +++ b/deps/v8/testing/gmock-support.h @@ -5,6 +5,9 @@ #ifndef V8_TESTING_GMOCK_SUPPORT_H_ #define V8_TESTING_GMOCK_SUPPORT_H_ +#include <cmath> +#include <cstring> + #include "testing/gmock/include/gmock/gmock.h" namespace testing { @@ -31,6 +34,25 @@ class Capture { namespace internal { +struct AnyBitEq { + template <typename A, typename B> + bool operator()(A const& a, B const& b) const { + if (sizeof(A) != sizeof(B)) return false; + return std::memcmp(&a, &b, sizeof(A)) == 0; + } +}; + + +template <typename Rhs> +class BitEqMatcher : public ComparisonBase<BitEqMatcher<Rhs>, Rhs, AnyBitEq> { + public: + explicit BitEqMatcher(Rhs const& rhs) + : ComparisonBase<BitEqMatcher<Rhs>, Rhs, AnyBitEq>(rhs) {} + static const char* Desc() { return "is bitwise equal to"; } + static const char* NegatedDesc() { return "isn't bitwise equal to"; } +}; + + template <typename T> class CaptureEqMatcher : public MatcherInterface<T> { public: @@ -60,13 +82,27 @@ class CaptureEqMatcher : public MatcherInterface<T> { } // namespace internal +// Creates a polymorphic matcher that matches anything whose bit representation +// is equal to that of x. +template <typename T> +inline internal::BitEqMatcher<T> BitEq(T const& x) { + return internal::BitEqMatcher<T>(x); +} + + // CaptureEq(capture) captures the value passed in during matching as long as it // is unset, and once set, compares the value for equality with the argument. template <typename T> -Matcher<T> CaptureEq(Capture<T>* capture) { +inline Matcher<T> CaptureEq(Capture<T>* capture) { return MakeMatcher(new internal::CaptureEqMatcher<T>(capture)); } + +// Creates a polymorphic matcher that matches any floating point NaN value. +MATCHER(IsNaN, std::string(negation ? "isn't" : "is") + " not a number") { + return std::isnan(arg); +} + } // namespace testing #endif // V8_TESTING_GMOCK_SUPPORT_H_ diff --git a/deps/v8/tools/push-to-trunk/generate_version.py b/deps/v8/tools/push-to-trunk/generate_version.py new file mode 100755 index 0000000000..b4a0221eae --- /dev/null +++ b/deps/v8/tools/push-to-trunk/generate_version.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# 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. + +""" +Script to set v8's version file to the version given by the latest tag. +""" + + +import os +import re +import subprocess +import sys + + +CWD = os.path.abspath( + os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) +VERSION_CC = os.path.join(CWD, "src", "version.cc") + +def main(): + tag = subprocess.check_output( + "git describe --tags", + shell=True, + cwd=CWD, + ).strip() + assert tag + + # Check for commits not exactly matching a tag. Those are candidate builds + # for the next version. The output has the form + # <tag name>-<n commits>-<hash>. + if "-" in tag: + version = tag.split("-")[0] + candidate = "1" + else: + version = tag + candidate = "0" + version_levels = version.split(".") + + # Set default patch level if none is given. + if len(version_levels) == 3: + version_levels.append("0") + assert len(version_levels) == 4 + + major, minor, build, patch = version_levels + + # Increment build level for candidate builds. + if candidate == "1": + build = str(int(build) + 1) + patch = "0" + + # Modify version.cc with the new values. + with open(VERSION_CC, "r") as f: + text = f.read() + output = [] + for line in text.split("\n"): + for definition, substitute in ( + ("MAJOR_VERSION", major), + ("MINOR_VERSION", minor), + ("BUILD_NUMBER", build), + ("PATCH_LEVEL", patch), + ("IS_CANDIDATE_VERSION", candidate)): + if line.startswith("#define %s" % definition): + line = re.sub("\d+$", substitute, line) + output.append(line) + with open(VERSION_CC, "w") as f: + f.write("\n".join(output)) + + # Log what was done. + candidate_txt = " (candidate)" if candidate == "1" else "" + patch_txt = ".%s" % patch if patch != "0" else "" + version_txt = ("%s.%s.%s%s%s" % + (major, minor, build, patch_txt, candidate_txt)) + print "Modified version.cc. Set V8 version to %s" % version_txt + return 0 + +if __name__ == "__main__": + sys.exit(main()) diff --git a/deps/v8/tools/run_perf.py b/deps/v8/tools/run_perf.py index 14d67c56b0..63c9148515 100755 --- a/deps/v8/tools/run_perf.py +++ b/deps/v8/tools/run_perf.py @@ -529,10 +529,17 @@ class AndroidPlatform(Platform): # pragma: no cover perf.SetDefaultPerfMode() self.device.RunShellCommand(["rm", "-rf", AndroidPlatform.DEVICE_DIR]) + def _SendCommand(self, cmd): + logging.info("adb -s %s %s" % (str(self.device), cmd)) + return self.adb.SendCommand(cmd, timeout_time=60) + def _PushFile(self, host_dir, file_name, target_rel="."): file_on_host = os.path.join(host_dir, file_name) + file_on_device_tmp = os.path.join( + AndroidPlatform.DEVICE_DIR, "_tmp_", file_name) file_on_device = os.path.join( AndroidPlatform.DEVICE_DIR, target_rel, file_name) + folder_on_device = os.path.dirname(file_on_device) # Only push files not yet pushed in one execution. if file_on_host in self.pushed: @@ -540,8 +547,16 @@ class AndroidPlatform(Platform): # pragma: no cover else: self.pushed.add(file_on_host) - logging.info("adb push %s %s" % (file_on_host, file_on_device)) - self.adb.Push(file_on_host, file_on_device) + # Work-around for "text file busy" errors. Push the files to a temporary + # location and then copy them with a shell command. + output = self._SendCommand( + "push %s %s" % (file_on_host, file_on_device_tmp)) + # Success looks like this: "3035 KB/s (12512056 bytes in 4.025s)". + # Errors look like this: "failed to copy ... ". + if output and not re.search('^[0-9]', output.splitlines()[-1]): + logging.critical('PUSH FAILED: ' + output) + self._SendCommand("shell mkdir -p %s" % folder_on_device) + self._SendCommand("shell cp %s %s" % (file_on_device_tmp, file_on_device)) def PreTests(self, node, path): suite_dir = os.path.abspath(os.path.dirname(path)) diff --git a/deps/v8/tools/whitespace.txt b/deps/v8/tools/whitespace.txt index 55592a9254..657e68f42e 100644 --- a/deps/v8/tools/whitespace.txt +++ b/deps/v8/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........... |