Version 3.30.33 (based on 6bee6dcebc3033d4665a8069020302ce5018522d)
`1..isPrototypeOf.call(null)` should return false, not throw TypeError (issue 3483).
Refactor ObjectGetOwnPropertyKeys to accept bitmask rather than boolean (issue 3549).
Add debug mirror support for ES6 Map/Set iterators (Chromium issue 427868).
Performance and stability improvements on all platforms.
Cr-Commit-Position: refs/heads/candidates@{#25122}
git-svn-id: https://v8.googlecode.com/svn/trunk@25122 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/BUILD.gn b/BUILD.gn
index 0b1b06e..1758ee9 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -498,6 +498,7 @@
"src/compiler/control-builders.h",
"src/compiler/control-reducer.cc",
"src/compiler/control-reducer.h",
+ "src/compiler/diamond.h",
"src/compiler/frame.h",
"src/compiler/gap-resolver.cc",
"src/compiler/gap-resolver.h",
@@ -571,6 +572,8 @@
"src/compiler/raw-machine-assembler.h",
"src/compiler/register-allocator.cc",
"src/compiler/register-allocator.h",
+ "src/compiler/register-configuration.cc",
+ "src/compiler/register-configuration.h",
"src/compiler/representation-change.h",
"src/compiler/schedule.cc",
"src/compiler/schedule.h",
diff --git a/ChangeLog b/ChangeLog
index 6e758a3..1e29853 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2014-11-05: Version 3.30.33
+
+ `1..isPrototypeOf.call(null)` should return false, not throw TypeError
+ (issue 3483).
+
+ Refactor ObjectGetOwnPropertyKeys to accept bitmask rather than boolean
+ (issue 3549).
+
+ Add debug mirror support for ES6 Map/Set iterators (Chromium issue
+ 427868).
+
+ Performance and stability improvements on all platforms.
+
+
2014-11-04: Version 3.30.30
Performance and stability improvements on all platforms.
diff --git a/include/v8.h b/include/v8.h
index 37e0ddc..d5433a6 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1626,6 +1626,18 @@
bool IsSet() const;
/**
+ * Returns true if this value is a Map Iterator.
+ * This is an experimental feature.
+ */
+ bool IsMapIterator() const;
+
+ /**
+ * Returns true if this value is a Set Iterator.
+ * This is an experimental feature.
+ */
+ bool IsSetIterator() const;
+
+ /**
* Returns true if this value is a WeakMap.
* This is an experimental feature.
*/
diff --git a/src/api.cc b/src/api.cc
index c9231a3..2c8009e 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -2571,6 +2571,16 @@
}
+bool Value::IsMapIterator() const {
+ return Utils::OpenHandle(this)->IsJSMapIterator();
+}
+
+
+bool Value::IsSetIterator() const {
+ return Utils::OpenHandle(this)->IsJSSetIterator();
+}
+
+
Local<String> Value::ToString(Isolate* v8_isolate) const {
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::Object> str;
diff --git a/src/arm/interface-descriptors-arm.cc b/src/arm/interface-descriptors-arm.cc
index 1b397ff..6e77ee4 100644
--- a/src/arm/interface-descriptors-arm.cc
+++ b/src/arm/interface-descriptors-arm.cc
@@ -152,6 +152,15 @@
}
+void AllocateHeapNumberDescriptor::Initialize(
+ CallInterfaceDescriptorData* data) {
+ // register state
+ // cp -- context
+ Register registers[] = {cp};
+ data->Initialize(arraysize(registers), registers, nullptr);
+}
+
+
void ArrayConstructorConstantArgCountDescriptor::Initialize(
CallInterfaceDescriptorData* data) {
// register state
diff --git a/src/arm64/interface-descriptors-arm64.cc b/src/arm64/interface-descriptors-arm64.cc
index 705e61b..57eebcc 100644
--- a/src/arm64/interface-descriptors-arm64.cc
+++ b/src/arm64/interface-descriptors-arm64.cc
@@ -185,6 +185,14 @@
}
+void AllocateHeapNumberDescriptor::Initialize(
+ CallInterfaceDescriptorData* data) {
+ // cp: context
+ Register registers[] = {cp};
+ data->Initialize(arraysize(registers), registers, nullptr);
+}
+
+
void ArrayConstructorConstantArgCountDescriptor::Initialize(
CallInterfaceDescriptorData* data) {
// cp: context
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 8fd762c..264d1c6 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -215,11 +215,9 @@
void InstallNativeFunctions_##id(); \
void InitializeGlobal_##id();
- SHIPPING_FEATURES(DECLARE_FEATURE_INITIALIZATION)
- HARMONY_FEATURES(DECLARE_FEATURE_INITIALIZATION)
- STAGED_FEATURES(DECLARE_FEATURE_INITIALIZATION)
-
- DECLARE_FEATURE_INITIALIZATION(harmony_proxies, "")
+ HARMONY_INPROGRESS(DECLARE_FEATURE_INITIALIZATION)
+ HARMONY_STAGED(DECLARE_FEATURE_INITIALIZATION)
+ HARMONY_SHIPPING(DECLARE_FEATURE_INITIALIZATION)
#undef DECLARE_FEATURE_INITIALIZATION
Handle<JSFunction> InstallInternalArray(Handle<JSBuiltinsObject> builtins,
@@ -1344,7 +1342,7 @@
#define FEATURE_INITIALIZE_GLOBAL(id, descr) InitializeGlobal_##id();
- SHIPPING_FEATURES(FEATURE_INITIALIZE_GLOBAL)
+ HARMONY_SHIPPING(FEATURE_INITIALIZE_GLOBAL)
#undef FEATURE_INITIALIZE_GLOBAL
// Initialize the embedder data slot.
@@ -1379,8 +1377,8 @@
void Genesis::InitializeExperimentalGlobal() {
#define FEATURE_INITIALIZE_GLOBAL(id, descr) InitializeGlobal_##id();
- HARMONY_FEATURES(FEATURE_INITIALIZE_GLOBAL)
- STAGED_FEATURES(FEATURE_INITIALIZE_GLOBAL)
+ HARMONY_INPROGRESS(FEATURE_INITIALIZE_GLOBAL)
+ HARMONY_STAGED(FEATURE_INITIALIZE_GLOBAL)
#undef FEATURE_INITIALIZE_GLOBAL
}
@@ -1565,8 +1563,7 @@
INSTALL_NATIVE(JSFunction, "ArrayValues", array_values_iterator);
#define INSTALL_NATIVE_FUNCTIONS_FOR(id, descr) InstallNativeFunctions_##id();
-
- SHIPPING_FEATURES(INSTALL_NATIVE_FUNCTIONS_FOR)
+ HARMONY_SHIPPING(INSTALL_NATIVE_FUNCTIONS_FOR)
#undef INSTALL_NATIVE_FUNCTIONS_FOR
}
@@ -1580,10 +1577,8 @@
}
#define INSTALL_NATIVE_FUNCTIONS_FOR(id, descr) InstallNativeFunctions_##id();
-
- HARMONY_FEATURES(INSTALL_NATIVE_FUNCTIONS_FOR)
- STAGED_FEATURES(INSTALL_NATIVE_FUNCTIONS_FOR)
- INSTALL_NATIVE_FUNCTIONS_FOR(harmony_proxies, "")
+ HARMONY_INPROGRESS(INSTALL_NATIVE_FUNCTIONS_FOR)
+ HARMONY_STAGED(INSTALL_NATIVE_FUNCTIONS_FOR)
#undef INSTALL_NATIVE_FUNCTIONS_FOR
}
@@ -1626,6 +1621,7 @@
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_arrow_functions)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_numeric_literals)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_tostring)
+EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_proxies)
void Genesis::InitializeGlobal_harmony_regexps() {
Handle<JSObject> builtins(native_context()->builtins());
@@ -2180,16 +2176,14 @@
} \
} \
}
- INSTALL_EXPERIMENTAL_NATIVES(harmony_proxies, "");
// Iterate over flags that are not enabled by default.
- HARMONY_FEATURES(INSTALL_EXPERIMENTAL_NATIVES);
- STAGED_FEATURES(INSTALL_EXPERIMENTAL_NATIVES);
+ HARMONY_INPROGRESS(INSTALL_EXPERIMENTAL_NATIVES);
+ HARMONY_STAGED(INSTALL_EXPERIMENTAL_NATIVES);
#undef INSTALL_EXPERIMENTAL_NATIVES
}
#define USE_NATIVES_FOR_FEATURE(id, descr) USE(id##_natives);
-
- SHIPPING_FEATURES(USE_NATIVES_FOR_FEATURE)
+ HARMONY_SHIPPING(USE_NATIVES_FOR_FEATURE)
#undef USE_NATIVES_FOR_FEATURE
InstallExperimentalNativeFunctions();
diff --git a/src/code-factory.cc b/src/code-factory.cc
index ae94fd5..e68d539 100644
--- a/src/code-factory.cc
+++ b/src/code-factory.cc
@@ -104,6 +104,13 @@
// static
+Callable CodeFactory::AllocateHeapNumber(Isolate* isolate) {
+ AllocateHeapNumberStub stub(isolate);
+ return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
+}
+
+
+// static
Callable CodeFactory::CallFunction(Isolate* isolate, int argc,
CallFunctionFlags flags) {
CallFunctionStub stub(isolate, argc, flags);
diff --git a/src/code-factory.h b/src/code-factory.h
index 2426cf0..f26bf2a 100644
--- a/src/code-factory.h
+++ b/src/code-factory.h
@@ -55,9 +55,13 @@
static Callable StringAdd(Isolate* isolate, StringAddFlags flags,
PretenureFlag pretenure_flag);
+ static Callable AllocateHeapNumber(Isolate* isolate);
+
static Callable CallFunction(Isolate* isolate, int argc,
CallFunctionFlags flags);
};
-}
-}
+
+} // namespace internal
+} // namespace v8
+
#endif // V8_CODE_FACTORY_H_
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index e3cbe7d..5579e05 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -883,6 +883,22 @@
return DoGenerateCode(this);
}
+
+template <>
+HValue* CodeStubGraphBuilder<AllocateHeapNumberStub>::BuildCodeStub() {
+ HValue* result =
+ Add<HAllocate>(Add<HConstant>(HeapNumber::kSize), HType::HeapNumber(),
+ NOT_TENURED, HEAP_NUMBER_TYPE);
+ AddStoreMapConstant(result, isolate()->factory()->heap_number_map());
+ return result;
+}
+
+
+Handle<Code> AllocateHeapNumberStub::GenerateCode() {
+ return DoGenerateCode(this);
+}
+
+
HValue* CodeStubGraphBuilderBase::BuildArrayConstructor(
ElementsKind kind,
AllocationSiteOverrideMode override_mode,
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 9832650..552b7eb 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -697,6 +697,13 @@
}
+void AllocateHeapNumberStub::InitializeDescriptor(
+ CodeStubDescriptor* descriptor) {
+ descriptor->Initialize(
+ Runtime::FunctionForId(Runtime::kAllocateHeapNumber)->entry);
+}
+
+
void CompareNilICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
descriptor->Initialize(FUNCTION_ADDR(CompareNilIC_Miss));
descriptor->SetMissHandler(
diff --git a/src/code-stubs.h b/src/code-stubs.h
index e8b7c83..6921883 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -51,6 +51,7 @@
V(StubFailureTrampoline) \
V(SubString) \
/* HydrogenCodeStubs */ \
+ V(AllocateHeapNumber) \
V(ArrayNArgumentsConstructor) \
V(ArrayNoArgumentConstructor) \
V(ArraySingleArgumentConstructor) \
@@ -2113,6 +2114,17 @@
};
+class AllocateHeapNumberStub FINAL : public HydrogenCodeStub {
+ public:
+ explicit AllocateHeapNumberStub(Isolate* isolate)
+ : HydrogenCodeStub(isolate) {}
+
+ private:
+ DEFINE_CALL_INTERFACE_DESCRIPTOR(AllocateHeapNumber);
+ DEFINE_HYDROGEN_CODE_STUB(AllocateHeapNumber, HydrogenCodeStub);
+};
+
+
class ArrayConstructorStubBase : public HydrogenCodeStub {
public:
ArrayConstructorStubBase(Isolate* isolate,
diff --git a/src/compiler/change-lowering.cc b/src/compiler/change-lowering.cc
index 0b4a399..cf18e62 100644
--- a/src/compiler/change-lowering.cc
+++ b/src/compiler/change-lowering.cc
@@ -4,6 +4,8 @@
#include "src/compiler/change-lowering.h"
+#include "src/code-factory.h"
+#include "src/compiler/diamond.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/linkage.h"
#include "src/compiler/machine-operator.h"
@@ -66,19 +68,16 @@
Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node* control) {
- // The AllocateHeapNumber() runtime function does not use the context, so we
- // can safely pass in Smi zero here.
+ // The AllocateHeapNumberStub does not use the context, so we can safely pass
+ // in Smi zero here.
+ Callable callable = CodeFactory::AllocateHeapNumber(isolate());
+ CallDescriptor* descriptor = linkage()->GetStubCallDescriptor(
+ callable.descriptor(), 0, CallDescriptor::kNoFlags);
+ Node* target = jsgraph()->HeapConstant(callable.code());
Node* context = jsgraph()->ZeroConstant();
Node* effect = graph()->NewNode(common()->ValueEffect(1), value);
- const Runtime::Function* function =
- Runtime::FunctionForId(Runtime::kAllocateHeapNumber);
- DCHECK_EQ(0, function->nargs);
- CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(
- function->function_id, 0, Operator::kNoProperties);
- Node* heap_number = graph()->NewNode(
- common()->Call(desc), jsgraph()->CEntryStubConstant(),
- jsgraph()->ExternalConstant(ExternalReference(function, isolate())),
- jsgraph()->Int32Constant(function->nargs), context, effect, control);
+ Node* heap_number = graph()->NewNode(common()->Call(descriptor), target,
+ context, effect, control);
Node* store = graph()->NewNode(
machine()->Store(StoreRepresentation(kMachFloat64, kNoWriteBarrier)),
heap_number, HeapNumberValueIndexConstant(), value, heap_number, control);
@@ -103,20 +102,11 @@
Reduction ChangeLowering::ChangeBitToBool(Node* val, Node* control) {
- Node* branch = graph()->NewNode(common()->Branch(), val, control);
-
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* true_value = jsgraph()->TrueConstant();
-
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
- Node* false_value = jsgraph()->FalseConstant();
-
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
- Node* phi = graph()->NewNode(
- common()->Phi(static_cast<MachineType>(kTypeBool | kRepTagged), 2),
- true_value, false_value, merge);
-
- return Replace(phi);
+ Diamond d(graph(), common(), val);
+ d.Chain(control);
+ MachineType machine_type = static_cast<MachineType>(kTypeBool | kRepTagged);
+ return Replace(d.Phi(machine_type, jsgraph()->TrueConstant(),
+ jsgraph()->FalseConstant()));
}
@@ -142,21 +132,12 @@
Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), val, val);
Node* ovf = graph()->NewNode(common()->Projection(1), add);
- Node* branch =
- graph()->NewNode(common()->Branch(BranchHint::kTrue), ovf, control);
-
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+ Diamond d(graph(), common(), ovf, BranchHint::kFalse);
+ d.Chain(control);
Node* heap_number = AllocateHeapNumberWithValue(
- graph()->NewNode(machine()->ChangeInt32ToFloat64(), val), if_true);
-
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+ graph()->NewNode(machine()->ChangeInt32ToFloat64(), val), d.if_true);
Node* smi = graph()->NewNode(common()->Projection(0), add);
-
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
- Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), heap_number,
- smi, merge);
-
- return Replace(phi);
+ return Replace(d.Phi(kMachAnyTagged, heap_number, smi));
}
@@ -167,23 +148,17 @@
Node* tag = graph()->NewNode(machine()->WordAnd(), val,
jsgraph()->IntPtrConstant(kSmiTagMask));
- Node* branch = graph()->NewNode(common()->Branch(), tag, control);
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+ Diamond d(graph(), common(), tag, BranchHint::kFalse);
+ d.Chain(control);
const Operator* op = (signedness == kSigned)
? machine()->ChangeFloat64ToInt32()
: machine()->ChangeFloat64ToUint32();
- Node* change = graph()->NewNode(op, LoadHeapNumberValue(val, if_true));
-
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+ Node* load = graph()->NewNode(op, LoadHeapNumberValue(val, d.if_true));
Node* number = ChangeSmiToInt32(val);
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
- Node* phi = graph()->NewNode(
- common()->Phi((signedness == kSigned) ? kMachInt32 : kMachUint32, 2),
- change, number, merge);
-
- return Replace(phi);
+ return Replace(
+ d.Phi((signedness == kSigned) ? kMachInt32 : kMachUint32, load, number));
}
@@ -193,20 +168,13 @@
Node* tag = graph()->NewNode(machine()->WordAnd(), val,
jsgraph()->IntPtrConstant(kSmiTagMask));
- Node* branch = graph()->NewNode(common()->Branch(), tag, control);
-
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* load = LoadHeapNumberValue(val, if_true);
-
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+ Diamond d(graph(), common(), tag, BranchHint::kFalse);
+ d.Chain(control);
+ Node* load = LoadHeapNumberValue(val, d.if_true);
Node* number = graph()->NewNode(machine()->ChangeInt32ToFloat64(),
ChangeSmiToInt32(val));
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
- Node* phi =
- graph()->NewNode(common()->Phi(kMachFloat64, 2), load, number, merge);
-
- return Replace(phi);
+ return Replace(d.Phi(kMachFloat64, load, number));
}
@@ -216,10 +184,8 @@
Node* cmp = graph()->NewNode(machine()->Uint32LessThanOrEqual(), val,
SmiMaxValueConstant());
- Node* branch =
- graph()->NewNode(common()->Branch(BranchHint::kTrue), cmp, control);
-
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+ Diamond d(graph(), common(), cmp, BranchHint::kTrue);
+ d.Chain(control);
Node* smi = graph()->NewNode(
machine()->WordShl(),
machine()->Is64()
@@ -227,15 +193,10 @@
: val,
SmiShiftBitsConstant());
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* heap_number = AllocateHeapNumberWithValue(
- graph()->NewNode(machine()->ChangeUint32ToFloat64(), val), if_false);
+ graph()->NewNode(machine()->ChangeUint32ToFloat64(), val), d.if_false);
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
- Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), smi,
- heap_number, merge);
-
- return Replace(phi);
+ return Replace(d.Phi(kMachAnyTagged, smi, heap_number));
}
diff --git a/src/compiler/diamond.h b/src/compiler/diamond.h
new file mode 100644
index 0000000..6133cc5
--- /dev/null
+++ b/src/compiler/diamond.h
@@ -0,0 +1,85 @@
+// Copyright 2013 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.
+
+#ifndef V8_COMPILER_DIAMOND_H_
+#define V8_COMPILER_DIAMOND_H_
+
+#include "src/v8.h"
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph-inl.h"
+#include "src/compiler/node.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// A helper to make it easier to build diamond-shaped control patterns.
+struct Diamond {
+ Graph* graph;
+ CommonOperatorBuilder* common;
+ Node* branch;
+ Node* if_true;
+ Node* if_false;
+ Node* merge;
+
+ Diamond(Graph* g, CommonOperatorBuilder* b, Node* cond,
+ BranchHint hint = BranchHint::kNone) {
+ graph = g;
+ common = b;
+ branch = graph->NewNode(common->Branch(hint), cond, graph->start());
+ if_true = graph->NewNode(common->IfTrue(), branch);
+ if_false = graph->NewNode(common->IfFalse(), branch);
+ merge = graph->NewNode(common->Merge(2), if_true, if_false);
+ }
+
+ // Place {this} after {that} in control flow order.
+ void Chain(Diamond& that) { branch->ReplaceInput(1, that.merge); }
+
+ // Place {this} after {that} in control flow order.
+ void Chain(Node* that) { branch->ReplaceInput(1, that); }
+
+ // Nest {this} into either the if_true or if_false branch of {that}.
+ void Nest(Diamond& that, bool if_true) {
+ if (if_true) {
+ branch->ReplaceInput(1, that.if_true);
+ that.merge->ReplaceInput(0, merge);
+ } else {
+ branch->ReplaceInput(1, that.if_false);
+ that.merge->ReplaceInput(1, merge);
+ }
+ }
+
+ Node* Phi(MachineType machine_type, Node* tv, Node* fv) {
+ return graph->NewNode(common->Phi(machine_type, 2), tv, fv, merge);
+ }
+
+ Node* EffectPhi(Node* tv, Node* fv) {
+ return graph->NewNode(common->EffectPhi(2), tv, fv, merge);
+ }
+
+ void OverwriteWithPhi(Node* node, MachineType machine_type, Node* tv,
+ Node* fv) {
+ DCHECK(node->InputCount() >= 3);
+ node->set_op(common->Phi(machine_type, 2));
+ node->ReplaceInput(0, tv);
+ node->ReplaceInput(1, fv);
+ node->ReplaceInput(2, merge);
+ node->TrimInputCount(3);
+ }
+
+ void OverwriteWithEffectPhi(Node* node, Node* te, Node* fe) {
+ DCHECK(node->InputCount() >= 3);
+ node->set_op(common->EffectPhi(2));
+ node->ReplaceInput(0, te);
+ node->ReplaceInput(1, fe);
+ node->ReplaceInput(2, merge);
+ node->TrimInputCount(3);
+ }
+};
+}
+}
+} // namespace v8::internal::compiler
+
+#endif // V8_COMPILER_DIAMOND_H_
diff --git a/src/compiler/graph-visualizer.cc b/src/compiler/graph-visualizer.cc
index 559da32..19f24cf 100644
--- a/src/compiler/graph-visualizer.cc
+++ b/src/compiler/graph-visualizer.cc
@@ -680,7 +680,9 @@
for (int j = instruction_block->first_instruction_index();
j <= instruction_block->last_instruction_index(); j++) {
PrintIndent();
- os_ << j << " " << *instructions->InstructionAt(j) << " <|@\n";
+ PrintableInstruction printable = {RegisterConfiguration::ArchDefault(),
+ instructions->InstructionAt(j)};
+ os_ << j << " " << printable << " <|@\n";
}
}
}
diff --git a/src/compiler/instruction.cc b/src/compiler/instruction.cc
index 9705bea..76a6950 100644
--- a/src/compiler/instruction.cc
+++ b/src/compiler/instruction.cc
@@ -6,17 +6,15 @@
#include "src/compiler/generic-node-inl.h"
#include "src/compiler/graph.h"
#include "src/compiler/instruction.h"
-#include "src/macro-assembler.h"
namespace v8 {
namespace internal {
namespace compiler {
-STATIC_ASSERT(kMaxGeneralRegisters >= Register::kNumRegisters);
-STATIC_ASSERT(kMaxDoubleRegisters >= DoubleRegister::kMaxNumRegisters);
-
-
-std::ostream& operator<<(std::ostream& os, const InstructionOperand& op) {
+std::ostream& operator<<(std::ostream& os,
+ const PrintableInstructionOperand& printable) {
+ const InstructionOperand& op = *printable.op_;
+ const RegisterConfiguration* conf = printable.register_configuration_;
switch (op.kind()) {
case InstructionOperand::INVALID:
return os << "(0)";
@@ -30,10 +28,10 @@
case UnallocatedOperand::NONE:
return os;
case UnallocatedOperand::FIXED_REGISTER:
- return os << "(=" << Register::AllocationIndexToString(
+ return os << "(=" << conf->general_register_name(
unalloc->fixed_register_index()) << ")";
case UnallocatedOperand::FIXED_DOUBLE_REGISTER:
- return os << "(=" << DoubleRegister::AllocationIndexToString(
+ return os << "(=" << conf->double_register_name(
unalloc->fixed_register_index()) << ")";
case UnallocatedOperand::MUST_HAVE_REGISTER:
return os << "(R)";
@@ -52,11 +50,9 @@
case InstructionOperand::DOUBLE_STACK_SLOT:
return os << "[double_stack:" << op.index() << "]";
case InstructionOperand::REGISTER:
- return os << "[" << Register::AllocationIndexToString(op.index())
- << "|R]";
+ return os << "[" << conf->general_register_name(op.index()) << "|R]";
case InstructionOperand::DOUBLE_REGISTER:
- return os << "[" << DoubleRegister::AllocationIndexToString(op.index())
- << "|R]";
+ return os << "[" << conf->double_register_name(op.index()) << "|R]";
}
UNREACHABLE();
return os;
@@ -101,9 +97,17 @@
}
-std::ostream& operator<<(std::ostream& os, const MoveOperands& mo) {
- os << *mo.destination();
- if (!mo.source()->Equals(mo.destination())) os << " = " << *mo.source();
+std::ostream& operator<<(std::ostream& os,
+ const PrintableMoveOperands& printable) {
+ const MoveOperands& mo = *printable.move_operands_;
+ PrintableInstructionOperand printable_op = {printable.register_configuration_,
+ mo.destination()};
+
+ os << printable_op;
+ if (!mo.source()->Equals(mo.destination())) {
+ printable_op.op_ = mo.source();
+ os << " = " << printable_op;
+ }
return os << ";";
}
@@ -116,14 +120,17 @@
}
-std::ostream& operator<<(std::ostream& os, const ParallelMove& pm) {
+std::ostream& operator<<(std::ostream& os,
+ const PrintableParallelMove& printable) {
+ const ParallelMove& pm = *printable.parallel_move_;
bool first = true;
for (ZoneList<MoveOperands>::iterator move = pm.move_operands()->begin();
move != pm.move_operands()->end(); ++move) {
if (move->IsEliminated()) continue;
if (!first) os << " ";
first = false;
- os << *move;
+ PrintableMoveOperands pmo = {printable.register_configuration_, move};
+ os << pmo;
}
return os;
}
@@ -256,11 +263,16 @@
}
-std::ostream& operator<<(std::ostream& os, const Instruction& instr) {
+std::ostream& operator<<(std::ostream& os,
+ const PrintableInstruction& printable) {
+ const Instruction& instr = *printable.instr_;
+ PrintableInstructionOperand printable_op = {printable.register_configuration_,
+ NULL};
if (instr.OutputCount() > 1) os << "(";
for (size_t i = 0; i < instr.OutputCount(); i++) {
if (i > 0) os << ", ";
- os << *instr.OutputAt(i);
+ printable_op.op_ = instr.OutputAt(i);
+ os << printable_op;
}
if (instr.OutputCount() > 1) os << ") = ";
@@ -272,7 +284,11 @@
for (int i = GapInstruction::FIRST_INNER_POSITION;
i <= GapInstruction::LAST_INNER_POSITION; i++) {
os << "(";
- if (gap->parallel_moves_[i] != NULL) os << *gap->parallel_moves_[i];
+ if (gap->parallel_moves_[i] != NULL) {
+ PrintableParallelMove ppm = {printable.register_configuration_,
+ gap->parallel_moves_[i]};
+ os << ppm;
+ }
os << ") ";
}
} else if (instr.IsSourcePosition()) {
@@ -293,7 +309,8 @@
}
if (instr.InputCount() > 0) {
for (size_t i = 0; i < instr.InputCount(); i++) {
- os << " " << *instr.InputAt(i);
+ printable_op.op_ = instr.InputAt(i);
+ os << " " << printable_op;
}
}
return os;
@@ -585,7 +602,9 @@
}
-std::ostream& operator<<(std::ostream& os, const InstructionSequence& code) {
+std::ostream& operator<<(std::ostream& os,
+ const PrintableInstructionSequence& printable) {
+ const InstructionSequence& code = *printable.sequence_;
for (size_t i = 0; i < code.immediates_.size(); ++i) {
Constant constant = code.immediates_[i];
os << "IMM#" << i << ": " << constant << "\n";
@@ -626,20 +645,16 @@
}
ScopedVector<char> buf(32);
+ PrintableInstruction printable_instr;
+ printable_instr.register_configuration_ = printable.register_configuration_;
for (int j = block->first_instruction_index();
j <= block->last_instruction_index(); j++) {
// TODO(svenpanne) Add some basic formatting to our streams.
SNPrintF(buf, "%5d", j);
- os << " " << buf.start() << ": " << *code.InstructionAt(j) << "\n";
+ printable_instr.instr_ = code.InstructionAt(j);
+ os << " " << buf.start() << ": " << printable_instr << "\n";
}
- // TODO(dcarney): add this back somehow?
- // os << " " << block->control();
-
- // if (block->control_input() != NULL) {
- // os << " v" << block->control_input()->id();
- // }
-
for (auto succ : block->successors()) {
const InstructionBlock* succ_block = code.InstructionBlockAt(succ);
os << " B" << succ_block->id();
diff --git a/src/compiler/instruction.h b/src/compiler/instruction.h
index 4f6649f..b42e17b 100644
--- a/src/compiler/instruction.h
+++ b/src/compiler/instruction.h
@@ -14,6 +14,7 @@
#include "src/compiler/frame.h"
#include "src/compiler/instruction-codes.h"
#include "src/compiler/opcodes.h"
+#include "src/compiler/register-configuration.h"
#include "src/compiler/schedule.h"
#include "src/compiler/source-position.h"
#include "src/zone-allocator.h"
@@ -27,18 +28,13 @@
const InstructionCode kBlockStartInstruction = -2;
const InstructionCode kSourcePositionInstruction = -3;
-// Platform independent maxes.
-static const int kMaxGeneralRegisters = 32;
-static const int kMaxDoubleRegisters = 32;
-
-
-#define INSTRUCTION_OPERAND_LIST(V) \
- V(Constant, CONSTANT, 0) \
- V(Immediate, IMMEDIATE, 0) \
- V(StackSlot, STACK_SLOT, 128) \
- V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128) \
- V(Register, REGISTER, kMaxGeneralRegisters) \
- V(DoubleRegister, DOUBLE_REGISTER, kMaxDoubleRegisters)
+#define INSTRUCTION_OPERAND_LIST(V) \
+ V(Constant, CONSTANT, 0) \
+ V(Immediate, IMMEDIATE, 0) \
+ V(StackSlot, STACK_SLOT, 128) \
+ V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128) \
+ V(Register, REGISTER, RegisterConfiguration::kMaxGeneralRegisters) \
+ V(DoubleRegister, DOUBLE_REGISTER, RegisterConfiguration::kMaxDoubleRegisters)
class InstructionOperand : public ZoneObject {
public:
@@ -87,7 +83,13 @@
typedef ZoneVector<InstructionOperand*> InstructionOperandVector;
-std::ostream& operator<<(std::ostream& os, const InstructionOperand& op);
+struct PrintableInstructionOperand {
+ const RegisterConfiguration* register_configuration_;
+ const InstructionOperand* op_;
+};
+
+std::ostream& operator<<(std::ostream& os,
+ const PrintableInstructionOperand& op);
class UnallocatedOperand : public InstructionOperand {
public:
@@ -306,7 +308,15 @@
InstructionOperand* destination_;
};
-std::ostream& operator<<(std::ostream& os, const MoveOperands& mo);
+
+struct PrintableMoveOperands {
+ const RegisterConfiguration* register_configuration_;
+ const MoveOperands* move_operands_;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const PrintableMoveOperands& mo);
+
template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands>
class SubKindOperand FINAL : public InstructionOperand {
@@ -359,7 +369,15 @@
ZoneList<MoveOperands> move_operands_;
};
-std::ostream& operator<<(std::ostream& os, const ParallelMove& pm);
+
+struct PrintableParallelMove {
+ const RegisterConfiguration* register_configuration_;
+ const ParallelMove* parallel_move_;
+};
+
+
+std::ostream& operator<<(std::ostream& os, const PrintableParallelMove& pm);
+
class PointerMap FINAL : public ZoneObject {
public:
@@ -534,7 +552,13 @@
InstructionOperand* operands_[1];
};
-std::ostream& operator<<(std::ostream& os, const Instruction& instr);
+
+struct PrintableInstruction {
+ const RegisterConfiguration* register_configuration_;
+ const Instruction* instr_;
+};
+std::ostream& operator<<(std::ostream& os, const PrintableInstruction& instr);
+
// Represents moves inserted before an instruction due to register allocation.
// TODO(titzer): squash GapInstruction back into Instruction, since essentially
@@ -585,7 +609,8 @@
}
private:
- friend std::ostream& operator<<(std::ostream& os, const Instruction& instr);
+ friend std::ostream& operator<<(std::ostream& os,
+ const PrintableInstruction& instr);
ParallelMove* parallel_moves_[LAST_INNER_POSITION + 1];
};
@@ -847,6 +872,9 @@
typedef ZoneVector<FrameStateDescriptor*> DeoptimizationVector;
typedef ZoneVector<InstructionBlock*> InstructionBlocks;
+struct PrintableInstructionSequence;
+
+
// Represents architecture-specific generated code before, during, and after
// register allocation.
// TODO(titzer): s/IsDouble/IsFloat64/
@@ -961,7 +989,7 @@
private:
friend std::ostream& operator<<(std::ostream& os,
- const InstructionSequence& code);
+ const PrintableInstructionSequence& code);
typedef std::set<int, std::less<int>, ZoneIntAllocator> VirtualRegisterSet;
@@ -977,7 +1005,15 @@
DeoptimizationVector deoptimization_entries_;
};
-std::ostream& operator<<(std::ostream& os, const InstructionSequence& code);
+
+struct PrintableInstructionSequence {
+ const RegisterConfiguration* register_configuration_;
+ const InstructionSequence* sequence_;
+};
+
+
+std::ostream& operator<<(std::ostream& os,
+ const PrintableInstructionSequence& code);
} // namespace compiler
} // namespace internal
diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc
index dbaa293..b363d3d 100644
--- a/src/compiler/js-builtin-reducer.cc
+++ b/src/compiler/js-builtin-reducer.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "src/compiler/diamond.h"
#include "src/compiler/graph-inl.h"
#include "src/compiler/js-builtin-reducer.h"
#include "src/compiler/node-matchers.h"
@@ -106,17 +107,10 @@
// Math.abs(a:number) -> (a > 0 ? a : 0 - a)
Node* value = r.left();
Node* zero = jsgraph()->ZeroConstant();
- Node* control = graph()->start();
- Node* tag = graph()->NewNode(simplified()->NumberLessThan(), zero, value);
-
- Node* branch = graph()->NewNode(common()->Branch(), tag, control);
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-
+ Node* cmp = graph()->NewNode(simplified()->NumberLessThan(), zero, value);
+ Diamond d(graph(), common(), cmp);
Node* neg = graph()->NewNode(simplified()->NumberSubtract(), zero, value);
- value = graph()->NewNode(common()->Phi(kMachNone, 2), value, neg, merge);
- return Replace(value);
+ return Replace(d.Phi(kMachNone, value, neg));
}
return NoChange();
}
@@ -150,15 +144,9 @@
Node* value = r.GetJSCallInput(0);
for (int i = 1; i < r.GetJSCallArity(); i++) {
Node* p = r.GetJSCallInput(i);
- Node* control = graph()->start();
- Node* tag = graph()->NewNode(simplified()->NumberLessThan(), value, p);
-
- Node* branch = graph()->NewNode(common()->Branch(), tag, control);
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-
- value = graph()->NewNode(common()->Phi(kMachNone, 2), p, value, merge);
+ Node* cmp = graph()->NewNode(simplified()->NumberLessThan(), value, p);
+ Diamond d(graph(), common(), cmp);
+ value = d.Phi(kMachNone, p, value);
}
return Replace(value);
}
diff --git a/src/compiler/js-intrinsic-builder.cc b/src/compiler/js-intrinsic-builder.cc
index 4d8f607..d4c0dcf 100644
--- a/src/compiler/js-intrinsic-builder.cc
+++ b/src/compiler/js-intrinsic-builder.cc
@@ -4,6 +4,7 @@
#include "src/compiler/access-builder.h"
#include "src/compiler/common-operator.h"
+#include "src/compiler/diamond.h"
#include "src/compiler/generic-node-inl.h"
#include "src/compiler/js-intrinsic-builder.h"
#include "src/compiler/js-operator.h"
@@ -68,29 +69,23 @@
SimplifiedOperatorBuilder simplified(jsgraph_->zone());
Node* is_smi = graph()->NewNode(simplified.ObjectIsSmi(), object);
- Node* branch = graph()->NewNode(common()->Branch(), is_smi, graph()->start());
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+ Diamond d(graph(), common(), is_smi);
Node* map = graph()->NewNode(simplified.LoadField(AccessBuilder::ForMap()),
- object, effect, if_false);
+ object, effect, d.if_false);
Node* instance_type = graph()->NewNode(
simplified.LoadField(AccessBuilder::ForMapInstanceType()), map, map,
- if_false);
+ d.if_false);
Node* has_map_type =
graph()->NewNode(jsgraph_->machine()->Word32Equal(), instance_type,
jsgraph_->Int32Constant(map_type));
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+ Node* phi = d.Phi(static_cast<MachineType>(kTypeBool | kRepTagged),
+ jsgraph_->FalseConstant(), has_map_type);
- Node* phi =
- graph()->NewNode(common()->Phi((MachineType)(kTypeBool | kRepTagged), 2),
- jsgraph_->FalseConstant(), has_map_type, merge);
-
- Node* ephi =
- graph()->NewNode(common()->EffectPhi(2), effect, instance_type, merge);
+ Node* ephi = d.EffectPhi(effect, instance_type);
return ResultAndEffect(phi, ephi);
}
@@ -112,44 +107,32 @@
SimplifiedOperatorBuilder simplified(jsgraph_->zone());
Node* is_smi = graph()->NewNode(simplified.ObjectIsSmi(), object);
- Node* branch = graph()->NewNode(common()->Branch(), is_smi, graph()->start());
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+
+ Diamond if_is_smi(graph(), common(), is_smi);
Node* map = graph()->NewNode(simplified.LoadField(AccessBuilder::ForMap()),
- object, effect, if_false);
+ object, effect, if_is_smi.if_false);
Node* instance_type = graph()->NewNode(
simplified.LoadField(AccessBuilder::ForMapInstanceType()), map, map,
- if_false);
+ if_is_smi.if_false);
Node* is_value =
graph()->NewNode(jsgraph_->machine()->Word32Equal(), instance_type,
jsgraph_->Constant(JS_VALUE_TYPE));
- Node* branch_is_value =
- graph()->NewNode(common()->Branch(), is_value, if_false);
- Node* is_value_true = graph()->NewNode(common()->IfTrue(), branch_is_value);
- Node* is_value_false = graph()->NewNode(common()->IfFalse(), branch_is_value);
+ Diamond if_is_value(graph(), common(), is_value);
+ if_is_value.Nest(if_is_smi, false);
Node* value =
graph()->NewNode(simplified.LoadField(AccessBuilder::ForValue()), object,
- instance_type, is_value_true);
+ instance_type, if_is_value.if_true);
- Node* merge_is_value =
- graph()->NewNode(common()->Merge(2), is_value_true, is_value_false);
+ Node* phi_is_value = if_is_value.Phi(kTypeAny, value, object);
- Node* phi_is_value = graph()->NewNode(common()->Phi((MachineType)kTypeAny, 2),
- value, object, merge_is_value);
+ Node* phi = if_is_smi.Phi(kTypeAny, object, phi_is_value);
-
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, merge_is_value);
-
- Node* phi = graph()->NewNode(common()->Phi((MachineType)kTypeAny, 2), object,
- phi_is_value, merge);
-
- Node* ephi =
- graph()->NewNode(common()->EffectPhi(2), effect, instance_type, merge);
+ Node* ephi = if_is_smi.EffectPhi(effect, instance_type);
return ResultAndEffect(phi, ephi);
}
diff --git a/src/compiler/machine-operator-reducer.cc b/src/compiler/machine-operator-reducer.cc
index f51125a..d1a275d 100644
--- a/src/compiler/machine-operator-reducer.cc
+++ b/src/compiler/machine-operator-reducer.cc
@@ -7,6 +7,7 @@
#include "src/base/bits.h"
#include "src/base/division-by-constant.h"
#include "src/codegen.h"
+#include "src/compiler/diamond.h"
#include "src/compiler/generic-node-inl.h"
#include "src/compiler/graph.h"
#include "src/compiler/js-graph.h"
@@ -640,22 +641,10 @@
Node* check =
graph()->NewNode(machine()->Int32LessThan(), dividend, zero);
- Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
- check, graph()->start());
-
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+ Diamond d(graph(), common(), check, BranchHint::kFalse);
Node* neg = Int32Sub(zero, Word32And(Int32Sub(zero, dividend), mask));
-
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* pos = Word32And(dividend, mask);
-
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-
- DCHECK_EQ(3, node->InputCount());
- node->set_op(common()->Phi(kMachInt32, 2));
- node->ReplaceInput(0, neg);
- node->ReplaceInput(1, pos);
- node->ReplaceInput(2, merge);
+ d.OverwriteWithPhi(node, kMachInt32, neg, pos);
} else {
Node* quotient = Int32Div(dividend, divisor);
node->set_op(machine()->Int32Sub());
diff --git a/src/compiler/mips/code-generator-mips.cc b/src/compiler/mips/code-generator-mips.cc
index 2a07940..1c6688e 100644
--- a/src/compiler/mips/code-generator-mips.cc
+++ b/src/compiler/mips/code-generator-mips.cc
@@ -240,11 +240,10 @@
__ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
break;
case kMipsTst:
- // Psuedo-instruction used for tst/branch.
- __ And(kCompareReg, i.InputRegister(0), i.InputOperand(1));
+ // Pseudo-instruction used for tst/branch. No opcode emitted here.
break;
case kMipsCmp:
- // Psuedo-instruction used for cmp/branch. No opcode emitted here.
+ // Pseudo-instruction used for cmp/branch. No opcode emitted here.
break;
case kMipsMov:
// TODO(plind): Should we combine mov/li like this, or use separate instr?
@@ -418,7 +417,6 @@
// not separated by other instructions.
if (instr->arch_opcode() == kMipsTst) {
- // The kMipsTst psuedo-instruction emits And to 'kCompareReg' register.
switch (condition) {
case kNotEqual:
cc = ne;
@@ -430,7 +428,8 @@
UNSUPPORTED_COND(kMipsTst, condition);
break;
}
- __ Branch(tlabel, cc, kCompareReg, Operand(zero_reg));
+ __ And(at, i.InputRegister(0), i.InputOperand(1));
+ __ Branch(tlabel, cc, at, Operand(zero_reg));
} else if (instr->arch_opcode() == kMipsAddOvf ||
instr->arch_opcode() == kMipsSubOvf) {
@@ -557,7 +556,6 @@
// TODO(plind): Add CHECK() to ensure that test/cmp and this branch were
// not separated by other instructions.
if (instr->arch_opcode() == kMipsTst) {
- // The kMipsTst psuedo-instruction emits And to 'kCompareReg' register.
switch (condition) {
case kNotEqual:
cc = ne;
@@ -569,7 +567,8 @@
UNSUPPORTED_COND(kMipsTst, condition);
break;
}
- __ Branch(USE_DELAY_SLOT, &done, cc, kCompareReg, Operand(zero_reg));
+ __ And(at, i.InputRegister(0), i.InputOperand(1));
+ __ Branch(USE_DELAY_SLOT, &done, cc, at, Operand(zero_reg));
__ li(result, Operand(1)); // In delay slot.
} else if (instr->arch_opcode() == kMipsAddOvf ||
diff --git a/src/compiler/mips/instruction-selector-mips.cc b/src/compiler/mips/instruction-selector-mips.cc
index f5a79ec..13df133 100644
--- a/src/compiler/mips/instruction-selector-mips.cc
+++ b/src/compiler/mips/instruction-selector-mips.cc
@@ -541,70 +541,114 @@
VisitWordCompare(selector, node, kMipsCmp, cont, false);
}
-
-void VisitWordTest(InstructionSelector* selector, Node* node,
- FlagsContinuation* cont) {
- MipsOperandGenerator g(selector);
- // kMipsTst is a pseudo-instruction to do logical 'and' and leave the result
- // in a dedicated tmp register.
- VisitCompare(selector, kMipsTst, g.UseRegister(node), g.UseRegister(node),
- cont);
-}
-
} // namespace
+// Shared routine for word comparisons against zero.
+void VisitWordCompareZero(InstructionSelector* selector, Node* user,
+ Node* value, FlagsContinuation* cont) {
+ while (selector->CanCover(user, value)) {
+ switch (value->opcode()) {
+ case IrOpcode::kWord32Equal: {
+ // Combine with comparisons against 0 by simply inverting the
+ // continuation.
+ Int32BinopMatcher m(value);
+ if (m.right().Is(0)) {
+ user = value;
+ value = m.left().node();
+ cont->Negate();
+ continue;
+ }
+ cont->OverwriteAndNegateIfEqual(kEqual);
+ return VisitWordCompare(selector, value, cont);
+ }
+ case IrOpcode::kInt32LessThan:
+ cont->OverwriteAndNegateIfEqual(kSignedLessThan);
+ return VisitWordCompare(selector, value, cont);
+ case IrOpcode::kInt32LessThanOrEqual:
+ cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
+ return VisitWordCompare(selector, value, cont);
+ case IrOpcode::kUint32LessThan:
+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
+ return VisitWordCompare(selector, value, cont);
+ case IrOpcode::kUint32LessThanOrEqual:
+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
+ return VisitWordCompare(selector, value, cont);
+ case IrOpcode::kFloat64Equal:
+ cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
+ return VisitFloat64Compare(selector, value, cont);
+ case IrOpcode::kFloat64LessThan:
+ cont->OverwriteAndNegateIfEqual(kUnorderedLessThan);
+ return VisitFloat64Compare(selector, value, cont);
+ case IrOpcode::kFloat64LessThanOrEqual:
+ cont->OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual);
+ return VisitFloat64Compare(selector, value, cont);
+ case IrOpcode::kProjection:
+ // Check if this is the overflow output projection of an
+ // <Operation>WithOverflow node.
+ if (OpParameter<size_t>(value) == 1u) {
+ // We cannot combine the <Operation>WithOverflow with this branch
+ // unless the 0th projection (the use of the actual value of the
+ // <Operation> is either NULL, which means there's no use of the
+ // actual value, or was already defined, which means it is scheduled
+ // *AFTER* this branch).
+ Node* const node = value->InputAt(0);
+ Node* const result = node->FindProjection(0);
+ if (!result || selector->IsDefined(result)) {
+ switch (node->opcode()) {
+ case IrOpcode::kInt32AddWithOverflow:
+ cont->OverwriteAndNegateIfEqual(kOverflow);
+ return VisitBinop(selector, node, kMipsAddOvf, cont);
+ case IrOpcode::kInt32SubWithOverflow:
+ cont->OverwriteAndNegateIfEqual(kOverflow);
+ return VisitBinop(selector, node, kMipsSubOvf, cont);
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ case IrOpcode::kWord32And:
+ return VisitWordCompare(selector, value, kMipsTst, cont, true);
+ default:
+ break;
+ }
+ break;
+ }
+
+ // Continuation could not be combined with a compare, emit compare against 0.
+ MipsOperandGenerator g(selector);
+ InstructionCode const opcode = cont->Encode(kMipsCmp);
+ InstructionOperand* const value_operand = g.UseRegister(value);
+ if (cont->IsBranch()) {
+ selector->Emit(opcode, nullptr, value_operand, g.TempImmediate(0),
+ g.Label(cont->true_block()),
+ g.Label(cont->false_block()))->MarkAsControl();
+ } else {
+ selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
+ g.TempImmediate(0));
+ }
+}
+
+
void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
BasicBlock* fbranch) {
- MipsOperandGenerator g(this);
- Node* user = branch;
- Node* value = branch->InputAt(0);
-
FlagsContinuation cont(kNotEqual, tbranch, fbranch);
-
// If we can fall through to the true block, invert the branch.
if (IsNextInAssemblyOrder(tbranch)) {
cont.Negate();
cont.SwapBlocks();
}
-
- // Try to combine with comparisons against 0 by simply inverting the branch.
- while (CanCover(user, value) && value->opcode() == IrOpcode::kWord32Equal) {
- Int32BinopMatcher m(value);
- if (m.right().Is(0)) {
- user = value;
- value = m.left().node();
- cont.Negate();
- } else {
- break;
- }
- }
-
- // Try to combine the branch with a comparison.
- if (CanCover(user, value)) {
- switch (value->opcode()) {
- case IrOpcode::kWord32And:
- // TODO(plind): understand the significance of 'IR and' special case.
- return VisitWordCompare(this, value, kMipsTst, &cont, true);
- default:
- break;
- }
- }
-
- // Branch could not be combined with a compare, emit compare against 0.
- return VisitWordTest(this, value, &cont);
+ VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
}
void InstructionSelector::VisitWord32Equal(Node* const node) {
- Node* const user = node;
FlagsContinuation cont(kEqual, node);
- Int32BinopMatcher m(user);
+ Int32BinopMatcher m(node);
if (m.right().Is(0)) {
- Node* const value = m.left().node();
- return VisitWordTest(this, value, &cont);
+ return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
}
-
VisitWordCompare(this, node, &cont);
}
diff --git a/src/compiler/pipeline.cc b/src/compiler/pipeline.cc
index 5c384c2..f2571e3 100644
--- a/src/compiler/pipeline.cc
+++ b/src/compiler/pipeline.cc
@@ -558,8 +558,10 @@
if (FLAG_trace_turbo) {
OFStream os(stdout);
+ PrintableInstructionSequence printable = {
+ RegisterConfiguration::ArchDefault(), &sequence};
os << "----- Instruction sequence before register allocation -----\n"
- << sequence;
+ << printable;
TurboCfgFile tcf(isolate());
tcf << AsC1V("CodeGen", data->schedule(), data->source_positions(),
&sequence);
@@ -587,7 +589,7 @@
#endif
- RegisterAllocator allocator(RegisterAllocator::PlatformConfig(),
+ RegisterAllocator allocator(RegisterConfiguration::ArchDefault(),
zone_scope.zone(), &frame, &sequence,
debug_name.get());
if (!allocator.Allocate(data->pipeline_statistics())) {
@@ -602,8 +604,10 @@
if (FLAG_trace_turbo) {
OFStream os(stdout);
+ PrintableInstructionSequence printable = {
+ RegisterConfiguration::ArchDefault(), &sequence};
os << "----- Instruction sequence after register allocation -----\n"
- << sequence;
+ << printable;
}
if (data->pipeline_statistics() != NULL) {
diff --git a/src/compiler/register-allocator.cc b/src/compiler/register-allocator.cc
index ced88a8..7a82768 100644
--- a/src/compiler/register-allocator.cc
+++ b/src/compiler/register-allocator.cc
@@ -5,7 +5,6 @@
#include "src/compiler/linkage.h"
#include "src/compiler/pipeline-statistics.h"
#include "src/compiler/register-allocator.h"
-#include "src/macro-assembler.h" // TODO(dcarney): remove this.
#include "src/string-stream.h"
namespace v8 {
@@ -507,22 +506,9 @@
}
-RegisterAllocator::Config RegisterAllocator::PlatformConfig() {
- DCHECK_EQ(Register::kMaxNumAllocatableRegisters,
- Register::NumAllocatableRegisters());
- Config config;
- config.num_general_registers_ = Register::kMaxNumAllocatableRegisters;
- config.num_double_registers_ = DoubleRegister::kMaxNumAllocatableRegisters;
- config.num_aliased_double_registers_ =
- DoubleRegister::NumAllocatableAliasedRegisters();
- config.GeneralRegisterName = Register::AllocationIndexToString;
- config.DoubleRegisterName = DoubleRegister::AllocationIndexToString;
- return config;
-}
-
-
-RegisterAllocator::RegisterAllocator(const Config& config, Zone* local_zone,
- Frame* frame, InstructionSequence* code,
+RegisterAllocator::RegisterAllocator(const RegisterConfiguration* config,
+ Zone* local_zone, Frame* frame,
+ InstructionSequence* code,
const char* debug_name)
: zone_(local_zone),
frame_(frame),
@@ -531,8 +517,8 @@
config_(config),
live_in_sets_(code->InstructionBlockCount(), zone()),
live_ranges_(code->VirtualRegisterCount() * 2, zone()),
- fixed_live_ranges_(this->config().num_general_registers_, NULL, zone()),
- fixed_double_live_ranges_(this->config().num_double_registers_, NULL,
+ fixed_live_ranges_(this->config()->num_general_registers(), NULL, zone()),
+ fixed_double_live_ranges_(this->config()->num_double_registers(), NULL,
zone()),
unhandled_live_ranges_(code->VirtualRegisterCount() * 2, zone()),
active_live_ranges_(8, zone()),
@@ -541,12 +527,14 @@
mode_(UNALLOCATED_REGISTERS),
num_registers_(-1),
allocation_ok_(true) {
- DCHECK(this->config().num_general_registers_ <= kMaxGeneralRegisters);
- DCHECK(this->config().num_double_registers_ <= kMaxDoubleRegisters);
+ DCHECK(this->config()->num_general_registers() <=
+ RegisterConfiguration::kMaxGeneralRegisters);
+ DCHECK(this->config()->num_double_registers() <=
+ RegisterConfiguration::kMaxDoubleRegisters);
// TryAllocateFreeReg and AllocateBlockedReg assume this
// when allocating local arrays.
- DCHECK(this->config().num_double_registers_ >=
- this->config().num_general_registers_);
+ DCHECK(this->config()->num_double_registers() >=
+ this->config()->num_general_registers());
}
@@ -603,7 +591,7 @@
int RegisterAllocator::FixedDoubleLiveRangeID(int index) {
- return -index - 1 - config().num_general_registers_;
+ return -index - 1 - config()->num_general_registers();
}
@@ -635,7 +623,7 @@
LiveRange* RegisterAllocator::FixedLiveRangeFor(int index) {
- DCHECK(index < config().num_general_registers_);
+ DCHECK(index < config()->num_general_registers());
LiveRange* result = fixed_live_ranges_[index];
if (result == NULL) {
// TODO(titzer): add a utility method to allocate a new LiveRange:
@@ -653,7 +641,7 @@
LiveRange* RegisterAllocator::FixedDoubleLiveRangeFor(int index) {
- DCHECK(index < config().num_aliased_double_registers_);
+ DCHECK(index < config()->num_aliased_double_registers());
LiveRange* result = fixed_double_live_ranges_[index];
if (result == NULL) {
result = new (zone()) LiveRange(FixedDoubleLiveRangeID(index), code_zone());
@@ -1031,7 +1019,7 @@
}
if (instr->ClobbersRegisters()) {
- for (int i = 0; i < config().num_general_registers_; ++i) {
+ for (int i = 0; i < config()->num_general_registers(); ++i) {
if (!IsOutputRegisterOf(instr, i)) {
LiveRange* range = FixedLiveRangeFor(i);
range->AddUseInterval(curr_position, curr_position.InstructionEnd(),
@@ -1041,7 +1029,7 @@
}
if (instr->ClobbersDoubleRegisters()) {
- for (int i = 0; i < config().num_aliased_double_registers_; ++i) {
+ for (int i = 0; i < config()->num_aliased_double_registers(); ++i) {
if (!IsOutputDoubleRegisterOf(instr, i)) {
LiveRange* range = FixedDoubleLiveRangeFor(i);
range->AddUseInterval(curr_position, curr_position.InstructionEnd(),
@@ -1126,10 +1114,10 @@
bool RegisterAllocator::Allocate(PipelineStatistics* stats) {
- assigned_registers_ =
- new (code_zone()) BitVector(config().num_general_registers_, code_zone());
+ assigned_registers_ = new (code_zone())
+ BitVector(config()->num_general_registers(), code_zone());
assigned_double_registers_ = new (code_zone())
- BitVector(config().num_aliased_double_registers_, code_zone());
+ BitVector(config()->num_aliased_double_registers(), code_zone());
{
PhaseScope phase_scope(stats, "meet register constraints");
MeetRegisterConstraints();
@@ -1535,14 +1523,14 @@
void RegisterAllocator::AllocateGeneralRegisters() {
- num_registers_ = config().num_general_registers_;
+ num_registers_ = config()->num_general_registers();
mode_ = GENERAL_REGISTERS;
AllocateRegisters();
}
void RegisterAllocator::AllocateDoubleRegisters() {
- num_registers_ = config().num_aliased_double_registers_;
+ num_registers_ = config()->num_aliased_double_registers();
mode_ = DOUBLE_REGISTERS;
AllocateRegisters();
}
@@ -1566,7 +1554,7 @@
DCHECK(inactive_live_ranges_.is_empty());
if (mode_ == DOUBLE_REGISTERS) {
- for (int i = 0; i < config().num_aliased_double_registers_; ++i) {
+ for (int i = 0; i < config()->num_aliased_double_registers(); ++i) {
LiveRange* current = fixed_double_live_ranges_.at(i);
if (current != NULL) {
AddToInactive(current);
@@ -1658,9 +1646,9 @@
const char* RegisterAllocator::RegisterName(int allocation_index) {
if (mode_ == GENERAL_REGISTERS) {
- return config().GeneralRegisterName(allocation_index);
+ return config()->general_register_name(allocation_index);
} else {
- return config().DoubleRegisterName(allocation_index);
+ return config()->double_register_name(allocation_index);
}
}
@@ -1805,7 +1793,7 @@
bool RegisterAllocator::TryAllocateFreeReg(LiveRange* current) {
- LifetimePosition free_until_pos[kMaxDoubleRegisters];
+ LifetimePosition free_until_pos[RegisterConfiguration::kMaxDoubleRegisters];
for (int i = 0; i < num_registers_; i++) {
free_until_pos[i] = LifetimePosition::MaxPosition();
@@ -1888,8 +1876,8 @@
return;
}
- LifetimePosition use_pos[kMaxGeneralRegisters];
- LifetimePosition block_pos[kMaxDoubleRegisters];
+ LifetimePosition use_pos[RegisterConfiguration::kMaxGeneralRegisters];
+ LifetimePosition block_pos[RegisterConfiguration::kMaxDoubleRegisters];
for (int i = 0; i < num_registers_; i++) {
use_pos[i] = block_pos[i] = LifetimePosition::MaxPosition();
diff --git a/src/compiler/register-allocator.h b/src/compiler/register-allocator.h
index db30f96..b167437 100644
--- a/src/compiler/register-allocator.h
+++ b/src/compiler/register-allocator.h
@@ -319,19 +319,9 @@
class RegisterAllocator FINAL {
public:
- class Config {
- public:
- int num_general_registers_;
- int num_double_registers_;
- int num_aliased_double_registers_;
- const char* (*GeneralRegisterName)(int allocation_index);
- const char* (*DoubleRegisterName)(int allocation_index);
- };
-
- static Config PlatformConfig();
-
- explicit RegisterAllocator(const Config& config, Zone* local_zone,
- Frame* frame, InstructionSequence* code,
+ explicit RegisterAllocator(const RegisterConfiguration* config,
+ Zone* local_zone, Frame* frame,
+ InstructionSequence* code,
const char* debug_name = nullptr);
bool Allocate(PipelineStatistics* stats = NULL);
@@ -502,14 +492,14 @@
Frame* frame() const { return frame_; }
const char* debug_name() const { return debug_name_; }
- const Config& config() const { return config_; }
+ const RegisterConfiguration* config() const { return config_; }
Zone* const zone_;
Frame* const frame_;
InstructionSequence* const code_;
const char* const debug_name_;
- const Config config_;
+ const RegisterConfiguration* config_;
// During liveness analysis keep a mapping from block id to live_in sets
// for blocks already analyzed.
diff --git a/src/compiler/register-configuration.cc b/src/compiler/register-configuration.cc
new file mode 100644
index 0000000..e7d8bbd
--- /dev/null
+++ b/src/compiler/register-configuration.cc
@@ -0,0 +1,68 @@
+// 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.
+
+#include "src/compiler/register-configuration.h"
+#include "src/macro-assembler.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+STATIC_ASSERT(RegisterConfiguration::kMaxGeneralRegisters >=
+ Register::kNumRegisters);
+STATIC_ASSERT(RegisterConfiguration::kMaxDoubleRegisters >=
+ DoubleRegister::kMaxNumRegisters);
+
+class ArchDefaultRegisterConfiguration : public RegisterConfiguration {
+ public:
+ ArchDefaultRegisterConfiguration()
+ : RegisterConfiguration(Register::kMaxNumAllocatableRegisters,
+ DoubleRegister::kMaxNumAllocatableRegisters,
+ DoubleRegister::NumAllocatableAliasedRegisters(),
+ general_register_name_table_,
+ double_register_name_table_) {
+ DCHECK_EQ(Register::kMaxNumAllocatableRegisters,
+ Register::NumAllocatableRegisters());
+ for (int i = 0; i < Register::kMaxNumAllocatableRegisters; ++i) {
+ general_register_name_table_[i] = Register::AllocationIndexToString(i);
+ }
+ for (int i = 0; i < DoubleRegister::kMaxNumAllocatableRegisters; ++i) {
+ double_register_name_table_[i] =
+ DoubleRegister::AllocationIndexToString(i);
+ }
+ }
+
+ const char*
+ general_register_name_table_[Register::kMaxNumAllocatableRegisters];
+ const char*
+ double_register_name_table_[DoubleRegister::kMaxNumAllocatableRegisters];
+};
+
+
+static base::LazyInstance<ArchDefaultRegisterConfiguration>::type
+ kDefaultRegisterConfiguration = LAZY_INSTANCE_INITIALIZER;
+
+} // namepace
+
+
+const RegisterConfiguration* RegisterConfiguration::ArchDefault() {
+ return &kDefaultRegisterConfiguration.Get();
+}
+
+RegisterConfiguration::RegisterConfiguration(
+ int num_general_registers, int num_double_registers,
+ int num_aliased_double_registers, const char* const* general_register_names,
+ const char* const* double_register_names)
+ : num_general_registers_(num_general_registers),
+ num_double_registers_(num_double_registers),
+ num_aliased_double_registers_(num_aliased_double_registers),
+ general_register_names_(general_register_names),
+ double_register_names_(double_register_names) {}
+
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
diff --git a/src/compiler/register-configuration.h b/src/compiler/register-configuration.h
new file mode 100644
index 0000000..8178ba2
--- /dev/null
+++ b/src/compiler/register-configuration.h
@@ -0,0 +1,56 @@
+// 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.
+
+#ifndef V8_COMPILER_REGISTER_CONFIGURATION_H_
+#define V8_COMPILER_REGISTER_CONFIGURATION_H_
+
+#include "src/v8.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// An architecture independent representation of the sets of registers available
+// for instruction creation.
+class RegisterConfiguration {
+ public:
+ // Architecture independent maxes.
+ static const int kMaxGeneralRegisters = 32;
+ static const int kMaxDoubleRegisters = 32;
+
+ static const RegisterConfiguration* ArchDefault();
+
+ RegisterConfiguration(int num_general_registers, int num_double_registers,
+ int num_aliased_double_registers,
+ const char* const* general_register_name,
+ const char* const* double_register_name);
+
+ int num_general_registers() const { return num_general_registers_; }
+ int num_double_registers() const { return num_double_registers_; }
+ int num_aliased_double_registers() const {
+ return num_aliased_double_registers_;
+ }
+
+ const char* general_register_name(int offset) const {
+ DCHECK(offset >= 0 && offset < kMaxGeneralRegisters);
+ return general_register_names_[offset];
+ }
+ const char* double_register_name(int offset) const {
+ DCHECK(offset >= 0 && offset < kMaxDoubleRegisters);
+ return double_register_names_[offset];
+ }
+
+ private:
+ const int num_general_registers_;
+ const int num_double_registers_;
+ const int num_aliased_double_registers_;
+ const char* const* general_register_names_;
+ const char* const* double_register_names_;
+};
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
+
+#endif // V8_COMPILER_REGISTER_CONFIGURATION_H_
diff --git a/src/compiler/select-lowering.cc b/src/compiler/select-lowering.cc
index 4e553d1..2e51d72 100644
--- a/src/compiler/select-lowering.cc
+++ b/src/compiler/select-lowering.cc
@@ -5,6 +5,7 @@
#include "src/compiler/select-lowering.h"
#include "src/compiler/common-operator.h"
+#include "src/compiler/diamond.h"
#include "src/compiler/generic-node-inl.h"
#include "src/compiler/graph.h"
@@ -26,17 +27,13 @@
SelectParameters const p = SelectParametersOf(node->op());
Node* const cond = node->InputAt(0);
- Node* const control = graph()->start();
// Check if we already have a diamond for this condition.
auto i = merges_.find(cond);
if (i == merges_.end()) {
// Create a new diamond for this condition and remember its merge node.
- Node* branch = graph()->NewNode(common()->Branch(p.hint()), cond, control);
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
- i = merges_.insert(std::make_pair(cond, merge)).first;
+ Diamond d(graph(), common(), cond, p.hint());
+ i = merges_.insert(std::make_pair(cond, d.merge)).first;
}
DCHECK_EQ(cond, i->first);
diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc
index 3069865..c50b338 100644
--- a/src/compiler/simplified-lowering.cc
+++ b/src/compiler/simplified-lowering.cc
@@ -9,6 +9,7 @@
#include "src/base/bits.h"
#include "src/code-factory.h"
#include "src/compiler/common-operator.h"
+#include "src/compiler/diamond.h"
#include "src/compiler/graph-inl.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties-inl.h"
@@ -632,7 +633,7 @@
if (lower()) DeferReplacement(node, lowering->Int32Div(node));
break;
}
- if (CanLowerToUint32Binop(node, use)) {
+ if (BothInputsAre(node, Type::Unsigned32()) && !CanObserveNaN(use)) {
// => unsigned Uint32Div
VisitUint32Binop(node);
if (lower()) DeferReplacement(node, lowering->Uint32Div(node));
@@ -1172,11 +1173,9 @@
node->ReplaceInput(2, effect);
node->ReplaceInput(3, graph()->start());
} else {
- Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
- check, graph()->start());
+ Diamond d(graph(), common(), check, BranchHint::kTrue);
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* load = graph()->NewNode(op, base, index, effect, if_true);
+ Node* load = graph()->NewNode(op, base, index, effect, d.if_true);
Node* result = load;
if (output_type & kRepTagged) {
// TODO(turbofan): This is ugly as hell!
@@ -1187,7 +1186,6 @@
changer.GetTaggedRepresentationFor(result, access.machine_type);
}
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
Node* undefined;
if (output_type & kRepTagged) {
DCHECK_EQ(0, access.machine_type & kRepTagged);
@@ -1202,23 +1200,10 @@
undefined = jsgraph()->Int32Constant(0);
}
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
- Node* phi = graph()->NewNode(common()->EffectPhi(2), load, effect, merge);
-
// Replace effect uses of node with the effect phi.
- for (UseIter i = node->uses().begin(); i != node->uses().end();) {
- if (NodeProperties::IsEffectEdge(i.edge())) {
- i = i.UpdateToAndIncrement(phi);
- } else {
- ++i;
- }
- }
+ NodeProperties::ReplaceWithValue(node, node, d.EffectPhi(load, effect));
- node->set_op(common()->Phi(output_type, 2));
- node->ReplaceInput(0, result);
- node->ReplaceInput(1, undefined);
- node->ReplaceInput(2, merge);
- node->TrimInputCount(3);
+ d.OverwriteWithPhi(node, output_type, result, undefined);
}
}
}
@@ -1257,21 +1242,10 @@
node->ReplaceInput(1, select);
node->RemoveInput(2);
} else {
- Node* branch =
- graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
-
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* store = graph()->NewNode(op, base, index, value, effect, if_true);
-
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
-
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-
- node->set_op(common()->EffectPhi(2));
- node->ReplaceInput(0, store);
- node->ReplaceInput(1, effect);
- node->ReplaceInput(2, merge);
- node->TrimInputCount(3);
+ Diamond d(graph(), common(), check, BranchHint::kTrue);
+ d.Chain(control);
+ Node* store = graph()->NewNode(op, base, index, value, effect, d.if_true);
+ d.OverwriteWithEffectPhi(node, store, effect);
}
}
}
@@ -1325,34 +1299,20 @@
return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
}
- Node* check0 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
- Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse), check0,
- graph()->start());
+ Diamond if_zero(graph(), common(),
+ graph()->NewNode(machine()->Word32Equal(), rhs, zero),
+ BranchHint::kFalse);
- Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
- Node* true0 = zero;
+ Diamond if_minus_one(graph(), common(),
+ graph()->NewNode(machine()->Word32Equal(), rhs,
+ jsgraph()->Int32Constant(-1)),
+ BranchHint::kFalse);
+ if_minus_one.Nest(if_zero, false);
+ Node* sub = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
+ Node* div =
+ graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_minus_one.if_false);
- Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
- Node* false0 = nullptr;
- {
- Node* check1 = graph()->NewNode(machine()->Word32Equal(), rhs,
- jsgraph()->Int32Constant(-1));
- Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
- check1, if_false0);
-
- Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
- Node* true1 = graph()->NewNode(machine()->Int32Sub(), zero, lhs);
-
- Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
- Node* false1 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_false1);
-
- if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
- false0 = graph()->NewNode(common()->Phi(kMachInt32, 2), true1, false1,
- if_false0);
- }
-
- Node* merge0 = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
- return graph()->NewNode(common()->Phi(kMachInt32, 2), true0, false0, merge0);
+ return if_zero.Phi(kMachInt32, zero, if_minus_one.Phi(kMachInt32, sub, div));
}
@@ -1368,34 +1328,19 @@
return graph()->NewNode(machine()->Int32Mod(), lhs, rhs, graph()->start());
}
- Node* check0 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
- Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse), check0,
- graph()->start());
+ Diamond if_zero(graph(), common(),
+ graph()->NewNode(machine()->Word32Equal(), rhs, zero),
+ BranchHint::kFalse);
- Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
- Node* true0 = zero;
+ Diamond if_minus_one(graph(), common(),
+ graph()->NewNode(machine()->Word32Equal(), rhs,
+ jsgraph()->Int32Constant(-1)),
+ BranchHint::kFalse);
+ if_minus_one.Nest(if_zero, false);
+ Node* mod =
+ graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_minus_one.if_false);
- Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
- Node* false0 = nullptr;
- {
- Node* check1 = graph()->NewNode(machine()->Word32Equal(), rhs,
- jsgraph()->Int32Constant(-1));
- Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
- check1, if_false0);
-
- Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
- Node* true1 = zero;
-
- Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
- Node* false1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_false1);
-
- if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
- false0 = graph()->NewNode(common()->Phi(kMachInt32, 2), true1, false1,
- if_false0);
- }
-
- Node* merge0 = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
- return graph()->NewNode(common()->Phi(kMachInt32, 2), true0, false0, merge0);
+ return if_zero.Phi(kMachInt32, zero, if_minus_one.Phi(kMachInt32, zero, mod));
}
@@ -1412,17 +1357,9 @@
}
Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
- Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse), check,
- graph()->start());
-
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* vtrue = zero;
-
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
- Node* vfalse = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, if_false);
-
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
- return graph()->NewNode(common()->Phi(kMachUint32, 2), vtrue, vfalse, merge);
+ Diamond d(graph(), common(), check, BranchHint::kFalse);
+ Node* div = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, d.if_false);
+ return d.Phi(kMachUint32, zero, div);
}
@@ -1439,17 +1376,9 @@
}
Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
- Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse), check,
- graph()->start());
-
- Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* vtrue = zero;
-
- Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
- Node* vfalse = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, if_false);
-
- Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
- return graph()->NewNode(common()->Phi(kMachUint32, 2), vtrue, vfalse, merge);
+ Diamond d(graph(), common(), check, BranchHint::kFalse);
+ Node* mod = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, d.if_false);
+ return d.Phi(kMachUint32, zero, mod);
}
diff --git a/src/factory.cc b/src/factory.cc
index 5713f73..72974a3 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -1722,6 +1722,22 @@
}
+Handle<JSMapIterator> Factory::NewJSMapIterator() {
+ Handle<Map> map(isolate()->native_context()->map_iterator_map());
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->AllocateJSObjectFromMap(*map),
+ JSMapIterator);
+}
+
+
+Handle<JSSetIterator> Factory::NewJSSetIterator() {
+ Handle<Map> map(isolate()->native_context()->set_iterator_map());
+ CALL_HEAP_FUNCTION(isolate(),
+ isolate()->heap()->AllocateJSObjectFromMap(*map),
+ JSSetIterator);
+}
+
+
namespace {
ElementsKind GetExternalArrayElementsKind(ExternalArrayType type) {
diff --git a/src/factory.h b/src/factory.h
index e9972cc..9f9813c 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -445,6 +445,10 @@
Handle<JSDataView> NewJSDataView(Handle<JSArrayBuffer> buffer,
size_t byte_offset, size_t byte_length);
+ // TODO(aandrey): Maybe these should take table, index and kind arguments.
+ Handle<JSMapIterator> NewJSMapIterator();
+ Handle<JSSetIterator> NewJSSetIterator();
+
// Allocates a Harmony proxy.
Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index d161d55..690e5c7 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -155,54 +155,65 @@
// Flags for language modes and experimental language features.
DEFINE_BOOL(use_strict, false, "enforce strict mode")
-DEFINE_BOOL(es_staging, false, "enable upcoming ES6+ features")
-DEFINE_BOOL(harmony, false, "enable all harmony features (except proxies)")
+DEFINE_BOOL(es_staging, false, "enable all completed harmony features")
+DEFINE_BOOL(harmony, false, "enable all completed harmony features")
DEFINE_IMPLICATION(harmony, es_staging)
+// TODO(rossberg): activate once we have staged scoping:
+// DEFINE_IMPLICATION(es_staging, harmony)
-#define HARMONY_FEATURES(V) \
+// Features that are still work in progress (behind individual flags).
+#define HARMONY_INPROGRESS(V) \
V(harmony_scoping, "harmony block scoping") \
V(harmony_modules, "harmony modules (implies block scoping)") \
- V(harmony_arrays, "harmony arrays") \
- V(harmony_classes, "harmony classes") \
+ V(harmony_arrays, "harmony array methods") \
+ V(harmony_classes, \
+ "harmony classes (implies block scoping & object literal extension)") \
V(harmony_object_literals, "harmony object literal extensions") \
- V(harmony_regexps, "reg-exp related harmony features") \
+ V(harmony_regexps, "harmony regular expression extensions") \
V(harmony_arrow_functions, "harmony arrow functions") \
- V(harmony_tostring, "harmony Symbol.toStringTag")
+ V(harmony_tostring, "harmony toString") \
+ V(harmony_proxies, "harmony proxies")
-#define STAGED_FEATURES(V) \
- V(harmony_strings, "harmony strings") \
- V(harmony_numeric_literals, "harmony numeric literals (0o77, 0b11)")
+// Features that are complete (but still behind --harmony/es-staging flag).
+#define HARMONY_STAGED(V) \
+ V(harmony_strings, "harmony string methods") \
+ V(harmony_numeric_literals, "harmony numeric literals")
-#define SHIPPING_FEATURES(V)
+// Features that are shipping (turned on by default, but internal flag remains).
+#define HARMONY_SHIPPING(V)
-#define FLAG_FEATURES(id, description) \
+// Once a shipping feature has proved stable in the wild, it will be dropped
+// from HARMONY_SHIPPING, all occurrences of the FLAG_ variable are removed,
+// and associated tests are moved from the harmony directory to the appropriate
+// esN directory.
+
+
+#define FLAG_INPROGRESS_FEATURES(id, description) \
+ DEFINE_BOOL(id, false, "enable " #description " (in progress)")
+HARMONY_INPROGRESS(FLAG_INPROGRESS_FEATURES)
+#undef FLAG_INPROGRESS_FEATURES
+
+// TODO(rossberg): temporary, remove once we have staged scoping.
+// After that, --harmony will be synonymous to --es-staging.
+DEFINE_IMPLICATION(harmony, harmony_scoping)
+
+#define FLAG_STAGED_FEATURES(id, description) \
DEFINE_BOOL(id, false, "enable " #description) \
- DEFINE_IMPLICATION(harmony, id)
-
-HARMONY_FEATURES(FLAG_FEATURES)
-STAGED_FEATURES(FLAG_FEATURES)
-#undef FLAG_FEATURES
-
-#define FLAG_STAGED_FEATURES(id, description) DEFINE_IMPLICATION(es_staging, id)
-
-STAGED_FEATURES(FLAG_STAGED_FEATURES)
+ DEFINE_IMPLICATION(es_staging, id)
+HARMONY_STAGED(FLAG_STAGED_FEATURES)
#undef FLAG_STAGED_FEATURES
#define FLAG_SHIPPING_FEATURES(id, description) \
DEFINE_BOOL_READONLY(id, true, "enable " #description)
-
-SHIPPING_FEATURES(FLAG_SHIPPING_FEATURES)
+HARMONY_SHIPPING(FLAG_SHIPPING_FEATURES)
#undef FLAG_SHIPPING_FEATURES
+
// Feature dependencies.
DEFINE_IMPLICATION(harmony_modules, harmony_scoping)
DEFINE_IMPLICATION(harmony_classes, harmony_scoping)
DEFINE_IMPLICATION(harmony_classes, harmony_object_literals)
-DEFINE_BOOL(harmony_proxies, false, "enable harmony proxies")
-// TODO(rossberg): Reenable when problems are sorted out.
-// DEFINE_IMPLICATION(harmony, harmony_proxies)
-
// Flags for experimental implementation features.
DEFINE_BOOL(compiled_keyed_generic_loads, false,
diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc
index 5b19fca..2cefebf 100644
--- a/src/heap/mark-compact.cc
+++ b/src/heap/mark-compact.cc
@@ -456,7 +456,6 @@
void MarkCompactCollector::StartSweeperThreads() {
DCHECK(free_list_old_pointer_space_.get()->IsEmpty());
DCHECK(free_list_old_data_space_.get()->IsEmpty());
- sweeping_in_progress_ = true;
V8::GetCurrentPlatform()->CallOnBackgroundThread(
new SweeperTask(heap(), heap()->old_data_space()),
v8::Platform::kShortRunningTask);
@@ -471,13 +470,15 @@
// If sweeping is not completed or not running at all, we try to complete it
// here.
- if (!IsSweepingCompleted()) {
+ if (FLAG_predictable || !IsSweepingCompleted()) {
SweepInParallel(heap()->paged_space(OLD_DATA_SPACE), 0);
SweepInParallel(heap()->paged_space(OLD_POINTER_SPACE), 0);
}
// Wait twice for both jobs.
- pending_sweeper_jobs_semaphore_.Wait();
- pending_sweeper_jobs_semaphore_.Wait();
+ if (!FLAG_predictable) {
+ pending_sweeper_jobs_semaphore_.Wait();
+ pending_sweeper_jobs_semaphore_.Wait();
+ }
ParallelSweepSpacesComplete();
sweeping_in_progress_ = false;
RefillFreeList(heap()->paged_space(OLD_DATA_SPACE));
@@ -4185,7 +4186,7 @@
SweepSpace(heap()->old_pointer_space(), CONCURRENT_SWEEPING);
SweepSpace(heap()->old_data_space(), CONCURRENT_SWEEPING);
}
-
+ sweeping_in_progress_ = true;
if (!FLAG_predictable) {
StartSweeperThreads();
}
diff --git a/src/heap/spaces.cc b/src/heap/spaces.cc
index 430f31d..2b696ea 100644
--- a/src/heap/spaces.cc
+++ b/src/heap/spaces.cc
@@ -2569,7 +2569,8 @@
intptr_t PagedSpace::SizeOfObjects() {
- DCHECK(heap()->mark_compact_collector()->sweeping_in_progress() ||
+ DCHECK(FLAG_predictable ||
+ heap()->mark_compact_collector()->sweeping_in_progress() ||
(unswept_free_bytes_ == 0));
return Size() - unswept_free_bytes_ - (limit() - top());
}
diff --git a/src/ia32/interface-descriptors-ia32.cc b/src/ia32/interface-descriptors-ia32.cc
index e5096b3..6c77ef8 100644
--- a/src/ia32/interface-descriptors-ia32.cc
+++ b/src/ia32/interface-descriptors-ia32.cc
@@ -155,6 +155,15 @@
}
+void AllocateHeapNumberDescriptor::Initialize(
+ CallInterfaceDescriptorData* data) {
+ // register state
+ // esi -- context
+ Register registers[] = {esi};
+ data->Initialize(arraysize(registers), registers, nullptr);
+}
+
+
void ArrayConstructorConstantArgCountDescriptor::Initialize(
CallInterfaceDescriptorData* data) {
// register state
diff --git a/src/ic/ic.cc b/src/ic/ic.cc
index d0c0edb..a9369ed 100644
--- a/src/ic/ic.cc
+++ b/src/ic/ic.cc
@@ -2688,7 +2688,7 @@
PrototypeIterator iter(isolate, receiver,
PrototypeIterator::START_AT_RECEIVER);
bool found = false;
- while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
+ for (; !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
Handle<Object> current = PrototypeIterator::GetCurrent(iter);
if (current->IsJSObject() &&
Handle<JSObject>::cast(current)->HasNamedInterceptor()) {
diff --git a/src/interface-descriptors.h b/src/interface-descriptors.h
index 3e4f3e7..5d02e84 100644
--- a/src/interface-descriptors.h
+++ b/src/interface-descriptors.h
@@ -33,6 +33,7 @@
V(CallConstruct) \
V(RegExpConstructResult) \
V(TransitionElementsKind) \
+ V(AllocateHeapNumber) \
V(ArrayConstructorConstantArgCount) \
V(ArrayConstructor) \
V(InternalArrayConstructorConstantArgCount) \
@@ -346,6 +347,12 @@
};
+class AllocateHeapNumberDescriptor : public CallInterfaceDescriptor {
+ public:
+ DECLARE_DESCRIPTOR(AllocateHeapNumberDescriptor, CallInterfaceDescriptor)
+};
+
+
class ArrayConstructorConstantArgCountDescriptor
: public CallInterfaceDescriptor {
public:
diff --git a/src/isolate.cc b/src/isolate.cc
index a49eee6..2595d2f 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -1047,15 +1047,15 @@
}
-void Isolate::ComputeLocationFromStackTrace(MessageLocation* target,
+bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target,
Handle<Object> exception) {
*target = MessageLocation(Handle<Script>(heap_.empty_script()), -1, -1);
- if (!exception->IsJSObject()) return;
+ if (!exception->IsJSObject()) return false;
Handle<Name> key = factory()->stack_trace_symbol();
Handle<Object> property =
JSObject::GetDataProperty(Handle<JSObject>::cast(exception), key);
- if (!property->IsJSArray()) return;
+ if (!property->IsJSArray()) return false;
Handle<JSArray> simple_stack_trace = Handle<JSArray>::cast(property);
Handle<FixedArray> elements(FixedArray::cast(simple_stack_trace->elements()));
@@ -1075,9 +1075,10 @@
int pos = code->SourcePosition(pc);
Handle<Script> casted_script(Script::cast(script));
*target = MessageLocation(casted_script, pos, pos + 1);
- break;
+ return true;
}
}
+ return false;
}
@@ -1149,10 +1150,6 @@
// at this throw site.
stack_trace_object =
GetDetailedStackTrace(Handle<JSObject>::cast(exception));
- if (!location) {
- ComputeLocationFromStackTrace(&potential_computed_location, exception);
- location = &potential_computed_location;
- }
}
if (stack_trace_object.is_null()) {
// Not an error object, we capture stack and location at throw site.
@@ -1162,7 +1159,10 @@
}
}
if (!location) {
- ComputeLocation(&potential_computed_location);
+ if (!ComputeLocationFromStackTrace(&potential_computed_location,
+ exception)) {
+ ComputeLocation(&potential_computed_location);
+ }
location = &potential_computed_location;
}
diff --git a/src/isolate.h b/src/isolate.h
index 7e50929..3551632 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -801,7 +801,7 @@
// Attempts to compute the current source location, storing the
// result in the target out parameter.
void ComputeLocation(MessageLocation* target);
- void ComputeLocationFromStackTrace(MessageLocation* target,
+ bool ComputeLocationFromStackTrace(MessageLocation* target,
Handle<Object> exception);
Handle<JSMessageObject> CreateMessage(Handle<Object> exception,
diff --git a/src/mips/interface-descriptors-mips.cc b/src/mips/interface-descriptors-mips.cc
index 7e14967..ecdaecf 100644
--- a/src/mips/interface-descriptors-mips.cc
+++ b/src/mips/interface-descriptors-mips.cc
@@ -152,6 +152,15 @@
}
+void AllocateHeapNumberDescriptor::Initialize(
+ CallInterfaceDescriptorData* data) {
+ // register state
+ // cp -- context
+ Register registers[] = {cp};
+ data->Initialize(arraysize(registers), registers, nullptr);
+}
+
+
void ArrayConstructorConstantArgCountDescriptor::Initialize(
CallInterfaceDescriptorData* data) {
// register state
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index a5af1b8..deb3ff6 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -2037,18 +2037,26 @@
b(offset);
break;
case eq:
- // We don't want any other register but scratch clobbered.
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- beq(rs, r2, offset);
+ if (rt.imm32_ == 0) {
+ beq(rs, zero_reg, offset);
+ } else {
+ // We don't want any other register but scratch clobbered.
+ DCHECK(!scratch.is(rs));
+ r2 = scratch;
+ li(r2, rt);
+ beq(rs, r2, offset);
+ }
break;
case ne:
- // We don't want any other register but scratch clobbered.
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- bne(rs, r2, offset);
+ if (rt.imm32_ == 0) {
+ bne(rs, zero_reg, offset);
+ } else {
+ // We don't want any other register but scratch clobbered.
+ DCHECK(!scratch.is(rs));
+ r2 = scratch;
+ li(r2, rt);
+ bne(rs, r2, offset);
+ }
break;
// Signed comparison.
case greater:
@@ -2290,18 +2298,28 @@
b(offset);
break;
case eq:
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- offset = shifted_branch_offset(L, false);
- beq(rs, r2, offset);
+ if (rt.imm32_ == 0) {
+ offset = shifted_branch_offset(L, false);
+ beq(rs, zero_reg, offset);
+ } else {
+ DCHECK(!scratch.is(rs));
+ r2 = scratch;
+ li(r2, rt);
+ offset = shifted_branch_offset(L, false);
+ beq(rs, r2, offset);
+ }
break;
case ne:
- DCHECK(!scratch.is(rs));
- r2 = scratch;
- li(r2, rt);
- offset = shifted_branch_offset(L, false);
- bne(rs, r2, offset);
+ if (rt.imm32_ == 0) {
+ offset = shifted_branch_offset(L, false);
+ bne(rs, zero_reg, offset);
+ } else {
+ DCHECK(!scratch.is(rs));
+ r2 = scratch;
+ li(r2, rt);
+ offset = shifted_branch_offset(L, false);
+ bne(rs, r2, offset);
+ }
break;
// Signed comparison.
case greater:
diff --git a/src/mips64/interface-descriptors-mips64.cc b/src/mips64/interface-descriptors-mips64.cc
index a14a08b..44c8dff 100644
--- a/src/mips64/interface-descriptors-mips64.cc
+++ b/src/mips64/interface-descriptors-mips64.cc
@@ -152,6 +152,15 @@
}
+void AllocateHeapNumberDescriptor::Initialize(
+ CallInterfaceDescriptorData* data) {
+ // register state
+ // cp -- context
+ Register registers[] = {cp};
+ data->Initialize(arraysize(registers), registers, nullptr);
+}
+
+
void ArrayConstructorConstantArgCountDescriptor::Initialize(
CallInterfaceDescriptorData* data) {
// register state
diff --git a/src/mirror-debugger.js b/src/mirror-debugger.js
index c36d6fd..da031d3 100644
--- a/src/mirror-debugger.js
+++ b/src/mirror-debugger.js
@@ -85,6 +85,8 @@
mirror = new MapMirror(value);
} else if (IS_SET(value) || IS_WEAKSET(value)) {
mirror = new SetMirror(value);
+ } else if (IS_MAP_ITERATOR(value) || IS_SET_ITERATOR(value)) {
+ mirror = new IteratorMirror(value);
} else if (ObjectIsPromise(value)) {
mirror = new PromiseMirror(value);
} else if (IS_GENERATOR(value)) {
@@ -163,6 +165,7 @@
var PROMISE_TYPE = 'promise';
var MAP_TYPE = 'map';
var SET_TYPE = 'set';
+var ITERATOR_TYPE = 'iterator';
var GENERATOR_TYPE = 'generator';
// Maximum length when sending strings through the JSON protocol.
@@ -217,6 +220,7 @@
// - PromiseMirror
// - MapMirror
// - SetMirror
+// - IteratorMirror
// - GeneratorMirror
// - PropertyMirror
// - InternalPropertyMirror
@@ -456,6 +460,15 @@
/**
+ * Check whether the mirror reflects an iterator.
+ * @returns {boolean} True if the mirror reflects an iterator
+ */
+Mirror.prototype.isIterator = function() {
+ return this instanceof IteratorMirror;
+};
+
+
+/**
* Allocate a handle id for this object.
*/
Mirror.prototype.allocateHandle_ = function() {
@@ -1343,6 +1356,16 @@
inherits(SetMirror, ObjectMirror);
+function IteratorGetValues_(iter, next_function) {
+ var result = [];
+ var next;
+ while (!(next = %_CallFunction(iter, next_function)).done) {
+ result.push(next.value);
+ }
+ return result;
+}
+
+
/**
* Returns an array of elements of a set.
* This will keep elements alive for WeakSets.
@@ -1354,13 +1377,31 @@
return %GetWeakSetValues(this.value_);
}
- var result = [];
var iter = %_CallFunction(this.value_, builtins.SetValues);
- var next;
- while (!(next = iter.next()).done) {
- result.push(next.value);
+ return IteratorGetValues_(iter, builtins.SetIteratorNextJS);
+};
+
+
+function IteratorMirror(value) {
+ %_CallFunction(this, value, ITERATOR_TYPE, ObjectMirror);
+}
+inherits(IteratorMirror, ObjectMirror);
+
+
+/**
+ * Returns a preview of elements of an iterator.
+ * Does not change the backing iterator state.
+ *
+ * @returns {Array.<Object>} Array of elements of an iterator.
+ */
+IteratorMirror.prototype.preview = function() {
+ if (IS_MAP_ITERATOR(this.value_)) {
+ return IteratorGetValues_(%MapIteratorClone(this.value_),
+ builtins.MapIteratorNextJS);
+ } else if (IS_SET_ITERATOR(this.value_)) {
+ return IteratorGetValues_(%SetIteratorClone(this.value_),
+ builtins.SetIteratorNextJS);
}
- return result;
};
diff --git a/src/objects-inl.h b/src/objects-inl.h
index b25ac5c..6d0f8d4 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2801,8 +2801,10 @@
// Perform a binary search in a fixed array. Low and high are entry indices. If
// there are three entries in this array it should be called with low=0 and
// high=2.
-template<SearchMode search_mode, typename T>
-int BinarySearch(T* array, Name* name, int low, int high, int valid_entries) {
+template <SearchMode search_mode, typename T>
+int BinarySearch(T* array, Name* name, int low, int high, int valid_entries,
+ int* out_insertion_index) {
+ DCHECK(search_mode == ALL_ENTRIES || out_insertion_index == NULL);
uint32_t hash = name->Hash();
int limit = high;
@@ -2823,7 +2825,13 @@
for (; low <= limit; ++low) {
int sort_index = array->GetSortedKeyIndex(low);
Name* entry = array->GetKey(sort_index);
- if (entry->Hash() != hash) break;
+ uint32_t current_hash = entry->Hash();
+ if (current_hash != hash) {
+ if (out_insertion_index != NULL) {
+ *out_insertion_index = sort_index + (current_hash > hash ? 0 : 1);
+ }
+ return T::kNotFound;
+ }
if (entry->Equals(name)) {
if (search_mode == ALL_ENTRIES || sort_index < valid_entries) {
return sort_index;
@@ -2832,37 +2840,45 @@
}
}
+ if (out_insertion_index != NULL) *out_insertion_index = limit + 1;
return T::kNotFound;
}
// Perform a linear search in this fixed array. len is the number of entry
// indices that are valid.
-template<SearchMode search_mode, typename T>
-int LinearSearch(T* array, Name* name, int len, int valid_entries) {
+template <SearchMode search_mode, typename T>
+int LinearSearch(T* array, Name* name, int len, int valid_entries,
+ int* out_insertion_index) {
uint32_t hash = name->Hash();
if (search_mode == ALL_ENTRIES) {
for (int number = 0; number < len; number++) {
int sorted_index = array->GetSortedKeyIndex(number);
Name* entry = array->GetKey(sorted_index);
uint32_t current_hash = entry->Hash();
- if (current_hash > hash) break;
+ if (current_hash > hash) {
+ if (out_insertion_index != NULL) *out_insertion_index = sorted_index;
+ return T::kNotFound;
+ }
if (current_hash == hash && entry->Equals(name)) return sorted_index;
}
+ if (out_insertion_index != NULL) *out_insertion_index = len;
+ return T::kNotFound;
} else {
DCHECK(len >= valid_entries);
+ DCHECK_EQ(NULL, out_insertion_index); // Not supported here.
for (int number = 0; number < valid_entries; number++) {
Name* entry = array->GetKey(number);
uint32_t current_hash = entry->Hash();
if (current_hash == hash && entry->Equals(name)) return number;
}
+ return T::kNotFound;
}
- return T::kNotFound;
}
-template<SearchMode search_mode, typename T>
-int Search(T* array, Name* name, int valid_entries) {
+template <SearchMode search_mode, typename T>
+int Search(T* array, Name* name, int valid_entries, int* out_insertion_index) {
if (search_mode == VALID_ENTRIES) {
SLOW_DCHECK(array->IsSortedNoDuplicates(valid_entries));
} else {
@@ -2870,7 +2886,10 @@
}
int nof = array->number_of_entries();
- if (nof == 0) return T::kNotFound;
+ if (nof == 0) {
+ if (out_insertion_index != NULL) *out_insertion_index = 0;
+ return T::kNotFound;
+ }
// Fast case: do linear search for small arrays.
const int kMaxElementsForLinearSearch = 8;
@@ -2878,16 +2897,18 @@
nof <= kMaxElementsForLinearSearch) ||
(search_mode == VALID_ENTRIES &&
valid_entries <= (kMaxElementsForLinearSearch * 3))) {
- return LinearSearch<search_mode>(array, name, nof, valid_entries);
+ return LinearSearch<search_mode>(array, name, nof, valid_entries,
+ out_insertion_index);
}
// Slow case: perform binary search.
- return BinarySearch<search_mode>(array, name, 0, nof - 1, valid_entries);
+ return BinarySearch<search_mode>(array, name, 0, nof - 1, valid_entries,
+ out_insertion_index);
}
int DescriptorArray::Search(Name* name, int valid_descriptors) {
- return internal::Search<VALID_ENTRIES>(this, name, valid_descriptors);
+ return internal::Search<VALID_ENTRIES>(this, name, valid_descriptors, NULL);
}
diff --git a/src/objects.h b/src/objects.h
index 0f2cfc0..d12896f 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -3145,12 +3145,9 @@
enum SearchMode { ALL_ENTRIES, VALID_ENTRIES };
-template<SearchMode search_mode, typename T>
-inline int LinearSearch(T* array, Name* name, int len, int valid_entries);
-
-
-template<SearchMode search_mode, typename T>
-inline int Search(T* array, Name* name, int valid_entries = 0);
+template <SearchMode search_mode, typename T>
+inline int Search(T* array, Name* name, int valid_entries = 0,
+ int* out_insertion_index = NULL);
// HashTable is a subclass of FixedArray that implements a hash table
diff --git a/src/runtime/runtime-collections.cc b/src/runtime/runtime-collections.cc
index c1a63dc..45ac41c 100644
--- a/src/runtime/runtime-collections.cc
+++ b/src/runtime/runtime-collections.cc
@@ -92,6 +92,20 @@
}
+RUNTIME_FUNCTION(Runtime_SetIteratorClone) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
+
+ Handle<JSSetIterator> result = isolate->factory()->NewJSSetIterator();
+ result->set_table(holder->table());
+ result->set_index(Smi::FromInt(Smi::cast(holder->index())->value()));
+ result->set_kind(Smi::FromInt(Smi::cast(holder->kind())->value()));
+
+ return *result;
+}
+
+
RUNTIME_FUNCTION(Runtime_SetIteratorNext) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
@@ -197,6 +211,20 @@
}
+RUNTIME_FUNCTION(Runtime_MapIteratorClone) {
+ HandleScope scope(isolate);
+ DCHECK(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
+
+ Handle<JSMapIterator> result = isolate->factory()->NewJSMapIterator();
+ result->set_table(holder->table());
+ result->set_index(Smi::FromInt(Smi::cast(holder->index())->value()));
+ result->set_kind(Smi::FromInt(Smi::cast(holder->kind())->value()));
+
+ return *result;
+}
+
+
RUNTIME_FUNCTION(Runtime_GetWeakMapEntries) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
index 599a024..448010a 100644
--- a/src/runtime/runtime.h
+++ b/src/runtime/runtime.h
@@ -310,6 +310,7 @@
F(SetGetSize, 1, 1) \
\
F(SetIteratorInitialize, 3, 1) \
+ F(SetIteratorClone, 1, 1) \
F(SetIteratorNext, 2, 1) \
\
/* Harmony maps */ \
@@ -322,6 +323,7 @@
F(MapGetSize, 1, 1) \
\
F(MapIteratorInitialize, 3, 1) \
+ F(MapIteratorClone, 1, 1) \
F(MapIteratorNext, 2, 1) \
\
/* Harmony weak maps and sets */ \
diff --git a/src/symbol.js b/src/symbol.js
index d6ac527..b4ae708 100644
--- a/src/symbol.js
+++ b/src/symbol.js
@@ -73,7 +73,7 @@
// TODO(arv): Proxies use a shared trap for String and Symbol keys.
- return ObjectGetOwnPropertyKeys(obj, true);
+ return ObjectGetOwnPropertyKeys(obj, PROPERTY_ATTRIBUTES_STRING);
}
diff --git a/src/transitions-inl.h b/src/transitions-inl.h
index 6ed86a1..087755d 100644
--- a/src/transitions-inl.h
+++ b/src/transitions-inl.h
@@ -140,13 +140,16 @@
}
-int TransitionArray::Search(Name* name) {
+int TransitionArray::Search(Name* name, int* out_insertion_index) {
if (IsSimpleTransition()) {
Name* key = GetKey(kSimpleTransitionIndex);
if (key->Equals(name)) return kSimpleTransitionIndex;
+ if (out_insertion_index != NULL) {
+ *out_insertion_index = key->Hash() > name->Hash() ? 0 : 1;
+ }
return kNotFound;
}
- return internal::Search<ALL_ENTRIES>(this, name);
+ return internal::Search<ALL_ENTRIES>(this, name, 0, out_insertion_index);
}
diff --git a/src/transitions.cc b/src/transitions.cc
index 3e570ff..ec1b7f4 100644
--- a/src/transitions.cc
+++ b/src/transitions.cc
@@ -41,11 +41,6 @@
}
-static bool InsertionPointFound(Name* key1, Name* key2) {
- return key1->Hash() > key2->Hash();
-}
-
-
Handle<TransitionArray> TransitionArray::NewWith(Handle<Map> map,
Handle<Name> name,
Handle<Map> target,
@@ -99,30 +94,36 @@
int number_of_transitions = map->transitions()->number_of_transitions();
int new_nof = number_of_transitions;
- int insertion_index = map->transitions()->Search(*name);
- if (insertion_index == kNotFound) ++new_nof;
+ int insertion_index = kNotFound;
+ int index = map->transitions()->Search(*name, &insertion_index);
+
+ if (index == kNotFound) {
+ ++new_nof;
+ } else {
+ insertion_index = index;
+ }
+ DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);
+
CHECK(new_nof <= kMaxNumberOfTransitions);
if (new_nof <= map->transitions()->number_of_transitions_storage()) {
DisallowHeapAllocation no_gc;
TransitionArray* array = map->transitions();
- if (insertion_index != kNotFound) {
- array->SetTarget(insertion_index, *target);
+ if (index != kNotFound) {
+ array->SetTarget(index, *target);
return handle(array);
}
array->SetNumberOfTransitions(new_nof);
- uint32_t hash = name->Hash();
- for (insertion_index = number_of_transitions; insertion_index > 0;
- --insertion_index) {
- Name* key = array->GetKey(insertion_index - 1);
- if (key->Hash() <= hash) break;
- array->SetKey(insertion_index, key);
- array->SetTarget(insertion_index, array->GetTarget(insertion_index - 1));
+ for (index = number_of_transitions; index > insertion_index; --index) {
+ Name* key = array->GetKey(index - 1);
+ DCHECK(key->Hash() > name->Hash());
+ array->SetKey(index, key);
+ array->SetTarget(index, array->GetTarget(index - 1));
}
- array->SetKey(insertion_index, *name);
- array->SetTarget(insertion_index, *target);
+ array->SetKey(index, *name);
+ array->SetTarget(index, *target);
return handle(array);
}
@@ -142,8 +143,14 @@
number_of_transitions = array->number_of_transitions();
new_nof = number_of_transitions;
- insertion_index = array->Search(*name);
- if (insertion_index == kNotFound) ++new_nof;
+ insertion_index = kNotFound;
+ index = array->Search(*name, &insertion_index);
+ if (index == kNotFound) {
+ ++new_nof;
+ } else {
+ insertion_index = index;
+ }
+ DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);
result->Shrink(ToKeyIndex(new_nof));
result->SetNumberOfTransitions(new_nof);
@@ -153,18 +160,13 @@
result->SetPrototypeTransitions(array->GetPrototypeTransitions());
}
- insertion_index = 0;
- for (; insertion_index < number_of_transitions; ++insertion_index) {
- if (InsertionPointFound(array->GetKey(insertion_index), *name)) break;
- result->NoIncrementalWriteBarrierCopyFrom(
- array, insertion_index, insertion_index);
+ DCHECK_NE(kNotFound, insertion_index);
+ for (int i = 0; i < insertion_index; ++i) {
+ result->NoIncrementalWriteBarrierCopyFrom(array, i, i);
}
-
result->NoIncrementalWriteBarrierSet(insertion_index, *name, *target);
-
- for (; insertion_index < number_of_transitions; ++insertion_index) {
- result->NoIncrementalWriteBarrierCopyFrom(
- array, insertion_index, insertion_index + 1);
+ for (int i = insertion_index; i < number_of_transitions; ++i) {
+ result->NoIncrementalWriteBarrierCopyFrom(array, i, i + 1);
}
result->set_back_pointer_storage(array->back_pointer_storage());
diff --git a/src/transitions.h b/src/transitions.h
index b7e4ebe..c5f9a30 100644
--- a/src/transitions.h
+++ b/src/transitions.h
@@ -100,7 +100,7 @@
SimpleTransitionFlag flag);
// Search a transition for a given property name.
- inline int Search(Name* name);
+ inline int Search(Name* name, int* out_insertion_index = NULL);
// Allocates a TransitionArray.
static Handle<TransitionArray> Allocate(Isolate* isolate,
diff --git a/src/v8natives.js b/src/v8natives.js
index 7636b70..6215ab0 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -252,8 +252,8 @@
// ECMA-262 - 15.2.4.6
function ObjectIsPrototypeOf(V) {
- CHECK_OBJECT_COERCIBLE(this, "Object.prototype.isPrototypeOf");
if (!IS_SPEC_OBJECT(V)) return false;
+ CHECK_OBJECT_COERCIBLE(this, "Object.prototype.isPrototypeOf");
return %IsInPrototypeChain(this, V);
}
@@ -1038,16 +1038,14 @@
}
-function ObjectGetOwnPropertyKeys(obj, symbolsOnly) {
+function ObjectGetOwnPropertyKeys(obj, filter) {
var nameArrays = new InternalArray();
- var filter = symbolsOnly ?
- PROPERTY_ATTRIBUTES_STRING | PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL :
- PROPERTY_ATTRIBUTES_SYMBOLIC;
+ filter |= PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL;
// Find all the indexed properties.
// Only get own element names if we want to include string keys.
- if (!symbolsOnly) {
+ if ((filter & PROPERTY_ATTRIBUTES_STRING) === 0) {
var ownElementNames = %GetOwnElementNames(obj);
for (var i = 0; i < ownElementNames.length; ++i) {
ownElementNames[i] = %_NumberToString(ownElementNames[i]);
@@ -1089,10 +1087,12 @@
var j = 0;
for (var i = 0; i < propertyNames.length; ++i) {
var name = propertyNames[i];
- if (symbolsOnly) {
- if (!IS_SYMBOL(name) || IS_PRIVATE(name)) continue;
+ if (IS_SYMBOL(name)) {
+ if ((filter & PROPERTY_ATTRIBUTES_SYMBOLIC) || IS_PRIVATE(name)) {
+ continue;
+ }
} else {
- if (IS_SYMBOL(name)) continue;
+ if (filter & PROPERTY_ATTRIBUTES_STRING) continue;
name = ToString(name);
}
if (seenKeys[name]) continue;
@@ -1116,7 +1116,7 @@
return ToNameArray(names, "getOwnPropertyNames", false);
}
- return ObjectGetOwnPropertyKeys(obj, false);
+ return ObjectGetOwnPropertyKeys(obj, PROPERTY_ATTRIBUTES_SYMBOLIC);
}
diff --git a/src/version.cc b/src/version.cc
index 09aa482..70a1f9d 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 30
-#define BUILD_NUMBER 32
+#define BUILD_NUMBER 33
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/interface-descriptors-x64.cc b/src/x64/interface-descriptors-x64.cc
index bc058ff..f19979d 100644
--- a/src/x64/interface-descriptors-x64.cc
+++ b/src/x64/interface-descriptors-x64.cc
@@ -155,6 +155,15 @@
}
+void AllocateHeapNumberDescriptor::Initialize(
+ CallInterfaceDescriptorData* data) {
+ // register state
+ // rsi -- context
+ Register registers[] = {rsi};
+ data->Initialize(arraysize(registers), registers, nullptr);
+}
+
+
void ArrayConstructorConstantArgCountDescriptor::Initialize(
CallInterfaceDescriptorData* data) {
// register state
diff --git a/test/cctest/compiler/test-codegen-deopt.cc b/test/cctest/compiler/test-codegen-deopt.cc
index c9a033b..974b423 100644
--- a/test/cctest/compiler/test-codegen-deopt.cc
+++ b/test/cctest/compiler/test-codegen-deopt.cc
@@ -75,18 +75,22 @@
selector.SelectInstructions();
if (FLAG_trace_turbo) {
+ PrintableInstructionSequence printable = {
+ RegisterConfiguration::ArchDefault(), code};
os << "----- Instruction sequence before register allocation -----\n"
- << *code;
+ << printable;
}
Frame frame;
- RegisterAllocator allocator(RegisterAllocator::PlatformConfig(),
+ RegisterAllocator allocator(RegisterConfiguration::ArchDefault(),
scope_->main_zone(), &frame, code);
CHECK(allocator.Allocate());
if (FLAG_trace_turbo) {
+ PrintableInstructionSequence printable = {
+ RegisterConfiguration::ArchDefault(), code};
os << "----- Instruction sequence after register allocation -----\n"
- << *code;
+ << printable;
}
compiler::CodeGenerator generator(&frame, linkage, code, &info);
diff --git a/test/cctest/compiler/test-control-reducer.cc b/test/cctest/compiler/test-control-reducer.cc
index 58437c5..67fdb68 100644
--- a/test/cctest/compiler/test-control-reducer.cc
+++ b/test/cctest/compiler/test-control-reducer.cc
@@ -973,6 +973,7 @@
};
+// TODO(titzer): use the diamonds from src/compiler/diamond.h here.
struct Diamond {
Node* branch;
Node* if_true;
diff --git a/test/cctest/compiler/test-gap-resolver.cc b/test/cctest/compiler/test-gap-resolver.cc
index aeaf8b9..ea6f4ee 100644
--- a/test/cctest/compiler/test-gap-resolver.cc
+++ b/test/cctest/compiler/test-gap-resolver.cc
@@ -65,7 +65,9 @@
if (it != is.values_.begin()) os << " ";
InstructionOperand source(it->first.first, it->first.second);
InstructionOperand destination(it->second.first, it->second.second);
- os << MoveOperands(&source, &destination);
+ MoveOperands mo(&source, &destination);
+ PrintableMoveOperands pmo = {RegisterConfiguration::ArchDefault(), &mo};
+ os << pmo;
}
return os;
}
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 0e6d128..068a07e 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -8638,6 +8638,8 @@
THREADED_TEST(ExceptionGetMessage) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
+ v8::Handle<String> foo_str = v8_str("foo");
+ v8::Handle<String> message_str = v8_str("message");
v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
@@ -8655,8 +8657,6 @@
CHECK(try_catch.HasCaught());
v8::Handle<v8::Value> error = try_catch.Exception();
- v8::Handle<String> foo_str = v8_str("foo");
- v8::Handle<String> message_str = v8_str("message");
CHECK(error->IsObject());
CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
@@ -8670,6 +8670,30 @@
CHECK_EQ(2, stackTrace->GetFrameCount());
v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
+
+ // Now check message location when SetCaptureStackTraceForUncaughtExceptions
+ // is false.
+ try_catch.Reset();
+
+ CompileRun(
+ "function f2() {\n"
+ " return throwV8Exception();\n"
+ "};\n"
+ "f2();");
+ CHECK(try_catch.HasCaught());
+
+ error = try_catch.Exception();
+ CHECK(error->IsObject());
+ CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
+
+ message = v8::Exception::GetMessage(error);
+ CHECK(!message.IsEmpty());
+ CHECK_EQ(2, message->GetLineNumber());
+ CHECK_EQ(9, message->GetStartColumn());
+
+ // Should be empty stack trace.
+ stackTrace = message->GetStackTrace();
+ CHECK(stackTrace.IsEmpty());
}
diff --git a/test/mjsunit/asm/uint32div.js b/test/mjsunit/asm/uint32div.js
index 54a2138..dcbb73b 100644
--- a/test/mjsunit/asm/uint32div.js
+++ b/test/mjsunit/asm/uint32div.js
@@ -22,8 +22,24 @@
var divisors = [0, 1, 3, 4, 10, 42, 64, 100, 1024, 2147483647, 4294967295];
for (var i in divisors) {
var divisor = divisors[i];
- var mod = Uint32Div(divisor);
+ var div = Uint32Div(divisor);
for (var dividend = 0; dividend < 4294967296; dividend += 3999773) {
- assertEquals((dividend / divisor) >>> 0, mod(dividend));
+ assertEquals((dividend / divisor) >>> 0, div(dividend));
+ }
+}
+
+var div = (function(stdlib, foreign, heap) {
+ "use asm";
+ function div(dividend, divisor) {
+ return (dividend >>> 0) / (divisor >>> 0) | 0;
+ }
+ return {div: div};
+})(stdlib, foreign, heap).div;
+
+for (var i in divisors) {
+ var divisor = divisors[i];
+ for (var dividend = 0; dividend < 4294967296; dividend += 3999773) {
+ assertEquals((dividend >>> 0) / (divisor >>> 0) | 0,
+ div(dividend, divisor));
}
}
diff --git a/test/mjsunit/es6/mirror-iterators.js b/test/mjsunit/es6/mirror-iterators.js
new file mode 100644
index 0000000..02fe7ff
--- /dev/null
+++ b/test/mjsunit/es6/mirror-iterators.js
@@ -0,0 +1,62 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug
+// Test the mirror object for collection iterators.
+
+function testIteratorMirror(iter, offset, expected) {
+ while (offset-- > 0) iter.next();
+
+ var mirror = debug.MakeMirror(iter);
+ assertTrue(mirror.isIterator());
+
+ var preview = mirror.preview();
+ assertArrayEquals(expected, preview);
+
+ // Check that iterator has not changed after taking preview.
+ var values = [];
+ for (var i of iter) values.push(i);
+ assertArrayEquals(expected, values);
+}
+
+var o1 = { foo: 1 };
+var o2 = { foo: 2 };
+
+var map = new Map();
+map.set(41, 42);
+map.set(o1, o2);
+
+testIteratorMirror(map.keys(), 0, [41, o1]);
+testIteratorMirror(map.values(), 0, [42, o2]);
+testIteratorMirror(map.entries(), 0, [[41, 42], [o1, o2]]);
+
+testIteratorMirror(map.keys(), 1, [o1]);
+testIteratorMirror(map.values(), 1, [o2]);
+testIteratorMirror(map.entries(), 1, [[o1, o2]]);
+
+testIteratorMirror(map.keys(), 2, []);
+testIteratorMirror(map.values(), 2, []);
+testIteratorMirror(map.entries(), 2, []);
+
+var set = new Set();
+set.add(41);
+set.add(42);
+set.add(o1);
+set.add(o2);
+
+testIteratorMirror(set.keys(), 0, [41, 42, o1, o2]);
+testIteratorMirror(set.values(), 0, [41, 42, o1, o2]);
+testIteratorMirror(set.entries(), 0, [[41, 41], [42, 42], [o1, o1], [o2, o2]]);
+
+testIteratorMirror(set.keys(), 1, [42, o1, o2]);
+testIteratorMirror(set.values(), 1, [42, o1, o2]);
+testIteratorMirror(set.entries(), 1, [[42, 42], [o1, o1], [o2, o2]]);
+
+testIteratorMirror(set.keys(), 3, [o2]);
+testIteratorMirror(set.values(), 3, [o2]);
+testIteratorMirror(set.entries(), 3, [[o2, o2]]);
+
+testIteratorMirror(set.keys(), 5, []);
+testIteratorMirror(set.values(), 5, []);
+testIteratorMirror(set.entries(), 5, []);
diff --git a/test/mjsunit/function-call.js b/test/mjsunit/function-call.js
index 88df353..fb91dcd 100644
--- a/test/mjsunit/function-call.js
+++ b/test/mjsunit/function-call.js
@@ -162,13 +162,10 @@
var exception = false;
try {
- // We call all functions with no parameters, which means that essential
- // parameters will have the undefined value.
- // The test for whether the "this" value is null or undefined is always
- // performed before access to the other parameters, so even if the
- // undefined value is an invalid argument value, it mustn't change
- // the result of the test.
- should_throw_on_null_and_undefined[i].call(null);
+ // We need to pass a dummy object argument ({}) to these functions because
+ // of Object.prototype.isPrototypeOf's special behavior, see issue 3483
+ // for more details.
+ should_throw_on_null_and_undefined[i].call(null, {});
} catch (e) {
exception = true;
checkExpectedMessage(e);
@@ -177,7 +174,7 @@
exception = false;
try {
- should_throw_on_null_and_undefined[i].call(undefined);
+ should_throw_on_null_and_undefined[i].call(undefined, {});
} catch (e) {
exception = true;
checkExpectedMessage(e);
@@ -186,7 +183,7 @@
exception = false;
try {
- should_throw_on_null_and_undefined[i].apply(null);
+ should_throw_on_null_and_undefined[i].apply(null, [{}]);
} catch (e) {
exception = true;
checkExpectedMessage(e);
@@ -195,7 +192,7 @@
exception = false;
try {
- should_throw_on_null_and_undefined[i].apply(undefined);
+ should_throw_on_null_and_undefined[i].apply(undefined, [{}]);
} catch (e) {
exception = true;
checkExpectedMessage(e);
@@ -248,7 +245,9 @@
// Test that we still throw when calling with thisArg null or undefined
// through an array mapping function.
-var array = [1,2,3,4,5];
+// We need to make sure that the elements of `array` are all object values,
+// see issue 3483 for more details.
+var array = [{}, [], new Number, new Map, new WeakSet];
for (var j = 0; j < mapping_functions.length; j++) {
for (var i = 0; i < should_throw_on_null_and_undefined.length; i++) {
exception = false;
diff --git a/test/mjsunit/harmony/classes.js b/test/mjsunit/harmony/classes.js
index c5c2b72..59371e4 100644
--- a/test/mjsunit/harmony/classes.js
+++ b/test/mjsunit/harmony/classes.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --harmony
+// Flags: --harmony-classes
(function TestBasics() {
var C = class C {}
diff --git a/test/mjsunit/harmony/regress/regress-343928.js b/test/mjsunit/harmony/regress/regress-343928.js
index b102ab9..f2ff371 100644
--- a/test/mjsunit/harmony/regress/regress-343928.js
+++ b/test/mjsunit/harmony/regress/regress-343928.js
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Flags: --harmony --expose-debug-as=debug
+// Flags: --harmony-modules --expose-debug-as=debug
(function () { // Scope for utility functions.
escaping_function = function(object) {
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index 9e3435d..1185a11 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -236,6 +236,8 @@
# TODO(mstarzinger): Takes too long with TF.
'array-sort': [PASS, NO_VARIANTS],
'regress/regress-91008': [PASS, NO_VARIANTS],
+ 'regress/regress-417709a': [PASS, ['arch == arm64', NO_VARIANTS]],
+ 'regress/regress-transcendental': [PASS, ['arch == arm64', NO_VARIANTS]],
'compiler/osr-regress-max-locals': [PASS, NO_VARIANTS],
'math-floor-of-div': [PASS, NO_VARIANTS],
'unicodelctest': [PASS, NO_VARIANTS],
diff --git a/test/mjsunit/polymorph-arrays.js b/test/mjsunit/polymorph-arrays.js
index 2bb0433..6a05c9f 100644
--- a/test/mjsunit/polymorph-arrays.js
+++ b/test/mjsunit/polymorph-arrays.js
@@ -36,7 +36,7 @@
for (var i = 0; i < 10; ++i ){
a[i] = i;
}
- a[5000000] = 256;
+ a[200000] = 256;
return %NormalizeElements(a);
}
@@ -115,7 +115,7 @@
var sparse_object_array = new Object;
var js_array = new Array(10);
var sparse_js_array = [];
- sparse_js_array.length = 5000001;
+ sparse_js_array.length = 200001;
init_array(object_array);
init_array(js_array);
@@ -134,7 +134,8 @@
var sparse_object_array = new Object;
var js_array = new Array(10);
var sparse_js_array = %NormalizeElements([]);
- sparse_js_array.length = 5000001;
+ sparse_js_array.length = 200001;
+ assertTrue(%HasDictionaryElements(sparse_js_array));
init_array(object_array);
init_array(js_array);
diff --git a/test/mjsunit/regress/regress-3483.js b/test/mjsunit/regress/regress-3483.js
new file mode 100644
index 0000000..dec95c4
--- /dev/null
+++ b/test/mjsunit/regress/regress-3483.js
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+assertFalse(Object.prototype.isPrototypeOf.call());
+assertFalse(Object.prototype.isPrototypeOf.call(null, 1));
+assertFalse(Object.prototype.isPrototypeOf.call(undefined, 1));
diff --git a/test/test262-es6/test262-es6.status b/test/test262-es6/test262-es6.status
index b1db063..3791dfd 100644
--- a/test/test262-es6/test262-es6.status
+++ b/test/test262-es6/test262-es6.status
@@ -50,6 +50,25 @@
###################### MISSING ES6 FEATURES #######################
+ # Array.fill (currently requires --harmony-arrays)
+ 'S22.1.3.6_T1': [FAIL],
+
+ # Array.find (currently requires --harmony-arrays)
+ 'S22.1.2.3_T1': [FAIL],
+ 'S22.1.2.3_T2': [FAIL],
+ 'Array.prototype.find_empty-array-undefined': [FAIL],
+ 'Array.prototype.find_length-property': [FAIL],
+ 'Array.prototype.find_modify-after-start': [FAIL],
+ 'Array.prototype.find_non-returning-predicate': [FAIL],
+ 'Array.prototype.find_predicate-arguments': [FAIL],
+ 'Array.prototype.find_push-after-start': [FAIL],
+ 'Array.prototype.find_remove-after-start': [FAIL],
+ 'Array.prototype.find_return-found-value': [FAIL],
+ 'Array.prototype.find_skip-empty': [FAIL],
+ 'Array.prototype.find_this-defined': [FAIL],
+ 'Array.prototype.find_this-is-object': [FAIL],
+ 'Array.prototype.find_this-undefined': [FAIL],
+
# Array.from
'S22.1.2.1_T1': [FAIL],
'S22.1.2.1_T2': [FAIL],
diff --git a/test/unittests/compiler/change-lowering-unittest.cc b/test/unittests/compiler/change-lowering-unittest.cc
index 5f14b8e..a6a0db7 100644
--- a/test/unittests/compiler/change-lowering-unittest.cc
+++ b/test/unittests/compiler/change-lowering-unittest.cc
@@ -79,13 +79,9 @@
Matcher<Node*> IsAllocateHeapNumber(const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher) {
- return IsCall(
- _, IsHeapConstant(Unique<HeapObject>::CreateImmovable(
- CEntryStub(isolate(), 1).GetCode())),
- IsExternalConstant(ExternalReference(
- Runtime::FunctionForId(Runtime::kAllocateHeapNumber), isolate())),
- IsInt32Constant(0), IsNumberConstant(0.0), effect_matcher,
- control_matcher);
+ return IsCall(_, IsHeapConstant(Unique<HeapObject>::CreateImmovable(
+ AllocateHeapNumberStub(isolate()).GetCode())),
+ IsNumberConstant(0.0), effect_matcher, control_matcher);
}
Matcher<Node*> IsLoadHeapNumber(const Matcher<Node*>& value_matcher,
const Matcher<Node*>& control_matcher) {
diff --git a/test/unittests/compiler/diamond-unittest.cc b/test/unittests/compiler/diamond-unittest.cc
new file mode 100644
index 0000000..c14886f
--- /dev/null
+++ b/test/unittests/compiler/diamond-unittest.cc
@@ -0,0 +1,161 @@
+// 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.
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/diamond.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::AllOf;
+using testing::Capture;
+using testing::CaptureEq;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class DiamondTest : public GraphTest {
+ public:
+ DiamondTest() : GraphTest(5) {}
+};
+
+
+TEST_F(DiamondTest, SimpleDiamond) {
+ Node* p = Parameter(0);
+ Diamond d(graph(), common(), p);
+ EXPECT_THAT(d.branch, IsBranch(p, graph()->start()));
+ EXPECT_THAT(d.if_true, IsIfTrue(d.branch));
+ EXPECT_THAT(d.if_false, IsIfFalse(d.branch));
+ EXPECT_THAT(d.merge, IsMerge(d.if_true, d.if_false));
+}
+
+
+TEST_F(DiamondTest, DiamondChainDiamond) {
+ Node* p0 = Parameter(0);
+ Node* p1 = Parameter(1);
+ Diamond d0(graph(), common(), p0);
+ Diamond d1(graph(), common(), p1);
+ d1.Chain(d0);
+ EXPECT_THAT(d1.branch, IsBranch(p1, d0.merge));
+ EXPECT_THAT(d0.branch, IsBranch(p0, graph()->start()));
+}
+
+
+TEST_F(DiamondTest, DiamondChainNode) {
+ Node* p1 = Parameter(1);
+ Diamond d1(graph(), common(), p1);
+ Node* other = graph()->NewNode(common()->Merge(0));
+ d1.Chain(other);
+ EXPECT_THAT(d1.branch, IsBranch(p1, other));
+}
+
+
+TEST_F(DiamondTest, DiamondChainN) {
+ Node* params[5] = {Parameter(0), Parameter(1), Parameter(2), Parameter(3),
+ Parameter(4)};
+ Diamond d[5] = {Diamond(graph(), common(), params[0]),
+ Diamond(graph(), common(), params[1]),
+ Diamond(graph(), common(), params[2]),
+ Diamond(graph(), common(), params[3]),
+ Diamond(graph(), common(), params[4])};
+
+ for (int i = 1; i < 5; i++) {
+ d[i].Chain(d[i - 1]);
+ EXPECT_THAT(d[i].branch, IsBranch(params[i], d[i - 1].merge));
+ }
+}
+
+
+TEST_F(DiamondTest, DiamondNested_true) {
+ Node* p0 = Parameter(0);
+ Node* p1 = Parameter(1);
+ Diamond d0(graph(), common(), p0);
+ Diamond d1(graph(), common(), p1);
+
+ d1.Nest(d0, true);
+
+ EXPECT_THAT(d0.branch, IsBranch(p0, graph()->start()));
+ EXPECT_THAT(d0.if_true, IsIfTrue(d0.branch));
+ EXPECT_THAT(d0.if_false, IsIfFalse(d0.branch));
+ EXPECT_THAT(d0.merge, IsMerge(d1.merge, d0.if_false));
+
+ EXPECT_THAT(d1.branch, IsBranch(p1, d0.if_true));
+ EXPECT_THAT(d1.if_true, IsIfTrue(d1.branch));
+ EXPECT_THAT(d1.if_false, IsIfFalse(d1.branch));
+ EXPECT_THAT(d1.merge, IsMerge(d1.if_true, d1.if_false));
+}
+
+
+TEST_F(DiamondTest, DiamondNested_false) {
+ Node* p0 = Parameter(0);
+ Node* p1 = Parameter(1);
+ Diamond d0(graph(), common(), p0);
+ Diamond d1(graph(), common(), p1);
+
+ d1.Nest(d0, false);
+
+ EXPECT_THAT(d0.branch, IsBranch(p0, graph()->start()));
+ EXPECT_THAT(d0.if_true, IsIfTrue(d0.branch));
+ EXPECT_THAT(d0.if_false, IsIfFalse(d0.branch));
+ EXPECT_THAT(d0.merge, IsMerge(d0.if_true, d1.merge));
+
+ EXPECT_THAT(d1.branch, IsBranch(p1, d0.if_false));
+ EXPECT_THAT(d1.if_true, IsIfTrue(d1.branch));
+ EXPECT_THAT(d1.if_false, IsIfFalse(d1.branch));
+ EXPECT_THAT(d1.merge, IsMerge(d1.if_true, d1.if_false));
+}
+
+
+TEST_F(DiamondTest, DiamondPhis) {
+ Node* p0 = Parameter(0);
+ Node* p1 = Parameter(1);
+ Node* p2 = Parameter(2);
+ Diamond d(graph(), common(), p0);
+
+ MachineType types[] = {kMachAnyTagged, kMachUint32, kMachInt32};
+
+ for (size_t i = 0; i < arraysize(types); i++) {
+ Node* phi = d.Phi(types[i], p1, p2);
+
+ EXPECT_THAT(d.branch, IsBranch(p0, graph()->start()));
+ EXPECT_THAT(d.if_true, IsIfTrue(d.branch));
+ EXPECT_THAT(d.if_false, IsIfFalse(d.branch));
+ EXPECT_THAT(d.merge, IsMerge(d.if_true, d.if_false));
+ EXPECT_THAT(phi, IsPhi(types[i], p1, p2, d.merge));
+ }
+}
+
+
+TEST_F(DiamondTest, DiamondEffectPhis) {
+ Node* p0 = Parameter(0);
+ Node* p1 = Parameter(1);
+ Node* p2 = Parameter(2);
+ Diamond d(graph(), common(), p0);
+
+ Node* phi = d.EffectPhi(p1, p2);
+
+ EXPECT_THAT(d.branch, IsBranch(p0, graph()->start()));
+ EXPECT_THAT(d.if_true, IsIfTrue(d.branch));
+ EXPECT_THAT(d.if_false, IsIfFalse(d.branch));
+ EXPECT_THAT(d.merge, IsMerge(d.if_true, d.if_false));
+ EXPECT_THAT(phi, IsEffectPhi(p1, p2, d.merge));
+}
+
+
+TEST_F(DiamondTest, BranchHint) {
+ Diamond dn(graph(), common(), Parameter(0));
+ CHECK(BranchHint::kNone == BranchHintOf(dn.branch->op()));
+
+ Diamond dt(graph(), common(), Parameter(0), BranchHint::kTrue);
+ CHECK(BranchHint::kTrue == BranchHintOf(dt.branch->op()));
+
+ Diamond df(graph(), common(), Parameter(0), BranchHint::kFalse);
+ CHECK(BranchHint::kFalse == BranchHintOf(df.branch->op()));
+}
+
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
diff --git a/test/unittests/compiler/instruction-selector-unittest.cc b/test/unittests/compiler/instruction-selector-unittest.cc
index 57ce690..c79a9e4 100644
--- a/test/unittests/compiler/instruction-selector-unittest.cc
+++ b/test/unittests/compiler/instruction-selector-unittest.cc
@@ -46,8 +46,10 @@
selector.SelectInstructions();
if (FLAG_trace_turbo) {
OFStream out(stdout);
+ PrintableInstructionSequence printable = {
+ RegisterConfiguration::ArchDefault(), &sequence};
out << "=== Code sequence after instruction selection ===" << std::endl
- << sequence;
+ << printable;
}
Stream s;
// Map virtual registers.
diff --git a/test/unittests/compiler/node-test-utils.cc b/test/unittests/compiler/node-test-utils.cc
index 4c1e10b..5f1dea3 100644
--- a/test/unittests/compiler/node-test-utils.cc
+++ b/test/unittests/compiler/node-test-utils.cc
@@ -300,6 +300,45 @@
};
+class IsEffectPhiMatcher FINAL : public NodeMatcher {
+ public:
+ IsEffectPhiMatcher(const Matcher<Node*>& effect0_matcher,
+ const Matcher<Node*>& effect1_matcher,
+ const Matcher<Node*>& control_matcher)
+ : NodeMatcher(IrOpcode::kEffectPhi),
+ effect0_matcher_(effect0_matcher),
+ effect1_matcher_(effect1_matcher),
+ control_matcher_(control_matcher) {}
+
+ virtual void DescribeTo(std::ostream* os) const OVERRIDE {
+ NodeMatcher::DescribeTo(os);
+ *os << "), effect0 (";
+ effect0_matcher_.DescribeTo(os);
+ *os << "), effect1 (";
+ effect1_matcher_.DescribeTo(os);
+ *os << ") and control (";
+ control_matcher_.DescribeTo(os);
+ *os << ")";
+ }
+
+ virtual bool MatchAndExplain(Node* node,
+ MatchResultListener* listener) const OVERRIDE {
+ return (NodeMatcher::MatchAndExplain(node, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetEffectInput(node, 0),
+ "effect0", effect0_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetEffectInput(node, 1),
+ "effect1", effect1_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+ "control", control_matcher_, listener));
+ }
+
+ private:
+ const Matcher<Node*> effect0_matcher_;
+ const Matcher<Node*> effect1_matcher_;
+ const Matcher<Node*> control_matcher_;
+};
+
+
class IsProjectionMatcher FINAL : public NodeMatcher {
public:
IsProjectionMatcher(const Matcher<size_t>& index_matcher,
@@ -332,15 +371,66 @@
};
-class IsCallMatcher FINAL : public NodeMatcher {
+class IsCall2Matcher FINAL : public NodeMatcher {
public:
- IsCallMatcher(const Matcher<CallDescriptor*>& descriptor_matcher,
- const Matcher<Node*>& value0_matcher,
- const Matcher<Node*>& value1_matcher,
- const Matcher<Node*>& value2_matcher,
- const Matcher<Node*>& value3_matcher,
- const Matcher<Node*>& effect_matcher,
- const Matcher<Node*>& control_matcher)
+ IsCall2Matcher(const Matcher<CallDescriptor*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher,
+ const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher)
+ : NodeMatcher(IrOpcode::kCall),
+ descriptor_matcher_(descriptor_matcher),
+ value0_matcher_(value0_matcher),
+ value1_matcher_(value1_matcher),
+ effect_matcher_(effect_matcher),
+ control_matcher_(control_matcher) {}
+
+ virtual void DescribeTo(std::ostream* os) const OVERRIDE {
+ NodeMatcher::DescribeTo(os);
+ *os << " whose value0 (";
+ value0_matcher_.DescribeTo(os);
+ *os << ") and value1 (";
+ value1_matcher_.DescribeTo(os);
+ *os << ") and effect (";
+ effect_matcher_.DescribeTo(os);
+ *os << ") and control (";
+ control_matcher_.DescribeTo(os);
+ *os << ")";
+ }
+
+ virtual bool MatchAndExplain(Node* node,
+ MatchResultListener* listener) const OVERRIDE {
+ return (NodeMatcher::MatchAndExplain(node, listener) &&
+ PrintMatchAndExplain(OpParameter<CallDescriptor*>(node),
+ "descriptor", descriptor_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
+ "value0", value0_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
+ "value1", value1_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
+ effect_matcher_, listener) &&
+ PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+ "control", control_matcher_, listener));
+ }
+
+ private:
+ const Matcher<CallDescriptor*> descriptor_matcher_;
+ const Matcher<Node*> value0_matcher_;
+ const Matcher<Node*> value1_matcher_;
+ const Matcher<Node*> effect_matcher_;
+ const Matcher<Node*> control_matcher_;
+};
+
+
+class IsCall4Matcher FINAL : public NodeMatcher {
+ public:
+ IsCall4Matcher(const Matcher<CallDescriptor*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher,
+ const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& value2_matcher,
+ const Matcher<Node*>& value3_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher)
: NodeMatcher(IrOpcode::kCall),
descriptor_matcher_(descriptor_matcher),
value0_matcher_(value0_matcher),
@@ -829,6 +919,14 @@
}
+Matcher<Node*> IsEffectPhi(const Matcher<Node*>& effect0_matcher,
+ const Matcher<Node*>& effect1_matcher,
+ const Matcher<Node*>& merge_matcher) {
+ return MakeMatcher(
+ new IsEffectPhiMatcher(effect0_matcher, effect1_matcher, merge_matcher));
+}
+
+
Matcher<Node*> IsProjection(const Matcher<size_t>& index_matcher,
const Matcher<Node*>& base_matcher) {
return MakeMatcher(new IsProjectionMatcher(index_matcher, base_matcher));
@@ -838,11 +936,22 @@
Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher) {
+ return MakeMatcher(new IsCall2Matcher(descriptor_matcher, value0_matcher,
+ value1_matcher, effect_matcher,
+ control_matcher));
+}
+
+
+Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher,
+ const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& value2_matcher,
const Matcher<Node*>& value3_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher) {
- return MakeMatcher(new IsCallMatcher(
+ return MakeMatcher(new IsCall4Matcher(
descriptor_matcher, value0_matcher, value1_matcher, value2_matcher,
value3_matcher, effect_matcher, control_matcher));
}
diff --git a/test/unittests/compiler/node-test-utils.h b/test/unittests/compiler/node-test-utils.h
index 7f153bd..89fcc4b 100644
--- a/test/unittests/compiler/node-test-utils.h
+++ b/test/unittests/compiler/node-test-utils.h
@@ -56,11 +56,19 @@
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& merge_matcher);
+Matcher<Node*> IsEffectPhi(const Matcher<Node*>& effect0_matcher,
+ const Matcher<Node*>& effect1_matcher,
+ const Matcher<Node*>& merge_matcher);
Matcher<Node*> IsProjection(const Matcher<size_t>& index_matcher,
const Matcher<Node*>& base_matcher);
Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
+ const Matcher<Node*>& effect_matcher,
+ const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher,
+ const Matcher<Node*>& value0_matcher,
+ const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& value2_matcher,
const Matcher<Node*>& value3_matcher,
const Matcher<Node*>& effect_matcher,
diff --git a/test/unittests/compiler/register-allocator-unittest.cc b/test/unittests/compiler/register-allocator-unittest.cc
index 5c61708..752999f 100644
--- a/test/unittests/compiler/register-allocator-unittest.cc
+++ b/test/unittests/compiler/register-allocator-unittest.cc
@@ -15,29 +15,22 @@
namespace {
-static const char* general_register_names_[kMaxGeneralRegisters];
-static const char* double_register_names_[kMaxDoubleRegisters];
-static char register_names_[10 * (kMaxGeneralRegisters + kMaxDoubleRegisters)];
-
-
-static const char* GeneralRegisterName(int allocation_index) {
- return general_register_names_[allocation_index];
-}
-
-
-static const char* DoubleRegisterName(int allocation_index) {
- return double_register_names_[allocation_index];
-}
+static const char*
+ general_register_names_[RegisterConfiguration::kMaxGeneralRegisters];
+static const char*
+ double_register_names_[RegisterConfiguration::kMaxDoubleRegisters];
+static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters +
+ RegisterConfiguration::kMaxDoubleRegisters)];
static void InitializeRegisterNames() {
char* loc = register_names_;
- for (int i = 0; i < kMaxGeneralRegisters; ++i) {
+ for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) {
general_register_names_[i] = loc;
loc += base::OS::SNPrintF(loc, 100, "gp_%d", i);
*loc++ = 0;
}
- for (int i = 0; i < kMaxDoubleRegisters; ++i) {
+ for (int i = 0; i < RegisterConfiguration::kMaxDoubleRegisters; ++i) {
double_register_names_[i] = loc;
loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1;
*loc++ = 0;
@@ -54,15 +47,21 @@
static const int kDefaultNRegs = 4;
RegisterAllocatorTest()
- : basic_blocks_(zone()),
+ : num_general_registers_(kDefaultNRegs),
+ num_double_registers_(kDefaultNRegs),
+ basic_blocks_(zone()),
instruction_blocks_(zone()),
current_block_(NULL) {
InitializeRegisterNames();
- config_.num_general_registers_ = kDefaultNRegs;
- config_.num_double_registers_ = kDefaultNRegs;
- config_.num_aliased_double_registers_ = kDefaultNRegs;
- config_.GeneralRegisterName = GeneralRegisterName;
- config_.DoubleRegisterName = DoubleRegisterName;
+ }
+
+ RegisterConfiguration* config() {
+ if (config_.is_empty()) {
+ config_.Reset(new RegisterConfiguration(
+ num_general_registers_, num_double_registers_, num_double_registers_,
+ general_register_names_, double_register_names_));
+ }
+ return config_.get();
}
Frame* frame() {
@@ -82,7 +81,7 @@
RegisterAllocator* allocator() {
if (allocator_.is_empty()) {
allocator_.Reset(
- new RegisterAllocator(config_, zone(), frame(), sequence()));
+ new RegisterAllocator(config(), zone(), frame(), sequence()));
}
return allocator_.get();
}
@@ -118,12 +117,14 @@
void Allocate() {
if (FLAG_trace_alloc) {
OFStream os(stdout);
- os << "Before: " << std::endl << *sequence() << std::endl;
+ PrintableInstructionSequence printable = {config(), sequence()};
+ os << "Before: " << std::endl << printable << std::endl;
}
allocator()->Allocate();
if (FLAG_trace_alloc) {
OFStream os(stdout);
- os << "After: " << std::endl << *sequence() << std::endl;
+ PrintableInstructionSequence printable = {config(), sequence()};
+ os << "After: " << std::endl << printable << std::endl;
}
}
@@ -167,7 +168,9 @@
return op;
}
- RegisterAllocator::Config config_;
+ int num_general_registers_;
+ int num_double_registers_;
+ SmartPointer<RegisterConfiguration> config_;
ZoneVector<BasicBlock*> basic_blocks_;
InstructionBlocks instruction_blocks_;
InstructionBlock* current_block_;
diff --git a/test/unittests/unittests.gyp b/test/unittests/unittests.gyp
index b849c63..a881e46 100644
--- a/test/unittests/unittests.gyp
+++ b/test/unittests/unittests.gyp
@@ -39,6 +39,7 @@
'compiler/change-lowering-unittest.cc',
'compiler/common-operator-unittest.cc',
'compiler/compiler-test-utils.h',
+ 'compiler/diamond-unittest.cc',
'compiler/graph-reducer-unittest.cc',
'compiler/graph-unittest.cc',
'compiler/graph-unittest.h',
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 4f89bcf..5874865 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -411,6 +411,7 @@
'../../src/compiler/control-builders.h',
'../../src/compiler/control-reducer.cc',
'../../src/compiler/control-reducer.h',
+ '../../src/compiler/diamond.h',
'../../src/compiler/frame.h',
'../../src/compiler/gap-resolver.cc',
'../../src/compiler/gap-resolver.h',
@@ -484,6 +485,8 @@
'../../src/compiler/raw-machine-assembler.h',
'../../src/compiler/register-allocator.cc',
'../../src/compiler/register-allocator.h',
+ '../../src/compiler/register-configuration.cc',
+ '../../src/compiler/register-configuration.h',
'../../src/compiler/representation-change.h',
'../../src/compiler/schedule.cc',
'../../src/compiler/schedule.h',