deps: upgrade v8 to 4.1.0.7
authorBen Noordhuis <info@bnoordhuis.nl>
Sat, 17 Jan 2015 22:02:56 +0000 (23:02 +0100)
committerBen Noordhuis <info@bnoordhuis.nl>
Sun, 18 Jan 2015 12:05:00 +0000 (13:05 +0100)
This commit upgrades V8 from 3.31.74.1 to 4.1.0.7.  Despite the major
version bump, there are no API or ABI changes, it's a bug fix release
only.

PR-URL: https://github.com/iojs/io.js/pull/490
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Fedor Indutny <fedor@indutny.com>
Reviewed-By: Kenan Sulayman <kenan@sly.mn>
Reviewed-By: Rod Vagg <rod@vagg.org>
57 files changed:
deps/v8/ChangeLog
deps/v8/DEPS
deps/v8/build/features.gypi
deps/v8/src/api.cc
deps/v8/src/base/platform/platform-freebsd.cc
deps/v8/src/base/platform/platform-posix.cc
deps/v8/src/compiler/control-reducer.cc
deps/v8/src/compiler/js-typed-lowering.cc
deps/v8/src/compiler/js-typed-lowering.h
deps/v8/src/compiler/opcodes.h
deps/v8/src/compiler/pipeline.cc
deps/v8/src/compiler/simplified-lowering.cc
deps/v8/src/compiler/simplified-lowering.h
deps/v8/src/compiler/simplified-operator-reducer.cc
deps/v8/src/compiler/simplified-operator-reducer.h
deps/v8/src/compiler/simplified-operator.cc
deps/v8/src/compiler/simplified-operator.h
deps/v8/src/compiler/typer.cc
deps/v8/src/compiler/verifier.cc
deps/v8/src/d8.cc
deps/v8/src/debug.cc
deps/v8/src/deoptimizer.cc
deps/v8/src/flag-definitions.h
deps/v8/src/heap/heap.cc
deps/v8/src/heap/heap.h
deps/v8/src/heap/incremental-marking.cc
deps/v8/src/heap/spaces.cc
deps/v8/src/ia32/assembler-ia32.cc
deps/v8/src/parser.h
deps/v8/src/preparser.h
deps/v8/src/runtime.js
deps/v8/src/unique.h
deps/v8/src/version.cc
deps/v8/src/x64/assembler-x64.cc
deps/v8/test/cctest/compiler/test-js-typed-lowering.cc
deps/v8/test/cctest/compiler/test-simplified-lowering.cc
deps/v8/test/cctest/test-alloc.cc
deps/v8/test/cctest/test-api.cc
deps/v8/test/mjsunit/compiler/regress-445876.js [new file with mode: 0644]
deps/v8/test/mjsunit/compiler/regress-446156.js [new file with mode: 0644]
deps/v8/test/mjsunit/compiler/regress-446778.js [new file with mode: 0644]
deps/v8/test/mjsunit/compiler/regress-ntl-effect.js [new file with mode: 0644]
deps/v8/test/mjsunit/regress/regress-447756.js [new file with mode: 0644]
deps/v8/test/unittests/compiler/change-lowering-unittest.cc
deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc
deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc
deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc
deps/v8/test/unittests/compiler/node-test-utils.cc
deps/v8/test/unittests/compiler/node-test-utils.h
deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc
deps/v8/test/unittests/compiler/simplified-operator-unittest.cc
deps/v8/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt
deps/v8/test/webkit/fast/js/Object-getOwnPropertyNames.js
deps/v8/testing/gmock-support.h
deps/v8/tools/push-to-trunk/generate_version.py [new file with mode: 0755]
deps/v8/tools/run_perf.py
deps/v8/tools/whitespace.txt

