Upgrade V8 to version 4.9.385.28

https://chromium.googlesource.com/v8/v8/+/4.9.385.28

FPIIM-449

Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/compiler/representation-change.cc b/src/compiler/representation-change.cc
new file mode 100644
index 0000000..5dab60f
--- /dev/null
+++ b/src/compiler/representation-change.cc
@@ -0,0 +1,537 @@
+// 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.
+
+#include "src/compiler/representation-change.h"
+
+#include <sstream>
+
+#include "src/base/bits.h"
+#include "src/code-factory.h"
+#include "src/compiler/machine-operator.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+const char* Truncation::description() const {
+  switch (kind()) {
+    case TruncationKind::kNone:
+      return "no-value-use";
+    case TruncationKind::kBool:
+      return "truncate-to-bool";
+    case TruncationKind::kWord32:
+      return "truncate-to-word32";
+    case TruncationKind::kWord64:
+      return "truncate-to-word64";
+    case TruncationKind::kFloat32:
+      return "truncate-to-float32";
+    case TruncationKind::kFloat64:
+      return "truncate-to-float64";
+    case TruncationKind::kAny:
+      return "no-truncation";
+  }
+  UNREACHABLE();
+  return nullptr;
+}
+
+
+// Partial order for truncations:
+//
+//  kWord64       kAny
+//     ^            ^
+//     \            |
+//      \         kFloat64  <--+
+//       \        ^    ^       |
+//        \       /    |       |
+//         kWord32  kFloat32  kBool
+//               ^     ^      ^
+//               \     |      /
+//                \    |     /
+//                 \   |    /
+//                  \  |   /
+//                   \ |  /
+//                   kNone
+
+// static
+Truncation::TruncationKind Truncation::Generalize(TruncationKind rep1,
+                                                  TruncationKind rep2) {
+  if (LessGeneral(rep1, rep2)) return rep2;
+  if (LessGeneral(rep2, rep1)) return rep1;
+  // Handle the generalization of float64-representable values.
+  if (LessGeneral(rep1, TruncationKind::kFloat64) &&
+      LessGeneral(rep2, TruncationKind::kFloat64)) {
+    return TruncationKind::kFloat64;
+  }
+  // All other combinations are illegal.
+  FATAL("Tried to combine incompatible truncations");
+  return TruncationKind::kNone;
+}
+
+
+// static
+bool Truncation::LessGeneral(TruncationKind rep1, TruncationKind rep2) {
+  switch (rep1) {
+    case TruncationKind::kNone:
+      return true;
+    case TruncationKind::kBool:
+      return rep2 == TruncationKind::kBool || rep2 == TruncationKind::kAny;
+    case TruncationKind::kWord32:
+      return rep2 == TruncationKind::kWord32 ||
+             rep2 == TruncationKind::kWord64 ||
+             rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny;
+    case TruncationKind::kWord64:
+      return rep2 == TruncationKind::kWord64;
+    case TruncationKind::kFloat32:
+      return rep2 == TruncationKind::kFloat32 ||
+             rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny;
+    case TruncationKind::kFloat64:
+      return rep2 == TruncationKind::kFloat64 || rep2 == TruncationKind::kAny;
+    case TruncationKind::kAny:
+      return rep2 == TruncationKind::kAny;
+  }
+  UNREACHABLE();
+  return false;
+}
+
+
+namespace {
+
+// TODO(titzer): should Word64 also be implicitly convertable to others?
+bool IsWord(MachineRepresentation rep) {
+  return rep == MachineRepresentation::kWord8 ||
+         rep == MachineRepresentation::kWord16 ||
+         rep == MachineRepresentation::kWord32;
+}
+
+}  // namespace
+
+
+// Changes representation from {output_rep} to {use_rep}. The {truncation}
+// parameter is only used for sanity checking - if the changer cannot figure
+// out signedness for the word32->float64 conversion, then we check that the
+// uses truncate to word32 (so they do not care about signedness).
+Node* RepresentationChanger::GetRepresentationFor(
+    Node* node, MachineRepresentation output_rep, Type* output_type,
+    MachineRepresentation use_rep, Truncation truncation) {
+  if (output_rep == MachineRepresentation::kNone) {
+    // The output representation should be set.
+    return TypeError(node, output_rep, output_type, use_rep);
+  }
+  if (use_rep == output_rep) {
+    // Representations are the same. That's a no-op.
+    return node;
+  }
+  if (IsWord(use_rep) && IsWord(output_rep)) {
+    // Both are words less than or equal to 32-bits.
+    // Since loads of integers from memory implicitly sign or zero extend the
+    // value to the full machine word size and stores implicitly truncate,
+    // no representation change is necessary.
+    return node;
+  }
+  switch (use_rep) {
+    case MachineRepresentation::kTagged:
+      return GetTaggedRepresentationFor(node, output_rep, output_type);
+    case MachineRepresentation::kFloat32:
+      return GetFloat32RepresentationFor(node, output_rep, output_type,
+                                         truncation);
+    case MachineRepresentation::kFloat64:
+      return GetFloat64RepresentationFor(node, output_rep, output_type,
+                                         truncation);
+    case MachineRepresentation::kBit:
+      return GetBitRepresentationFor(node, output_rep, output_type);
+    case MachineRepresentation::kWord8:
+    case MachineRepresentation::kWord16:
+    case MachineRepresentation::kWord32:
+      return GetWord32RepresentationFor(node, output_rep, output_type);
+    case MachineRepresentation::kWord64:
+      return GetWord64RepresentationFor(node, output_rep, output_type);
+    case MachineRepresentation::kNone:
+      return node;
+  }
+  UNREACHABLE();
+  return nullptr;
+}
+
+
+Node* RepresentationChanger::GetTaggedRepresentationFor(
+    Node* node, MachineRepresentation output_rep, Type* output_type) {
+  // Eagerly fold representation changes for constants.
+  switch (node->opcode()) {
+    case IrOpcode::kNumberConstant:
+    case IrOpcode::kHeapConstant:
+      return node;  // No change necessary.
+    case IrOpcode::kInt32Constant:
+      if (output_type->Is(Type::Signed32())) {
+        int32_t value = OpParameter<int32_t>(node);
+        return jsgraph()->Constant(value);
+      } else if (output_type->Is(Type::Unsigned32())) {
+        uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node));
+        return jsgraph()->Constant(static_cast<double>(value));
+      } else if (output_rep == MachineRepresentation::kBit) {
+        return OpParameter<int32_t>(node) == 0 ? jsgraph()->FalseConstant()
+                                               : jsgraph()->TrueConstant();
+      } else {
+        return TypeError(node, output_rep, output_type,
+                         MachineRepresentation::kTagged);
+      }
+    case IrOpcode::kFloat64Constant:
+      return jsgraph()->Constant(OpParameter<double>(node));
+    case IrOpcode::kFloat32Constant:
+      return jsgraph()->Constant(OpParameter<float>(node));
+    default:
+      break;
+  }
+  // Select the correct X -> Tagged operator.
+  const Operator* op;
+  if (output_rep == MachineRepresentation::kBit) {
+    op = simplified()->ChangeBitToBool();
+  } else if (IsWord(output_rep)) {
+    if (output_type->Is(Type::Unsigned32())) {
+      op = simplified()->ChangeUint32ToTagged();
+    } else if (output_type->Is(Type::Signed32())) {
+      op = simplified()->ChangeInt32ToTagged();
+    } else {
+      return TypeError(node, output_rep, output_type,
+                       MachineRepresentation::kTagged);
+    }
+  } else if (output_rep ==
+             MachineRepresentation::kFloat32) {  // float32 -> float64 -> tagged
+    node = InsertChangeFloat32ToFloat64(node);
+    op = simplified()->ChangeFloat64ToTagged();
+  } else if (output_rep == MachineRepresentation::kFloat64) {
+    op = simplified()->ChangeFloat64ToTagged();
+  } else {
+    return TypeError(node, output_rep, output_type,
+                     MachineRepresentation::kTagged);
+  }
+  return jsgraph()->graph()->NewNode(op, node);
+}
+
+
+Node* RepresentationChanger::GetFloat32RepresentationFor(
+    Node* node, MachineRepresentation output_rep, Type* output_type,
+    Truncation truncation) {
+  // Eagerly fold representation changes for constants.
+  switch (node->opcode()) {
+    case IrOpcode::kFloat64Constant:
+    case IrOpcode::kNumberConstant:
+      return jsgraph()->Float32Constant(
+          DoubleToFloat32(OpParameter<double>(node)));
+    case IrOpcode::kInt32Constant:
+      if (output_type->Is(Type::Unsigned32())) {
+        uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node));
+        return jsgraph()->Float32Constant(static_cast<float>(value));
+      } else {
+        int32_t value = OpParameter<int32_t>(node);
+        return jsgraph()->Float32Constant(static_cast<float>(value));
+      }
+    case IrOpcode::kFloat32Constant:
+      return node;  // No change necessary.
+    default:
+      break;
+  }
+  // Select the correct X -> Float32 operator.
+  const Operator* op;
+  if (output_rep == MachineRepresentation::kBit) {
+    return TypeError(node, output_rep, output_type,
+                     MachineRepresentation::kFloat32);
+  } else if (IsWord(output_rep)) {
+    if (output_type->Is(Type::Signed32())) {
+      op = machine()->ChangeInt32ToFloat64();
+    } else {
+      // Either the output is int32 or the uses only care about the
+      // low 32 bits (so we can pick int32 safely).
+      DCHECK(output_type->Is(Type::Unsigned32()) ||
+             truncation.TruncatesToWord32());
+      op = machine()->ChangeUint32ToFloat64();
+    }
+    // int32 -> float64 -> float32
+    node = jsgraph()->graph()->NewNode(op, node);
+    op = machine()->TruncateFloat64ToFloat32();
+  } else if (output_rep == MachineRepresentation::kTagged) {
+    op = simplified()->ChangeTaggedToFloat64();  // tagged -> float64 -> float32
+    node = jsgraph()->graph()->NewNode(op, node);
+    op = machine()->TruncateFloat64ToFloat32();
+  } else if (output_rep == MachineRepresentation::kFloat64) {
+    op = machine()->TruncateFloat64ToFloat32();
+  } else {
+    return TypeError(node, output_rep, output_type,
+                     MachineRepresentation::kFloat32);
+  }
+  return jsgraph()->graph()->NewNode(op, node);
+}
+
+
+Node* RepresentationChanger::GetFloat64RepresentationFor(
+    Node* node, MachineRepresentation output_rep, Type* output_type,
+    Truncation truncation) {
+  // Eagerly fold representation changes for constants.
+  switch (node->opcode()) {
+    case IrOpcode::kNumberConstant:
+      return jsgraph()->Float64Constant(OpParameter<double>(node));
+    case IrOpcode::kInt32Constant:
+      if (output_type->Is(Type::Signed32())) {
+        int32_t value = OpParameter<int32_t>(node);
+        return jsgraph()->Float64Constant(value);
+      } else {
+        DCHECK(output_type->Is(Type::Unsigned32()));
+        uint32_t value = static_cast<uint32_t>(OpParameter<int32_t>(node));
+        return jsgraph()->Float64Constant(static_cast<double>(value));
+      }
+    case IrOpcode::kFloat64Constant:
+      return node;  // No change necessary.
+    case IrOpcode::kFloat32Constant:
+      return jsgraph()->Float64Constant(OpParameter<float>(node));
+    default:
+      break;
+  }
+  // Select the correct X -> Float64 operator.
+  const Operator* op;
+  if (output_rep == MachineRepresentation::kBit) {
+    return TypeError(node, output_rep, output_type,
+                     MachineRepresentation::kFloat64);
+  } else if (IsWord(output_rep)) {
+    if (output_type->Is(Type::Signed32())) {
+      op = machine()->ChangeInt32ToFloat64();
+    } else {
+      // Either the output is int32 or the uses only care about the
+      // low 32 bits (so we can pick int32 safely).
+      DCHECK(output_type->Is(Type::Unsigned32()) ||
+             truncation.TruncatesToWord32());
+      op = machine()->ChangeUint32ToFloat64();
+    }
+  } else if (output_rep == MachineRepresentation::kTagged) {
+    op = simplified()->ChangeTaggedToFloat64();
+  } else if (output_rep == MachineRepresentation::kFloat32) {
+    op = machine()->ChangeFloat32ToFloat64();
+  } else {
+    return TypeError(node, output_rep, output_type,
+                     MachineRepresentation::kFloat64);
+  }
+  return jsgraph()->graph()->NewNode(op, node);
+}
+
+
+Node* RepresentationChanger::MakeTruncatedInt32Constant(double value) {
+  return jsgraph()->Int32Constant(DoubleToInt32(value));
+}
+
+
+Node* RepresentationChanger::GetWord32RepresentationFor(
+    Node* node, MachineRepresentation output_rep, Type* output_type) {
+  // Eagerly fold representation changes for constants.
+  switch (node->opcode()) {
+    case IrOpcode::kInt32Constant:
+      return node;  // No change necessary.
+    case IrOpcode::kFloat32Constant:
+      return MakeTruncatedInt32Constant(OpParameter<float>(node));
+    case IrOpcode::kNumberConstant:
+    case IrOpcode::kFloat64Constant:
+      return MakeTruncatedInt32Constant(OpParameter<double>(node));
+    default:
+      break;
+  }
+  // Select the correct X -> Word32 operator.
+  const Operator* op;
+  Type* type = NodeProperties::GetType(node);
+
+  if (output_rep == MachineRepresentation::kBit) {
+    return node;  // Sloppy comparison -> word32
+  } else if (output_rep == MachineRepresentation::kFloat64) {
+    // TODO(jarin) Use only output_type here, once we intersect it with the
+    // type inferred by the typer.
+    if (output_type->Is(Type::Unsigned32()) || type->Is(Type::Unsigned32())) {
+      op = machine()->ChangeFloat64ToUint32();
+    } else if (output_type->Is(Type::Signed32()) ||
+               type->Is(Type::Signed32())) {
+      op = machine()->ChangeFloat64ToInt32();
+    } else {
+      op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
+    }
+  } else if (output_rep == MachineRepresentation::kFloat32) {
+    node = InsertChangeFloat32ToFloat64(node);  // float32 -> float64 -> int32
+    if (output_type->Is(Type::Unsigned32()) || type->Is(Type::Unsigned32())) {
+      op = machine()->ChangeFloat64ToUint32();
+    } else if (output_type->Is(Type::Signed32()) ||
+               type->Is(Type::Signed32())) {
+      op = machine()->ChangeFloat64ToInt32();
+    } else {
+      op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
+    }
+  } else if (output_rep == MachineRepresentation::kTagged) {
+    if (output_type->Is(Type::Unsigned32()) || type->Is(Type::Unsigned32())) {
+      op = simplified()->ChangeTaggedToUint32();
+    } else if (output_type->Is(Type::Signed32()) ||
+               type->Is(Type::Signed32())) {
+      op = simplified()->ChangeTaggedToInt32();
+    } else {
+      node = InsertChangeTaggedToFloat64(node);
+      op = machine()->TruncateFloat64ToInt32(TruncationMode::kJavaScript);
+    }
+  } else {
+    return TypeError(node, output_rep, output_type,
+                     MachineRepresentation::kWord32);
+  }
+  return jsgraph()->graph()->NewNode(op, node);
+}
+
+
+Node* RepresentationChanger::GetBitRepresentationFor(
+    Node* node, MachineRepresentation output_rep, Type* output_type) {
+  // Eagerly fold representation changes for constants.
+  switch (node->opcode()) {
+    case IrOpcode::kHeapConstant: {
+      Handle<HeapObject> value = OpParameter<Handle<HeapObject>>(node);
+      DCHECK(value.is_identical_to(factory()->true_value()) ||
+             value.is_identical_to(factory()->false_value()));
+      return jsgraph()->Int32Constant(
+          value.is_identical_to(factory()->true_value()) ? 1 : 0);
+    }
+    default:
+      break;
+  }
+  // Select the correct X -> Bit operator.
+  const Operator* op;
+  if (output_rep == MachineRepresentation::kTagged) {
+    op = simplified()->ChangeBoolToBit();
+  } else {
+    return TypeError(node, output_rep, output_type,
+                     MachineRepresentation::kBit);
+  }
+  return jsgraph()->graph()->NewNode(op, node);
+}
+
+
+Node* RepresentationChanger::GetWord64RepresentationFor(
+    Node* node, MachineRepresentation output_rep, Type* output_type) {
+  if (output_rep == MachineRepresentation::kBit) {
+    return node;  // Sloppy comparison -> word64
+  }
+  // Can't really convert Word64 to anything else. Purported to be internal.
+  return TypeError(node, output_rep, output_type,
+                   MachineRepresentation::kWord64);
+}
+
+
+const Operator* RepresentationChanger::Int32OperatorFor(
+    IrOpcode::Value opcode) {
+  switch (opcode) {
+    case IrOpcode::kNumberAdd:
+      return machine()->Int32Add();
+    case IrOpcode::kNumberSubtract:
+      return machine()->Int32Sub();
+    case IrOpcode::kNumberMultiply:
+      return machine()->Int32Mul();
+    case IrOpcode::kNumberDivide:
+      return machine()->Int32Div();
+    case IrOpcode::kNumberModulus:
+      return machine()->Int32Mod();
+    case IrOpcode::kNumberBitwiseOr:
+      return machine()->Word32Or();
+    case IrOpcode::kNumberBitwiseXor:
+      return machine()->Word32Xor();
+    case IrOpcode::kNumberBitwiseAnd:
+      return machine()->Word32And();
+    case IrOpcode::kNumberEqual:
+      return machine()->Word32Equal();
+    case IrOpcode::kNumberLessThan:
+      return machine()->Int32LessThan();
+    case IrOpcode::kNumberLessThanOrEqual:
+      return machine()->Int32LessThanOrEqual();
+    default:
+      UNREACHABLE();
+      return nullptr;
+  }
+}
+
+
+const Operator* RepresentationChanger::Uint32OperatorFor(
+    IrOpcode::Value opcode) {
+  switch (opcode) {
+    case IrOpcode::kNumberAdd:
+      return machine()->Int32Add();
+    case IrOpcode::kNumberSubtract:
+      return machine()->Int32Sub();
+    case IrOpcode::kNumberMultiply:
+      return machine()->Int32Mul();
+    case IrOpcode::kNumberDivide:
+      return machine()->Uint32Div();
+    case IrOpcode::kNumberModulus:
+      return machine()->Uint32Mod();
+    case IrOpcode::kNumberEqual:
+      return machine()->Word32Equal();
+    case IrOpcode::kNumberLessThan:
+      return machine()->Uint32LessThan();
+    case IrOpcode::kNumberLessThanOrEqual:
+      return machine()->Uint32LessThanOrEqual();
+    default:
+      UNREACHABLE();
+      return nullptr;
+  }
+}
+
+
+const Operator* RepresentationChanger::Float64OperatorFor(
+    IrOpcode::Value opcode) {
+  switch (opcode) {
+    case IrOpcode::kNumberAdd:
+      return machine()->Float64Add();
+    case IrOpcode::kNumberSubtract:
+      return machine()->Float64Sub();
+    case IrOpcode::kNumberMultiply:
+      return machine()->Float64Mul();
+    case IrOpcode::kNumberDivide:
+      return machine()->Float64Div();
+    case IrOpcode::kNumberModulus:
+      return machine()->Float64Mod();
+    case IrOpcode::kNumberEqual:
+      return machine()->Float64Equal();
+    case IrOpcode::kNumberLessThan:
+      return machine()->Float64LessThan();
+    case IrOpcode::kNumberLessThanOrEqual:
+      return machine()->Float64LessThanOrEqual();
+    default:
+      UNREACHABLE();
+      return nullptr;
+  }
+}
+
+
+Node* RepresentationChanger::TypeError(Node* node,
+                                       MachineRepresentation output_rep,
+                                       Type* output_type,
+                                       MachineRepresentation use) {
+  type_error_ = true;
+  if (!testing_type_errors_) {
+    std::ostringstream out_str;
+    out_str << output_rep << " (";
+    output_type->PrintTo(out_str, Type::SEMANTIC_DIM);
+    out_str << ")";
+
+    std::ostringstream use_str;
+    use_str << use;
+
+    V8_Fatal(__FILE__, __LINE__,
+             "RepresentationChangerError: node #%d:%s of "
+             "%s cannot be changed to %s",
+             node->id(), node->op()->mnemonic(), out_str.str().c_str(),
+             use_str.str().c_str());
+  }
+  return node;
+}
+
+
+Node* RepresentationChanger::InsertChangeFloat32ToFloat64(Node* node) {
+  return jsgraph()->graph()->NewNode(machine()->ChangeFloat32ToFloat64(), node);
+}
+
+
+Node* RepresentationChanger::InsertChangeTaggedToFloat64(Node* node) {
+  return jsgraph()->graph()->NewNode(simplified()->ChangeTaggedToFloat64(),
+                                     node);
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8