index d016b79..d42a2f1 100644 (file)
@@ -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
index e85604b..a81c7ec 100644 (file)
@@ -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 = {
index 25041ce..465eba9 100644 (file)
       'Release': {
         'variables': {
           'v8_enable_extra_checks%': 0,
-          'v8_enable_handle_zapping%': 1,
+          'v8_enable_handle_zapping%': 0,
         },
         'conditions': [
           ['v8_enable_extra_checks==1', {
index 61e565f..88d3c88 100644 (file)
@@ -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();
index 58316f8..507b946 100644 (file)
@@ -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)
index 64aed2b..c2fa26a 100644 (file)
@@ -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
 }
 
index e738ccf..eef8a49 100644 (file)
@@ -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) {
index 2338866..7618375 100644 (file)
@@ -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);
index aa7510b..838085e 100644 (file)
@@ -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);
index 3f00e6a..d229b6d 100644 (file)
 
 // Opcodes for VirtuaMachine-level operators.
 #define SIMPLIFIED_OP_LIST(V) \
+  V(AnyToBoolean)             \
   V(BooleanNot)               \
   V(BooleanToNumber)          \
   V(NumberEqual)              \
index 0e80623..c7432c6 100644 (file)
@@ -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());
index bb57614..1461709 100644 (file)
@@ -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);
 }
 
index 852ac7e..b21cf21 100644 (file)
@@ -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);
index 0868cab..9d45e5b 100644 (file)
@@ -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();
 }
index 8f6c9aa..1e565b8 100644 (file)
@@ -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_; }
 
index e082a4b..9d88d12 100644 (file)
@@ -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)            \
index 72608ee..22664fa 100644 (file)
@@ -128,6 +128,8 @@ class SimplifiedOperatorBuilder FINAL {
  public:
   explicit SimplifiedOperatorBuilder(Zone* zone);
 
+  const Operator* AnyToBoolean();
+
   const Operator* BooleanNot();
   const Operator* BooleanToNumber();
 
index a170a71..137829e 100644 (file)
@@ -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());
index 84b060f..693b414 100644 (file)
@@ -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());
index 132891e..7157cb8 100644 (file)
@@ -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);
index cdcb0a7..93ef1cf 100644 (file)
@@ -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;
 }
 
index 554ba8e..748f95e 100644 (file)
@@ -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,"
index 6f36199..348a52e 100644 (file)
@@ -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
index cf67dab..0b817e4 100644 (file)
@@ -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();
index 3027131..e6ccf2e 100644 (file)
@@ -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).
index 33f9de0..aadd17c 100644 (file)
@@ -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;
   }
 
index 37a123d..3802e47 100644 (file)
@@ -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;
 
index 2805fa0..168a196 100644 (file)
 // 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;
 }
 
index 02dfe15..219f1c4 100644 (file)
@@ -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);
index ad27744..18004a5 100644 (file)
@@ -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);
   }
 
index 79824e4..978429e 100644 (file)
@@ -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;
 }
index 321eb36..9232f85 100644 (file)
@@ -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) {
index e84633d..c71ecff 100644 (file)
 // 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
index 469ebe9..fd722b2 100644 (file)
@@ -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;
 }
 
index 70b1312..3023837 100644 (file)
@@ -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());
   }
 }
 
index d463997..147aa32 100644 (file)
@@ -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},
index 54d516e..2e071ac 100644 (file)
@@ -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);
index 5c8584d..d18059c 100644 (file)
@@ -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 (file)
index 0000000..30e10e5
--- /dev/null
@@ -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 (file)
index 0000000..f3cd2dd
--- /dev/null
@@ -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 (file)
index 0000000..a7fa3fd
--- /dev/null
@@ -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 (file)
index 0000000..708fe32
--- /dev/null
@@ -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 (file)
index 0000000..1fc7518
--- /dev/null
@@ -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();
+}
index 763a443..060b1c1 100644 (file)
@@ -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) {
index 87d1ad5..9c57282 100644 (file)
@@ -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)));
     }
   }
 }
index e4ea4a5..97ff106 100644 (file)
@@ -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))));
   }
 }
 
index b92bd28..6fdba35 100644 (file)
@@ -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));
   }
 }
 
index 3162c54..74afda9 100644 (file)
@@ -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)
index f1f20cf..02b6e43 100644 (file)
@@ -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);
index 066cbe9..e5f46c0 100644 (file)
@@ -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))));
   }
 }
 
index e7fceba..bc537fd 100644 (file)
@@ -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),
index c96c836..0e00f23 100644 (file)
@@ -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']
index 46d7966..72bd21b 100644 (file)
@@ -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']",
index 44348b6..012775b 100644 (file)
@@ -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 (executable)
index 0000000..b4a0221
--- /dev/null
@@ -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())
index 14d67c5..63c9148 100755 (executable)
@@ -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))
index 55592a9..657e68f 100644 (file)
@@ -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...........