Commit a17289f4 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

[turbofan] Drop broken StaticParameterTraits.

The StaticParameterTraits are broken by design, and cause way too much
trouble. The compilers usually pick the wrong specialization (i.e. the
default specialization is picked for Load and Phi even tho there is a
specialization for MachineType), which is not only the reason why GVN is
ineffective and slow, but can also lead to correctness issues in some
rare cases.

Also clean up some minor bugs/inconsistencies on the way.

TEST=cctest,unittests
R=svenpanne@chromium.org

Review URL: https://codereview.chromium.org/636893002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24437 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 304d91d2
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <cmath> #include <cmath>
#include "src/api.h" #include "src/api.h"
#include "src/base/cpu.h" #include "src/base/cpu.h"
#include "src/base/functional.h"
#include "src/base/lazy-instance.h" #include "src/base/lazy-instance.h"
#include "src/base/platform/platform.h" #include "src/base/platform/platform.h"
#include "src/builtins.h" #include "src/builtins.h"
...@@ -1521,6 +1522,29 @@ ExternalReference ExternalReference::debug_step_in_fp_address( ...@@ -1521,6 +1522,29 @@ ExternalReference ExternalReference::debug_step_in_fp_address(
} }
bool operator==(ExternalReference lhs, ExternalReference rhs) {
return lhs.address() == rhs.address();
}
bool operator!=(ExternalReference lhs, ExternalReference rhs) {
return !(lhs == rhs);
}
size_t hash_value(ExternalReference reference) {
return base::hash<Address>()(reference.address());
}
std::ostream& operator<<(std::ostream& os, ExternalReference reference) {
os << static_cast<const void*>(reference.address());
const Runtime::Function* fn = Runtime::FunctionForEntry(reference.address());
if (fn) os << "<" << fn->name << ".entry>";
return os;
}
void PositionsRecorder::RecordPosition(int pos) { void PositionsRecorder::RecordPosition(int pos) {
DCHECK(pos != RelocInfo::kNoPosition); DCHECK(pos != RelocInfo::kNoPosition);
DCHECK(pos >= 0); DCHECK(pos >= 0);
......
...@@ -959,14 +959,6 @@ class ExternalReference BASE_EMBEDDED { ...@@ -959,14 +959,6 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference stress_deopt_count(Isolate* isolate); static ExternalReference stress_deopt_count(Isolate* isolate);
bool operator==(const ExternalReference& other) const {
return address_ == other.address_;
}
bool operator!=(const ExternalReference& other) const {
return !(*this == other);
}
private: private:
explicit ExternalReference(void* address) explicit ExternalReference(void* address)
: address_(address) {} : address_(address) {}
...@@ -987,6 +979,13 @@ class ExternalReference BASE_EMBEDDED { ...@@ -987,6 +979,13 @@ class ExternalReference BASE_EMBEDDED {
void* address_; void* address_;
}; };
bool operator==(ExternalReference, ExternalReference);
bool operator!=(ExternalReference, ExternalReference);
size_t hash_value(ExternalReference);
std::ostream& operator<<(std::ostream&, ExternalReference);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Position recording support // Position recording support
......
...@@ -24,35 +24,51 @@ class ControlOperator : public Operator1<int> { ...@@ -24,35 +24,51 @@ class ControlOperator : public Operator1<int> {
: Operator1<int>(opcode, properties, inputs, outputs, mnemonic, : Operator1<int>(opcode, properties, inputs, outputs, mnemonic,
controls) {} controls) {}
virtual std::ostream& PrintParameter(std::ostream& os) const FINAL { virtual void PrintParameter(std::ostream& os) const FINAL {}
return os;
}
}; };
} // namespace } // namespace
// Specialization for static parameters of type {ExternalReference}. size_t hash_value(OutputFrameStateCombine const& sc) {
template <> return base::hash_combine(sc.kind_, sc.parameter_);
struct StaticParameterTraits<ExternalReference> { }
static std::ostream& PrintTo(std::ostream& os, ExternalReference reference) {
os << static_cast<const void*>(reference.address());
// TODO(bmeurer): Move to operator<<(os, ExternalReference) std::ostream& operator<<(std::ostream& os, OutputFrameStateCombine const& sc) {
const Runtime::Function* function = switch (sc.kind_) {
Runtime::FunctionForEntry(reference.address()); case OutputFrameStateCombine::kPushOutput:
if (function) { if (sc.parameter_ == 0) return os << "Ignore";
os << " <" << function->name << ".entry>"; return os << "Push(" << sc.parameter_ << ")";
case OutputFrameStateCombine::kPokeAt:
return os << "PokeAt(" << sc.parameter_ << ")";
} }
UNREACHABLE();
return os; return os;
} }
static int HashCode(ExternalReference reference) {
return bit_cast<int>(static_cast<uint32_t>(
reinterpret_cast<uintptr_t>(reference.address()))); bool operator==(FrameStateCallInfo const& lhs, FrameStateCallInfo const& rhs) {
} return lhs.type() == rhs.type() && lhs.bailout_id() == rhs.bailout_id() &&
static bool Equals(ExternalReference lhs, ExternalReference rhs) { lhs.state_combine() == rhs.state_combine();
return lhs == rhs; }
}
};
bool operator!=(FrameStateCallInfo const& lhs, FrameStateCallInfo const& rhs) {
return !(lhs == rhs);
}
size_t hash_value(FrameStateCallInfo const& info) {
return base::hash_combine(info.type(), info.bailout_id(),
info.state_combine());
}
std::ostream& operator<<(std::ostream& os, FrameStateCallInfo const& info) {
return os << info.type() << ", " << info.bailout_id() << ", "
<< info.state_combine();
}
#define SHARED_OP_LIST(V) \ #define SHARED_OP_LIST(V) \
...@@ -162,8 +178,8 @@ const Operator* CommonOperatorBuilder::NumberConstant(volatile double value) { ...@@ -162,8 +178,8 @@ const Operator* CommonOperatorBuilder::NumberConstant(volatile double value) {
const Operator* CommonOperatorBuilder::HeapConstant( const Operator* CommonOperatorBuilder::HeapConstant(
const Unique<Object>& value) { const Unique<HeapObject>& value) {
return new (zone()) Operator1<Unique<Object> >( return new (zone()) Operator1<Unique<HeapObject>>(
IrOpcode::kHeapConstant, Operator::kPure, 0, 1, "HeapConstant", value); IrOpcode::kHeapConstant, Operator::kPure, 0, 1, "HeapConstant", value);
} }
...@@ -184,8 +200,8 @@ const Operator* CommonOperatorBuilder::EffectPhi(int arguments) { ...@@ -184,8 +200,8 @@ const Operator* CommonOperatorBuilder::EffectPhi(int arguments) {
const Operator* CommonOperatorBuilder::ValueEffect(int arguments) { const Operator* CommonOperatorBuilder::ValueEffect(int arguments) {
DCHECK(arguments > 0); // Disallow empty value effects. DCHECK(arguments > 0); // Disallow empty value effects.
return new (zone()) SimpleOperator(IrOpcode::kValueEffect, Operator::kPure, return new (zone()) Operator1<int>(IrOpcode::kValueEffect, Operator::kPure,
arguments, 0, "ValueEffect"); arguments, 0, "ValueEffect", arguments);
} }
...@@ -224,8 +240,8 @@ const Operator* CommonOperatorBuilder::Call(const CallDescriptor* descriptor) { ...@@ -224,8 +240,8 @@ const Operator* CommonOperatorBuilder::Call(const CallDescriptor* descriptor) {
static_cast<int>(descriptor->ReturnCount()), mnemonic, static_cast<int>(descriptor->ReturnCount()), mnemonic,
descriptor) {} descriptor) {}
virtual std::ostream& PrintParameter(std::ostream& os) const OVERRIDE { virtual void PrintParameter(std::ostream& os) const OVERRIDE {
return os << "[" << *parameter() << "]"; os << "[" << *parameter() << "]";
} }
}; };
return new (zone()) CallOperator(descriptor, "Call"); return new (zone()) CallOperator(descriptor, "Call");
...@@ -237,50 +253,6 @@ const Operator* CommonOperatorBuilder::Projection(size_t index) { ...@@ -237,50 +253,6 @@ const Operator* CommonOperatorBuilder::Projection(size_t index) {
1, 1, "Projection", index); 1, 1, "Projection", index);
} }
OutputFrameStateCombine::OutputFrameStateCombine(CombineKind kind,
size_t parameter)
: kind_(kind), parameter_(parameter) {}
// static
OutputFrameStateCombine OutputFrameStateCombine::Ignore() {
return OutputFrameStateCombine(kPushOutput, 0);
}
// static
OutputFrameStateCombine OutputFrameStateCombine::Push(size_t count) {
return OutputFrameStateCombine(kPushOutput, count);
}
// static
OutputFrameStateCombine OutputFrameStateCombine::PokeAt(size_t index) {
return OutputFrameStateCombine(kPokeAt, index);
}
OutputFrameStateCombine::CombineKind OutputFrameStateCombine::kind() {
return kind_;
}
size_t OutputFrameStateCombine::GetPushCount() {
DCHECK(kind() == kPushOutput);
return parameter_;
}
size_t OutputFrameStateCombine::GetOffsetToPokeAt() {
DCHECK(kind() == kPokeAt);
return parameter_;
}
bool OutputFrameStateCombine::IsOutputIgnored() {
return kind() == kPushOutput && GetPushCount() == 0;
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -27,27 +27,53 @@ class Operator; ...@@ -27,27 +27,53 @@ class Operator;
// the output of a node to obtain a framestate for lazy bailout. // the output of a node to obtain a framestate for lazy bailout.
class OutputFrameStateCombine { class OutputFrameStateCombine {
public: public:
enum CombineKind { enum Kind {
kPushOutput, // Push the output on the expression stack. kPushOutput, // Push the output on the expression stack.
kPokeAt // Poke at the given environment location, kPokeAt // Poke at the given environment location,
// counting from the top of the stack. // counting from the top of the stack.
}; };
static OutputFrameStateCombine Ignore(); static OutputFrameStateCombine Ignore() {
static OutputFrameStateCombine Push(size_t count = 1); return OutputFrameStateCombine(kPushOutput, 0);
static OutputFrameStateCombine PokeAt(size_t index); }
static OutputFrameStateCombine Push(size_t count = 1) {
CombineKind kind(); return OutputFrameStateCombine(kPushOutput, count);
size_t GetPushCount(); }
size_t GetOffsetToPokeAt(); static OutputFrameStateCombine PokeAt(size_t index) {
return OutputFrameStateCombine(kPokeAt, index);
bool IsOutputIgnored(); }
Kind kind() const { return kind_; }
size_t GetPushCount() const {
DCHECK_EQ(kPushOutput, kind());
return parameter_;
}
size_t GetOffsetToPokeAt() const {
DCHECK_EQ(kPokeAt, kind());
return parameter_;
}
bool IsOutputIgnored() const {
return kind_ == kPushOutput && parameter_ == 0;
}
bool operator==(OutputFrameStateCombine const& other) const {
return kind_ == other.kind_ && parameter_ == other.parameter_;
}
bool operator!=(OutputFrameStateCombine const& other) const {
return !(*this == other);
}
friend size_t hash_value(OutputFrameStateCombine const&);
friend std::ostream& operator<<(std::ostream&,
OutputFrameStateCombine const&);
private: private:
OutputFrameStateCombine(CombineKind kind, size_t parameter); OutputFrameStateCombine(Kind kind, size_t parameter)
: kind_(kind), parameter_(parameter) {}
CombineKind kind_; Kind const kind_;
size_t parameter_; size_t const parameter_;
}; };
...@@ -81,6 +107,13 @@ class FrameStateCallInfo FINAL { ...@@ -81,6 +107,13 @@ class FrameStateCallInfo FINAL {
MaybeHandle<JSFunction> jsfunction_; MaybeHandle<JSFunction> jsfunction_;
}; };
bool operator==(FrameStateCallInfo const&, FrameStateCallInfo const&);
bool operator!=(FrameStateCallInfo const&, FrameStateCallInfo const&);
size_t hash_value(FrameStateCallInfo const&);
std::ostream& operator<<(std::ostream&, FrameStateCallInfo const&);
// Interface for building common operators that can be used at any level of IR, // Interface for building common operators that can be used at any level of IR,
// including JavaScript, mid-level, and low-level. // including JavaScript, mid-level, and low-level.
...@@ -107,7 +140,7 @@ class CommonOperatorBuilder FINAL { ...@@ -107,7 +140,7 @@ class CommonOperatorBuilder FINAL {
const Operator* Float64Constant(volatile double); const Operator* Float64Constant(volatile double);
const Operator* ExternalConstant(const ExternalReference&); const Operator* ExternalConstant(const ExternalReference&);
const Operator* NumberConstant(volatile double); const Operator* NumberConstant(volatile double);
const Operator* HeapConstant(const Unique<Object>&); const Operator* HeapConstant(const Unique<HeapObject>&);
const Operator* Phi(MachineType type, int arguments); const Operator* Phi(MachineType type, int arguments);
const Operator* EffectPhi(int arguments); const Operator* EffectPhi(int arguments);
......
...@@ -10,8 +10,8 @@ namespace v8 { ...@@ -10,8 +10,8 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
Node* JSGraph::ImmovableHeapConstant(Handle<Object> object) { Node* JSGraph::ImmovableHeapConstant(Handle<HeapObject> object) {
Unique<Object> unique = Unique<Object>::CreateImmovable(object); Unique<HeapObject> unique = Unique<HeapObject>::CreateImmovable(object);
return NewNode(common()->HeapConstant(unique)); return NewNode(common()->HeapConstant(unique));
} }
...@@ -93,13 +93,13 @@ Node* JSGraph::NaNConstant() { ...@@ -93,13 +93,13 @@ Node* JSGraph::NaNConstant() {
} }
Node* JSGraph::HeapConstant(Unique<Object> value) { Node* JSGraph::HeapConstant(Unique<HeapObject> value) {
// TODO(turbofan): canonicalize heap constants using Unique<T> // TODO(turbofan): canonicalize heap constants using Unique<T>
return NewNode(common()->HeapConstant(value)); return NewNode(common()->HeapConstant(value));
} }
Node* JSGraph::HeapConstant(Handle<Object> value) { Node* JSGraph::HeapConstant(Handle<HeapObject> value) {
// TODO(titzer): We could also match against the addresses of immortable // TODO(titzer): We could also match against the addresses of immortable
// immovables here, even without access to the heap, thus always // immovables here, even without access to the heap, thus always
// canonicalizing references to them. // canonicalizing references to them.
...@@ -107,7 +107,8 @@ Node* JSGraph::HeapConstant(Handle<Object> value) { ...@@ -107,7 +107,8 @@ Node* JSGraph::HeapConstant(Handle<Object> value) {
// TODO(turbofan): This is a work-around to make Unique::HashCode() work for // TODO(turbofan): This is a work-around to make Unique::HashCode() work for
// value numbering. We need some sane way to compute a unique hash code for // value numbering. We need some sane way to compute a unique hash code for
// arbitrary handles here. // arbitrary handles here.
Unique<Object> unique(reinterpret_cast<Address>(*value.location()), value); Unique<HeapObject> unique(reinterpret_cast<Address>(*value.location()),
value);
return HeapConstant(unique); return HeapConstant(unique);
} }
...@@ -128,7 +129,7 @@ Node* JSGraph::Constant(Handle<Object> value) { ...@@ -128,7 +129,7 @@ Node* JSGraph::Constant(Handle<Object> value) {
} else if (value->IsTheHole()) { } else if (value->IsTheHole()) {
return TheHoleConstant(); return TheHoleConstant();
} else { } else {
return HeapConstant(value); return HeapConstant(Handle<HeapObject>::cast(value));
} }
} }
......
...@@ -46,11 +46,11 @@ class JSGraph : public ZoneObject { ...@@ -46,11 +46,11 @@ class JSGraph : public ZoneObject {
// Creates a HeapConstant node, possibly canonicalized, without inspecting the // Creates a HeapConstant node, possibly canonicalized, without inspecting the
// object. // object.
Node* HeapConstant(Unique<Object> value); Node* HeapConstant(Unique<HeapObject> value);
// Creates a HeapConstant node, possibly canonicalized, and may access the // Creates a HeapConstant node, possibly canonicalized, and may access the
// heap to inspect the object. // heap to inspect the object.
Node* HeapConstant(Handle<Object> value); Node* HeapConstant(Handle<HeapObject> value);
// Creates a Constant node of the appropriate type for the given object. // Creates a Constant node of the appropriate type for the given object.
// Accesses the heap to inspect the object and determine whether one of the // Accesses the heap to inspect the object and determine whether one of the
...@@ -109,7 +109,7 @@ class JSGraph : public ZoneObject { ...@@ -109,7 +109,7 @@ class JSGraph : public ZoneObject {
CommonNodeCache cache_; CommonNodeCache cache_;
Node* ImmovableHeapConstant(Handle<Object> value); Node* ImmovableHeapConstant(Handle<HeapObject> value);
Node* NumberConstant(double value); Node* NumberConstant(double value);
Node* NewNode(const Operator* op); Node* NewNode(const Operator* op);
......
...@@ -14,12 +14,56 @@ namespace v8 { ...@@ -14,12 +14,56 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
bool operator==(CallFunctionParameters const& lhs,
CallFunctionParameters const& rhs) {
return lhs.arity() == rhs.arity() && lhs.flags() == rhs.flags();
}
bool operator!=(CallFunctionParameters const& lhs,
CallFunctionParameters const& rhs) {
return !(lhs == rhs);
}
size_t hash_value(CallFunctionParameters const& p) {
return base::hash_combine(p.arity(), p.flags());
}
std::ostream& operator<<(std::ostream& os, CallFunctionParameters const& p) {
return os << p.arity() << ", " << p.flags();
}
const CallFunctionParameters& CallFunctionParametersOf(const Operator* op) { const CallFunctionParameters& CallFunctionParametersOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kJSCallFunction, op->opcode()); DCHECK_EQ(IrOpcode::kJSCallFunction, op->opcode());
return OpParameter<CallFunctionParameters>(op); return OpParameter<CallFunctionParameters>(op);
} }
bool operator==(CallRuntimeParameters const& lhs,
CallRuntimeParameters const& rhs) {
return lhs.id() == rhs.id() && lhs.arity() == rhs.arity();
}
bool operator!=(CallRuntimeParameters const& lhs,
CallRuntimeParameters const& rhs) {
return !(lhs == rhs);
}
size_t hash_value(CallRuntimeParameters const& p) {
return base::hash_combine(p.id(), p.arity());
}
std::ostream& operator<<(std::ostream& os, CallRuntimeParameters const& p) {
return os << p.id() << ", " << p.arity();
}
const CallRuntimeParameters& CallRuntimeParametersOf(const Operator* op) { const CallRuntimeParameters& CallRuntimeParametersOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kJSCallRuntime, op->opcode()); DCHECK_EQ(IrOpcode::kJSCallRuntime, op->opcode());
return OpParameter<CallRuntimeParameters>(op); return OpParameter<CallRuntimeParameters>(op);
...@@ -35,64 +79,90 @@ ContextAccess::ContextAccess(size_t depth, size_t index, bool immutable) ...@@ -35,64 +79,90 @@ ContextAccess::ContextAccess(size_t depth, size_t index, bool immutable)
} }
bool operator==(const ContextAccess& lhs, const ContextAccess& rhs) { bool operator==(ContextAccess const& lhs, ContextAccess const& rhs) {
return lhs.depth() == rhs.depth() && lhs.index() == rhs.index() && return lhs.depth() == rhs.depth() && lhs.index() == rhs.index() &&
lhs.immutable() == rhs.immutable(); lhs.immutable() == rhs.immutable();
} }
bool operator!=(const ContextAccess& lhs, const ContextAccess& rhs) { bool operator!=(ContextAccess const& lhs, ContextAccess const& rhs) {
return !(lhs == rhs); return !(lhs == rhs);
} }
const ContextAccess& ContextAccessOf(const Operator* op) { size_t hash_value(ContextAccess const& access) {
return base::hash_combine(access.depth(), access.index(), access.immutable());
}
std::ostream& operator<<(std::ostream& os, ContextAccess const& access) {
return os << access.depth() << ", " << access.index() << ", "
<< access.immutable();
}
ContextAccess const& ContextAccessOf(Operator const* op) {
DCHECK(op->opcode() == IrOpcode::kJSLoadContext || DCHECK(op->opcode() == IrOpcode::kJSLoadContext ||
op->opcode() == IrOpcode::kJSStoreContext); op->opcode() == IrOpcode::kJSStoreContext);
return OpParameter<ContextAccess>(op); return OpParameter<ContextAccess>(op);
} }
bool operator==(LoadNamedParameters const& lhs,
LoadNamedParameters const& rhs) {
return lhs.name() == rhs.name() &&
lhs.contextual_mode() == rhs.contextual_mode();
}
bool operator!=(LoadNamedParameters const& lhs,
LoadNamedParameters const& rhs) {
return !(lhs == rhs);
}
size_t hash_value(LoadNamedParameters const& p) {
return base::hash_combine(p.name(), p.contextual_mode());
}
std::ostream& operator<<(std::ostream& os, LoadNamedParameters const& p) {
return os << Brief(*p.name().handle()) << ", " << p.contextual_mode();
}
const LoadNamedParameters& LoadNamedParametersOf(const Operator* op) { const LoadNamedParameters& LoadNamedParametersOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kJSLoadNamed, op->opcode()); DCHECK_EQ(IrOpcode::kJSLoadNamed, op->opcode());
return OpParameter<LoadNamedParameters>(op); return OpParameter<LoadNamedParameters>(op);
} }
const StoreNamedParameters& StoreNamedParametersOf(const Operator* op) { bool operator==(StoreNamedParameters const& lhs,
DCHECK_EQ(IrOpcode::kJSStoreNamed, op->opcode()); StoreNamedParameters const& rhs) {
return OpParameter<StoreNamedParameters>(op); return lhs.strict_mode() == rhs.strict_mode() && lhs.name() == rhs.name();
} }
// Specialization for static parameters of type {ContextAccess}. bool operator!=(StoreNamedParameters const& lhs,
template <> StoreNamedParameters const& rhs) {
struct StaticParameterTraits<ContextAccess> { return !(lhs == rhs);
static std::ostream& PrintTo(std::ostream& os, const ContextAccess& access) { }
return os << access.depth() << "," << access.index()
<< (access.immutable() ? ",imm" : "");
}
static int HashCode(const ContextAccess& access) {
return static_cast<int>((access.depth() << 16) | (access.index() & 0xffff));
}
static bool Equals(const ContextAccess& lhs, const ContextAccess& rhs) {
return lhs == rhs;
}
};
// Specialization for static parameters of type {Runtime::FunctionId}. size_t hash_value(StoreNamedParameters const& p) {
template <> return base::hash_combine(p.strict_mode(), p.name());
struct StaticParameterTraits<Runtime::FunctionId> { }
static std::ostream& PrintTo(std::ostream& os, Runtime::FunctionId val) {
const Runtime::Function* f = Runtime::FunctionForId(val);
return os << (f->name ? f->name : "?Runtime?"); std::ostream& operator<<(std::ostream& os, StoreNamedParameters const& p) {
} return os << p.strict_mode() << ", " << Brief(*p.name().handle());
static int HashCode(Runtime::FunctionId val) { return static_cast<int>(val); } }
static bool Equals(Runtime::FunctionId a, Runtime::FunctionId b) {
return a == b;
} const StoreNamedParameters& StoreNamedParametersOf(const Operator* op) {
}; DCHECK_EQ(IrOpcode::kJSStoreNamed, op->opcode());
return OpParameter<StoreNamedParameters>(op);
}
#define SHARED_OP_LIST(V) \ #define SHARED_OP_LIST(V) \
...@@ -241,8 +311,8 @@ const Operator* JSOperatorBuilder::StoreContext(size_t depth, size_t index) { ...@@ -241,8 +311,8 @@ const Operator* JSOperatorBuilder::StoreContext(size_t depth, size_t index) {
const Operator* JSOperatorBuilder::CreateCatchContext( const Operator* JSOperatorBuilder::CreateCatchContext(
const Unique<String>& name) { const Unique<String>& name) {
return new (zone()) Operator1<Unique<String> >( return new (zone()) Operator1<Unique<String>>(IrOpcode::kJSCreateCatchContext,
IrOpcode::kJSCreateCatchContext, Operator::kNoProperties, 1, 1, Operator::kNoProperties, 1, 1,
"JSCreateCatchContext", name); "JSCreateCatchContext", name);
} }
......
...@@ -32,6 +32,13 @@ class CallFunctionParameters FINAL { ...@@ -32,6 +32,13 @@ class CallFunctionParameters FINAL {
const CallFunctionFlags flags_; const CallFunctionFlags flags_;
}; };
bool operator==(CallFunctionParameters const&, CallFunctionParameters const&);
bool operator!=(CallFunctionParameters const&, CallFunctionParameters const&);
size_t hash_value(CallFunctionParameters const&);
std::ostream& operator<<(std::ostream&, CallFunctionParameters const&);
const CallFunctionParameters& CallFunctionParametersOf(const Operator* op); const CallFunctionParameters& CallFunctionParametersOf(const Operator* op);
...@@ -50,6 +57,13 @@ class CallRuntimeParameters FINAL { ...@@ -50,6 +57,13 @@ class CallRuntimeParameters FINAL {
const size_t arity_; const size_t arity_;
}; };
bool operator==(CallRuntimeParameters const&, CallRuntimeParameters const&);
bool operator!=(CallRuntimeParameters const&, CallRuntimeParameters const&);
size_t hash_value(CallRuntimeParameters const&);
std::ostream& operator<<(std::ostream&, CallRuntimeParameters const&);
const CallRuntimeParameters& CallRuntimeParametersOf(const Operator* op); const CallRuntimeParameters& CallRuntimeParametersOf(const Operator* op);
...@@ -72,10 +86,14 @@ class ContextAccess FINAL { ...@@ -72,10 +86,14 @@ class ContextAccess FINAL {
const uint32_t index_; const uint32_t index_;
}; };
bool operator==(const ContextAccess& lhs, const ContextAccess& rhs); bool operator==(ContextAccess const&, ContextAccess const&);
bool operator!=(const ContextAccess& lhs, const ContextAccess& rhs); bool operator!=(ContextAccess const&, ContextAccess const&);
size_t hash_value(ContextAccess const&);
const ContextAccess& ContextAccessOf(const Operator* op); std::ostream& operator<<(std::ostream&, ContextAccess const&);
ContextAccess const& ContextAccessOf(Operator const*);
// Defines the property being loaded from an object by a named load. This is // Defines the property being loaded from an object by a named load. This is
...@@ -93,6 +111,13 @@ class LoadNamedParameters FINAL { ...@@ -93,6 +111,13 @@ class LoadNamedParameters FINAL {
const ContextualMode contextual_mode_; const ContextualMode contextual_mode_;
}; };
bool operator==(LoadNamedParameters const&, LoadNamedParameters const&);
bool operator!=(LoadNamedParameters const&, LoadNamedParameters const&);
size_t hash_value(LoadNamedParameters const&);
std::ostream& operator<<(std::ostream&, LoadNamedParameters const&);
const LoadNamedParameters& LoadNamedParametersOf(const Operator* op); const LoadNamedParameters& LoadNamedParametersOf(const Operator* op);
...@@ -111,6 +136,13 @@ class StoreNamedParameters FINAL { ...@@ -111,6 +136,13 @@ class StoreNamedParameters FINAL {
const Unique<Name> name_; const Unique<Name> name_;
}; };
bool operator==(StoreNamedParameters const&, StoreNamedParameters const&);
bool operator!=(StoreNamedParameters const&, StoreNamedParameters const&);
size_t hash_value(StoreNamedParameters const&);
std::ostream& operator<<(std::ostream&, StoreNamedParameters const&);
const StoreNamedParameters& StoreNamedParametersOf(const Operator* op); const StoreNamedParameters& StoreNamedParametersOf(const Operator* op);
......
...@@ -12,9 +12,8 @@ namespace v8 { ...@@ -12,9 +12,8 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
std::ostream& operator<<(std::ostream& os, std::ostream& operator<<(std::ostream& os, WriteBarrierKind kind) {
const WriteBarrierKind& write_barrier_kind) { switch (kind) {
switch (write_barrier_kind) {
case kNoWriteBarrier: case kNoWriteBarrier:
return os << "NoWriteBarrier"; return os << "NoWriteBarrier";
case kFullWriteBarrier: case kFullWriteBarrier:
...@@ -25,39 +24,26 @@ std::ostream& operator<<(std::ostream& os, ...@@ -25,39 +24,26 @@ std::ostream& operator<<(std::ostream& os,
} }
std::ostream& operator<<(std::ostream& os, const StoreRepresentation& rep) { bool operator==(StoreRepresentation lhs, StoreRepresentation rhs) {
return os << "(" << rep.machine_type() << " : " << rep.write_barrier_kind() return lhs.machine_type() == rhs.machine_type() &&
<< ")"; lhs.write_barrier_kind() == rhs.write_barrier_kind();
} }
template <> bool operator!=(StoreRepresentation lhs, StoreRepresentation rhs) {
struct StaticParameterTraits<StoreRepresentation> { return !(lhs == rhs);
static std::ostream& PrintTo(std::ostream& os, }
const StoreRepresentation& rep) {
return os << rep;
}
static int HashCode(const StoreRepresentation& rep) {
return rep.machine_type() + rep.write_barrier_kind();
}
static bool Equals(const StoreRepresentation& rep1,
const StoreRepresentation& rep2) {
return rep1 == rep2;
}
};
template <> size_t hash_value(StoreRepresentation rep) {
struct StaticParameterTraits<LoadRepresentation> { return base::hash_combine(rep.machine_type(), rep.write_barrier_kind());
static std::ostream& PrintTo(std::ostream& os, }
LoadRepresentation type) { // NOLINT
return os << type;
} std::ostream& operator<<(std::ostream& os, StoreRepresentation rep) {
static int HashCode(LoadRepresentation type) { return type; } return os << "(" << rep.machine_type() << " : " << rep.write_barrier_kind()
static bool Equals(LoadRepresentation lhs, LoadRepresentation rhs) { << ")";
return lhs == rhs; }
}
};
#define PURE_OP_LIST(V) \ #define PURE_OP_LIST(V) \
......
...@@ -19,15 +19,15 @@ class Operator; ...@@ -19,15 +19,15 @@ class Operator;
// Supported write barrier modes. // Supported write barrier modes.
enum WriteBarrierKind { kNoWriteBarrier, kFullWriteBarrier }; enum WriteBarrierKind { kNoWriteBarrier, kFullWriteBarrier };
std::ostream& operator<<(std::ostream& os, std::ostream& operator<<(std::ostream& os, WriteBarrierKind);
const WriteBarrierKind& write_barrier_kind);
// A Load needs a MachineType.
typedef MachineType LoadRepresentation; typedef MachineType LoadRepresentation;
// A Store needs a MachineType and a WriteBarrierKind // A Store needs a MachineType and a WriteBarrierKind in order to emit the
// in order to emit the correct write barrier. // correct write barrier.
class StoreRepresentation FINAL { class StoreRepresentation FINAL {
public: public:
StoreRepresentation(MachineType machine_type, StoreRepresentation(MachineType machine_type,
...@@ -42,18 +42,12 @@ class StoreRepresentation FINAL { ...@@ -42,18 +42,12 @@ class StoreRepresentation FINAL {
WriteBarrierKind write_barrier_kind_; WriteBarrierKind write_barrier_kind_;
}; };
inline bool operator==(const StoreRepresentation& rep1, bool operator==(StoreRepresentation, StoreRepresentation);
const StoreRepresentation& rep2) { bool operator!=(StoreRepresentation, StoreRepresentation);
return rep1.machine_type() == rep2.machine_type() &&
rep1.write_barrier_kind() == rep2.write_barrier_kind();
}
inline bool operator!=(const StoreRepresentation& rep1, size_t hash_value(StoreRepresentation);
const StoreRepresentation& rep2) {
return !(rep1 == rep2);
}
std::ostream& operator<<(std::ostream& os, const StoreRepresentation& rep); std::ostream& operator<<(std::ostream&, StoreRepresentation);
// Interface for building machine-level operators. These operators are // Interface for building machine-level operators. These operators are
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "src/compiler/node.h" #include "src/compiler/node.h"
#include "src/compiler/operator.h" #include "src/compiler/operator.h"
#include "src/unique.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
......
...@@ -42,11 +42,6 @@ Node* Node::FindProjection(size_t projection_index) { ...@@ -42,11 +42,6 @@ Node* Node::FindProjection(size_t projection_index) {
} }
std::ostream& operator<<(std::ostream& os, const Operator& op) {
return op.PrintTo(os);
}
std::ostream& operator<<(std::ostream& os, const Node& n) { std::ostream& operator<<(std::ostream& os, const Node& n) {
os << n.id() << ": " << *n.op(); os << n.id() << ": " << *n.op();
if (n.op()->InputCount() != 0) { if (n.op()->InputCount() != 0) {
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "src/compiler/operator.h" #include "src/compiler/operator.h"
#include <limits>
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
...@@ -11,16 +13,44 @@ namespace compiler { ...@@ -11,16 +13,44 @@ namespace compiler {
Operator::~Operator() {} Operator::~Operator() {}
std::ostream& operator<<(std::ostream& os, const Operator& op) {
op.PrintTo(os);
return os;
}
SimpleOperator::SimpleOperator(Opcode opcode, Properties properties, SimpleOperator::SimpleOperator(Opcode opcode, Properties properties,
int input_count, int output_count, size_t input_count, size_t output_count,
const char* mnemonic) const char* mnemonic)
: Operator(opcode, properties, mnemonic), : Operator(opcode, properties, mnemonic),
input_count_(input_count), input_count_(static_cast<uint8_t>(input_count)),
output_count_(output_count) {} output_count_(static_cast<uint8_t>(output_count)) {
DCHECK(input_count <= std::numeric_limits<uint8_t>::max());
DCHECK(output_count <= std::numeric_limits<uint8_t>::max());
}
SimpleOperator::~SimpleOperator() {} SimpleOperator::~SimpleOperator() {}
bool SimpleOperator::Equals(const Operator* that) const {
return opcode() == that->opcode();
}
size_t SimpleOperator::HashCode() const {
return base::hash<Opcode>()(opcode());
}
int SimpleOperator::InputCount() const { return input_count_; }
int SimpleOperator::OutputCount() const { return output_count_; }
void SimpleOperator::PrintTo(std::ostream& os) const { os << mnemonic(); }
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -5,9 +5,11 @@ ...@@ -5,9 +5,11 @@
#ifndef V8_COMPILER_OPERATOR_H_ #ifndef V8_COMPILER_OPERATOR_H_
#define V8_COMPILER_OPERATOR_H_ #define V8_COMPILER_OPERATOR_H_
#include <ostream> // NOLINT(readability/streams)
#include "src/base/flags.h" #include "src/base/flags.h"
#include "src/ostreams.h" #include "src/base/functional.h"
#include "src/unique.h" #include "src/zone.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -63,12 +65,12 @@ class Operator : public ZoneObject { ...@@ -63,12 +65,12 @@ class Operator : public ZoneObject {
// Check if this operator equals another operator. Equivalent operators can // Check if this operator equals another operator. Equivalent operators can
// be merged, and nodes with equivalent operators and equivalent inputs // be merged, and nodes with equivalent operators and equivalent inputs
// can be merged. // can be merged.
virtual bool Equals(const Operator* other) const = 0; virtual bool Equals(const Operator*) const = 0;
// Compute a hashcode to speed up equivalence-set checking. // Compute a hashcode to speed up equivalence-set checking.
// Equal operators should always have equal hashcodes, and unequal operators // Equal operators should always have equal hashcodes, and unequal operators
// should have unequal hashcodes with high probability. // should have unequal hashcodes with high probability.
virtual int HashCode() const = 0; virtual size_t HashCode() const = 0;
// Check whether this operator has the given property. // Check whether this operator has the given property.
bool HasProperty(Property property) const { bool HasProperty(Property property) const {
...@@ -87,7 +89,7 @@ class Operator : public ZoneObject { ...@@ -87,7 +89,7 @@ class Operator : public ZoneObject {
protected: protected:
// Print the full operator into the given stream, including any // Print the full operator into the given stream, including any
// static parameters. Useful for debugging and visualizing the IR. // static parameters. Useful for debugging and visualizing the IR.
virtual std::ostream& PrintTo(std::ostream& os) const = 0; // NOLINT virtual void PrintTo(std::ostream& os) const = 0; // NOLINT
friend std::ostream& operator<<(std::ostream& os, const Operator& op); friend std::ostream& operator<<(std::ostream& os, const Operator& op);
private: private:
...@@ -102,159 +104,82 @@ DEFINE_OPERATORS_FOR_FLAGS(Operator::Properties) ...@@ -102,159 +104,82 @@ DEFINE_OPERATORS_FOR_FLAGS(Operator::Properties)
std::ostream& operator<<(std::ostream& os, const Operator& op); std::ostream& operator<<(std::ostream& os, const Operator& op);
// An implementation of Operator that has no static parameters. Such operators // An implementation of Operator that has no static parameters. Such operators
// have just a name, an opcode, and a fixed number of inputs and outputs. // have just a name, an opcode, and a fixed number of inputs and outputs.
// They can represented by singletons and shared globally. // They can represented by singletons and shared globally.
class SimpleOperator : public Operator { class SimpleOperator : public Operator {
public: public:
SimpleOperator(Opcode opcode, Properties properties, int input_count, SimpleOperator(Opcode opcode, Properties properties, size_t input_count,
int output_count, const char* mnemonic); size_t output_count, const char* mnemonic);
~SimpleOperator(); ~SimpleOperator();
virtual bool Equals(const Operator* that) const FINAL { virtual bool Equals(const Operator* that) const FINAL;
return opcode() == that->opcode(); virtual size_t HashCode() const FINAL;
} virtual int InputCount() const FINAL;
virtual int HashCode() const FINAL { return opcode(); } virtual int OutputCount() const FINAL;
virtual int InputCount() const FINAL { return input_count_; }
virtual int OutputCount() const FINAL { return output_count_; }
private: private:
virtual std::ostream& PrintTo(std::ostream& os) const FINAL { // NOLINT virtual void PrintTo(std::ostream& os) const FINAL;
return os << mnemonic();
}
int input_count_; uint8_t input_count_;
int output_count_; uint8_t output_count_;
DISALLOW_COPY_AND_ASSIGN(SimpleOperator); DISALLOW_COPY_AND_ASSIGN(SimpleOperator);
}; };
// Template specialization implements a kind of type class for dealing with the
// static parameters of Operator1 automatically.
template <typename T>
struct StaticParameterTraits {
static std::ostream& PrintTo(std::ostream& os, T val) { // NOLINT
return os << "??";
}
static int HashCode(T a) { return 0; }
static bool Equals(T a, T b) {
return false; // Not every T has a ==. By default, be conservative.
}
};
// Specialization for static parameters of type {int}.
template <>
struct StaticParameterTraits<int> {
static std::ostream& PrintTo(std::ostream& os, int val) { // NOLINT
return os << val;
}
static int HashCode(int a) { return a; }
static bool Equals(int a, int b) { return a == b; }
};
// Specialization for static parameters of type {double}.
template <>
struct StaticParameterTraits<double> {
static std::ostream& PrintTo(std::ostream& os, double val) { // NOLINT
return os << val;
}
static int HashCode(double a) {
return static_cast<int>(bit_cast<int64_t>(a));
}
static bool Equals(double a, double b) {
return bit_cast<int64_t>(a) == bit_cast<int64_t>(b);
}
};
// Specialization for static parameters of type {Unique<Object>}.
template <>
struct StaticParameterTraits<Unique<Object> > {
static std::ostream& PrintTo(std::ostream& os,
Unique<Object> val) { // NOLINT
return os << Brief(*val.handle());
}
static int HashCode(Unique<Object> a) {
return static_cast<int>(a.Hashcode());
}
static bool Equals(Unique<Object> a, Unique<Object> b) { return a == b; }
};
// Specialization for static parameters of type {Unique<Name>}.
template <>
struct StaticParameterTraits<Unique<Name> > {
static std::ostream& PrintTo(std::ostream& os, Unique<Name> val) { // NOLINT
return os << Brief(*val.handle());
}
static int HashCode(Unique<Name> a) { return static_cast<int>(a.Hashcode()); }
static bool Equals(Unique<Name> a, Unique<Name> b) { return a == b; }
};
#if DEBUG
// Specialization for static parameters of type {Handle<Object>} to prevent any
// direct usage of Handles in constants.
template <>
struct StaticParameterTraits<Handle<Object> > {
static std::ostream& PrintTo(std::ostream& os,
Handle<Object> val) { // NOLINT
UNREACHABLE(); // Should use Unique<Object> instead
return os;
}
static int HashCode(Handle<Object> a) {
UNREACHABLE(); // Should use Unique<Object> instead
return 0;
}
static bool Equals(Handle<Object> a, Handle<Object> b) {
UNREACHABLE(); // Should use Unique<Object> instead
return false;
}
};
#endif
// A templatized implementation of Operator that has one static parameter of // A templatized implementation of Operator that has one static parameter of
// type {T}. If a specialization of StaticParameterTraits<{T}> exists, then // type {T}.
// operators of this kind can automatically be hashed, compared, and printed. template <typename T, typename Pred = std::equal_to<T>,
template <typename T> typename Hash = base::hash<T>>
class Operator1 : public Operator { class Operator1 : public Operator {
public: public:
Operator1(Opcode opcode, Properties properties, int input_count, Operator1(Opcode opcode, Properties properties, int input_count,
int output_count, const char* mnemonic, T parameter) int output_count, const char* mnemonic, T parameter,
Pred const& pred = Pred(), Hash const& hash = Hash())
: Operator(opcode, properties, mnemonic), : Operator(opcode, properties, mnemonic),
input_count_(input_count), input_count_(input_count),
output_count_(output_count), output_count_(output_count),
parameter_(parameter) {} parameter_(parameter),
pred_(pred),
hash_(hash) {}
const T& parameter() const { return parameter_; } T const& parameter() const { return parameter_; }
virtual bool Equals(const Operator* other) const OVERRIDE { virtual bool Equals(const Operator* other) const FINAL {
if (opcode() != other->opcode()) return false; if (opcode() != other->opcode()) return false;
const Operator1<T>* that = static_cast<const Operator1<T>*>(other); const Operator1<T>* that = static_cast<const Operator1<T>*>(other);
return StaticParameterTraits<T>::Equals(this->parameter_, that->parameter_); return this->pred_(this->parameter(), that->parameter());
} }
virtual int HashCode() const OVERRIDE { virtual size_t HashCode() const FINAL {
return opcode() + 33 * StaticParameterTraits<T>::HashCode(this->parameter_); return base::hash_combine(this->opcode(), this->hash_(this->parameter()));
} }
virtual int InputCount() const OVERRIDE { return input_count_; } virtual int InputCount() const FINAL { return input_count_; }
virtual int OutputCount() const OVERRIDE { return output_count_; } virtual int OutputCount() const FINAL { return output_count_; }
virtual std::ostream& PrintParameter(std::ostream& os) const { // NOLINT virtual void PrintParameter(std::ostream& os) const {
return StaticParameterTraits<T>::PrintTo(os << "[", parameter_) << "]"; os << "[" << this->parameter() << "]";
} }
protected: protected:
virtual std::ostream& PrintTo(std::ostream& os) const FINAL { // NOLINT virtual void PrintTo(std::ostream& os) const FINAL {
return PrintParameter(os << mnemonic()); os << mnemonic();
PrintParameter(os);
} }
private: private:
int input_count_; int const input_count_;
int output_count_; int const output_count_;
T parameter_; T const parameter_;
Pred const pred_;
Hash const hash_;
}; };
// Helper to extract parameters from Operator1<*> operator. // Helper to extract parameters from Operator1<*> operator.
template <typename T> template <typename T>
static inline const T& OpParameter(const Operator* op) { inline T const& OpParameter(const Operator* op) {
return reinterpret_cast<const Operator1<T>*>(op)->parameter(); return static_cast<const Operator1<T>*>(op)->parameter();
} }
} // namespace compiler } // namespace compiler
......
...@@ -57,7 +57,7 @@ class RawMachineAssembler : public GraphBuilder { ...@@ -57,7 +57,7 @@ class RawMachineAssembler : public GraphBuilder {
MachineSignature* machine_sig() const { return machine_sig_; } MachineSignature* machine_sig() const { return machine_sig_; }
Node* UndefinedConstant() { Node* UndefinedConstant() {
Unique<Object> unique = Unique<Object>::CreateImmovable( Unique<HeapObject> unique = Unique<HeapObject>::CreateImmovable(
isolate()->factory()->undefined_value()); isolate()->factory()->undefined_value());
return NewNode(common()->HeapConstant(unique)); return NewNode(common()->HeapConstant(unique));
} }
...@@ -86,8 +86,8 @@ class RawMachineAssembler : public GraphBuilder { ...@@ -86,8 +86,8 @@ class RawMachineAssembler : public GraphBuilder {
Node* Float64Constant(double value) { Node* Float64Constant(double value) {
return NewNode(common()->Float64Constant(value)); return NewNode(common()->Float64Constant(value));
} }
Node* HeapConstant(Handle<Object> object) { Node* HeapConstant(Handle<HeapObject> object) {
Unique<Object> val = Unique<Object>::CreateUninitialized(object); Unique<HeapObject> val = Unique<HeapObject>::CreateUninitialized(object);
return NewNode(common()->HeapConstant(val)); return NewNode(common()->HeapConstant(val));
} }
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
#include "src/compiler/simplified-operator.h" #include "src/compiler/simplified-operator.h"
#include <ostream> // NOLINT(readability/streams)
#include "src/base/lazy-instance.h" #include "src/base/lazy-instance.h"
#include "src/compiler/opcodes.h" #include "src/compiler/opcodes.h"
#include "src/compiler/operator.h" #include "src/compiler/operator.h"
...@@ -29,7 +27,7 @@ std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) { ...@@ -29,7 +27,7 @@ std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) {
bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) { bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) {
return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset && return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset &&
lhs.type == rhs.type && lhs.machine_type == rhs.machine_type; lhs.machine_type == rhs.machine_type;
} }
...@@ -38,6 +36,12 @@ bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs) { ...@@ -38,6 +36,12 @@ bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs) {
} }
size_t hash_value(FieldAccess const& access) {
return base::hash_combine(access.base_is_tagged, access.offset,
access.machine_type);
}
std::ostream& operator<<(std::ostream& os, FieldAccess const& access) { std::ostream& operator<<(std::ostream& os, FieldAccess const& access) {
os << "[" << access.base_is_tagged << ", " << access.offset << ", "; os << "[" << access.base_is_tagged << ", " << access.offset << ", ";
#ifdef OBJECT_PRINT #ifdef OBJECT_PRINT
...@@ -67,7 +71,7 @@ std::ostream& operator<<(std::ostream& os, BoundsCheckMode bounds_check_mode) { ...@@ -67,7 +71,7 @@ std::ostream& operator<<(std::ostream& os, BoundsCheckMode bounds_check_mode) {
bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) { bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) {
return lhs.base_is_tagged == rhs.base_is_tagged && return lhs.base_is_tagged == rhs.base_is_tagged &&
lhs.header_size == rhs.header_size && lhs.type == rhs.type && lhs.header_size == rhs.header_size &&
lhs.machine_type == rhs.machine_type; lhs.machine_type == rhs.machine_type;
} }
...@@ -77,10 +81,16 @@ bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) { ...@@ -77,10 +81,16 @@ bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) {
} }
size_t hash_value(ElementAccess const& access) {
return base::hash_combine(access.base_is_tagged, access.header_size,
access.machine_type);
}
std::ostream& operator<<(std::ostream& os, ElementAccess const& access) { std::ostream& operator<<(std::ostream& os, ElementAccess const& access) {
os << "[" << access.base_is_tagged << ", " << access.header_size << ", "; os << access.base_is_tagged << ", " << access.header_size << ", ";
access.type->PrintTo(os); access.type->PrintTo(os);
os << ", " << access.machine_type << ", " << access.bounds_check << "]"; os << ", " << access.machine_type << ", " << access.bounds_check;
return os; return os;
} }
...@@ -101,40 +111,6 @@ const ElementAccess& ElementAccessOf(const Operator* op) { ...@@ -101,40 +111,6 @@ const ElementAccess& ElementAccessOf(const Operator* op) {
} }
// Specialization for static parameters of type {FieldAccess}.
template <>
struct StaticParameterTraits<FieldAccess> {
static std::ostream& PrintTo(std::ostream& os, const FieldAccess& val) {
return os << val.offset;
}
static int HashCode(const FieldAccess& val) {
return (val.offset < 16) | (val.machine_type & 0xffff);
}
static bool Equals(const FieldAccess& lhs, const FieldAccess& rhs) {
return lhs.base_is_tagged == rhs.base_is_tagged &&
lhs.offset == rhs.offset && lhs.machine_type == rhs.machine_type &&
lhs.type->Is(rhs.type);
}
};
// Specialization for static parameters of type {ElementAccess}.
template <>
struct StaticParameterTraits<ElementAccess> {
static std::ostream& PrintTo(std::ostream& os, const ElementAccess& access) {
return os << access;
}
static int HashCode(const ElementAccess& access) {
return (access.header_size < 16) | (access.machine_type & 0xffff);
}
static bool Equals(const ElementAccess& lhs, const ElementAccess& rhs) {
return lhs.base_is_tagged == rhs.base_is_tagged &&
lhs.header_size == rhs.header_size &&
lhs.machine_type == rhs.machine_type && lhs.type->Is(rhs.type);
}
};
#define PURE_OP_LIST(V) \ #define PURE_OP_LIST(V) \
V(BooleanNot, Operator::kNoProperties, 1) \ V(BooleanNot, Operator::kNoProperties, 1) \
V(BooleanToNumber, Operator::kNoProperties, 1) \ V(BooleanToNumber, Operator::kNoProperties, 1) \
......
...@@ -32,6 +32,7 @@ enum BaseTaggedness { kUntaggedBase, kTaggedBase }; ...@@ -32,6 +32,7 @@ enum BaseTaggedness { kUntaggedBase, kTaggedBase };
std::ostream& operator<<(std::ostream&, BaseTaggedness); std::ostream& operator<<(std::ostream&, BaseTaggedness);
// An access descriptor for loads/stores of fixed structures like field // An access descriptor for loads/stores of fixed structures like field
// accesses of heap objects. Accesses from either tagged or untagged base // accesses of heap objects. Accesses from either tagged or untagged base
// pointers are supported; untagging is done automatically during lowering. // pointers are supported; untagging is done automatically during lowering.
...@@ -45,12 +46,15 @@ struct FieldAccess { ...@@ -45,12 +46,15 @@ struct FieldAccess {
int tag() const { return base_is_tagged == kTaggedBase ? kHeapObjectTag : 0; } int tag() const { return base_is_tagged == kTaggedBase ? kHeapObjectTag : 0; }
}; };
bool operator==(FieldAccess const& lhs, FieldAccess const& rhs); bool operator==(FieldAccess const&, FieldAccess const&);
bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs); bool operator!=(FieldAccess const&, FieldAccess const&);
size_t hash_value(FieldAccess const&);
std::ostream& operator<<(std::ostream&, FieldAccess const&); std::ostream& operator<<(std::ostream&, FieldAccess const&);
// The bound checking mode for ElementAccess below.
enum BoundsCheckMode { kNoBoundsCheck, kTypedArrayBoundsCheck }; enum BoundsCheckMode { kNoBoundsCheck, kTypedArrayBoundsCheck };
std::ostream& operator<<(std::ostream&, BoundsCheckMode); std::ostream& operator<<(std::ostream&, BoundsCheckMode);
...@@ -70,8 +74,10 @@ struct ElementAccess { ...@@ -70,8 +74,10 @@ struct ElementAccess {
int tag() const { return base_is_tagged == kTaggedBase ? kHeapObjectTag : 0; } int tag() const { return base_is_tagged == kTaggedBase ? kHeapObjectTag : 0; }
}; };
bool operator==(ElementAccess const& lhs, ElementAccess const& rhs); bool operator==(ElementAccess const&, ElementAccess const&);
bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs); bool operator!=(ElementAccess const&, ElementAccess const&);
size_t hash_value(ElementAccess const&);
std::ostream& operator<<(std::ostream&, ElementAccess const&); std::ostream& operator<<(std::ostream&, ElementAccess const&);
......
...@@ -3318,5 +3318,11 @@ const Runtime::Function* Runtime::FunctionForEntry(Address entry) { ...@@ -3318,5 +3318,11 @@ const Runtime::Function* Runtime::FunctionForEntry(Address entry) {
const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
return &(kIntrinsicFunctions[static_cast<int>(id)]); return &(kIntrinsicFunctions[static_cast<int>(id)]);
} }
std::ostream& operator<<(std::ostream& os, Runtime::FunctionId id) {
return os << Runtime::FunctionForId(id)->name;
} }
} // namespace v8::internal
} // namespace internal
} // namespace v8
...@@ -898,6 +898,8 @@ class Runtime : public AllStatic { ...@@ -898,6 +898,8 @@ class Runtime : public AllStatic {
}; };
std::ostream& operator<<(std::ostream&, Runtime::FunctionId);
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Constants used by interface to runtime functions. // Constants used by interface to runtime functions.
...@@ -907,7 +909,8 @@ class AllocateTargetSpace : public BitField<AllocationSpace, 1, 3> {}; ...@@ -907,7 +909,8 @@ class AllocateTargetSpace : public BitField<AllocationSpace, 1, 3> {};
class DeclareGlobalsEvalFlag : public BitField<bool, 0, 1> {}; class DeclareGlobalsEvalFlag : public BitField<bool, 0, 1> {};
class DeclareGlobalsNativeFlag : public BitField<bool, 1, 1> {}; class DeclareGlobalsNativeFlag : public BitField<bool, 1, 1> {};
class DeclareGlobalsStrictMode : public BitField<StrictMode, 2, 1> {}; class DeclareGlobalsStrictMode : public BitField<StrictMode, 2, 1> {};
}
} // namespace v8::internal } // namespace internal
} // namespace v8
#endif // V8_RUNTIME_H_ #endif // V8_RUNTIME_H_
...@@ -5,9 +5,11 @@ ...@@ -5,9 +5,11 @@
#ifndef V8_HYDROGEN_UNIQUE_H_ #ifndef V8_HYDROGEN_UNIQUE_H_
#define V8_HYDROGEN_UNIQUE_H_ #define V8_HYDROGEN_UNIQUE_H_
#include <ostream> // NOLINT(readability/streams)
#include "src/base/functional.h"
#include "src/handles-inl.h" // TODO(everyone): Fix our inl.h crap #include "src/handles-inl.h" // TODO(everyone): Fix our inl.h crap
#include "src/objects-inl.h" // TODO(everyone): Fix our inl.h crap #include "src/objects-inl.h" // TODO(everyone): Fix our inl.h crap
#include "src/string-stream.h"
#include "src/utils.h" #include "src/utils.h"
#include "src/zone.h" #include "src/zone.h"
...@@ -81,6 +83,11 @@ class Unique { ...@@ -81,6 +83,11 @@ class Unique {
return raw_address_ != other.raw_address_; return raw_address_ != other.raw_address_;
} }
friend inline size_t hash_value(Unique<T> const& unique) {
DCHECK(unique.IsInitialized());
return base::hash<void*>()(unique.raw_address_);
}
inline intptr_t Hashcode() const { inline intptr_t Hashcode() const {
DCHECK(IsInitialized()); DCHECK(IsInitialized());
return reinterpret_cast<intptr_t>(raw_address_); return reinterpret_cast<intptr_t>(raw_address_);
...@@ -128,6 +135,11 @@ class Unique { ...@@ -128,6 +135,11 @@ class Unique {
friend class SideEffectsTracker; friend class SideEffectsTracker;
}; };
template <typename T>
inline std::ostream& operator<<(std::ostream& os, Unique<T> uniq) {
return os << Brief(*uniq.handle());
}
template <typename T> template <typename T>
class UniqueSet FINAL : public ZoneObject { class UniqueSet FINAL : public ZoneObject {
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "src/v8.h" #include "src/v8.h"
#include "src/base/functional.h"
#include "src/base/logging.h" #include "src/base/logging.h"
#include "src/base/platform/platform.h" #include "src/base/platform/platform.h"
#include "src/utils.h" #include "src/utils.h"
...@@ -77,6 +78,17 @@ char* SimpleStringBuilder::Finalize() { ...@@ -77,6 +78,17 @@ char* SimpleStringBuilder::Finalize() {
} }
size_t hash_value(BailoutId id) {
base::hash<int> h;
return h(id.id_);
}
std::ostream& operator<<(std::ostream& os, BailoutId id) {
return os << id.id_;
}
void PrintF(const char* format, ...) { void PrintF(const char* format, ...) {
va_list arguments; va_list arguments;
va_start(arguments, format); va_start(arguments, format);
......
...@@ -965,6 +965,8 @@ class BailoutId { ...@@ -965,6 +965,8 @@ class BailoutId {
bool IsNone() const { return id_ == kNoneId; } bool IsNone() const { return id_ == kNoneId; }
bool operator==(const BailoutId& other) const { return id_ == other.id_; } bool operator==(const BailoutId& other) const { return id_ == other.id_; }
bool operator!=(const BailoutId& other) const { return id_ != other.id_; } bool operator!=(const BailoutId& other) const { return id_ != other.id_; }
friend size_t hash_value(BailoutId);
friend std::ostream& operator<<(std::ostream&, BailoutId);
private: private:
static const int kNoneId = -1; static const int kNoneId = -1;
......
...@@ -477,10 +477,10 @@ TEST(RunHeapConstant) { ...@@ -477,10 +477,10 @@ TEST(RunHeapConstant) {
TEST(RunHeapNumberConstant) { TEST(RunHeapNumberConstant) {
RawMachineAssemblerTester<Object*> m; RawMachineAssemblerTester<HeapObject*> m;
Handle<Object> number = m.isolate()->factory()->NewHeapNumber(100.5); Handle<HeapObject> number = m.isolate()->factory()->NewHeapNumber(100.5);
m.Return(m.HeapConstant(number)); m.Return(m.HeapConstant(number));
Object* result = m.Call(); HeapObject* result = m.Call();
CHECK_EQ(result, *number); CHECK_EQ(result, *number);
} }
......
...@@ -45,8 +45,8 @@ class SimplifiedGraphBuilder : public GraphBuilder { ...@@ -45,8 +45,8 @@ class SimplifiedGraphBuilder : public GraphBuilder {
Node* Int32Constant(int32_t value) { Node* Int32Constant(int32_t value) {
return NewNode(common()->Int32Constant(value)); return NewNode(common()->Int32Constant(value));
} }
Node* HeapConstant(Handle<Object> object) { Node* HeapConstant(Handle<HeapObject> object) {
Unique<Object> val = Unique<Object>::CreateUninitialized(object); Unique<HeapObject> val = Unique<HeapObject>::CreateUninitialized(object);
return NewNode(common()->HeapConstant(val)); return NewNode(common()->HeapConstant(val));
} }
......
...@@ -129,13 +129,13 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester { ...@@ -129,13 +129,13 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester {
Handle<JSFunction> deopt_function = Handle<JSFunction> deopt_function =
NewFunction("function deopt() { %DeoptimizeFunction(foo); }; deopt"); NewFunction("function deopt() { %DeoptimizeFunction(foo); }; deopt");
Unique<Object> deopt_fun_constant = Unique<JSFunction> deopt_fun_constant =
Unique<Object>::CreateUninitialized(deopt_function); Unique<JSFunction>::CreateUninitialized(deopt_function);
Node* deopt_fun_node = m.NewNode(common.HeapConstant(deopt_fun_constant)); Node* deopt_fun_node = m.NewNode(common.HeapConstant(deopt_fun_constant));
Handle<Context> caller_context(function->context(), CcTest::i_isolate()); Handle<Context> caller_context(function->context(), CcTest::i_isolate());
Unique<Object> caller_context_constant = Unique<Context> caller_context_constant =
Unique<Object>::CreateUninitialized(caller_context); Unique<Context>::CreateUninitialized(caller_context);
Node* caller_context_node = Node* caller_context_node =
m.NewNode(common.HeapConstant(caller_context_constant)); m.NewNode(common.HeapConstant(caller_context_constant));
...@@ -150,8 +150,8 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester { ...@@ -150,8 +150,8 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester {
parameters, locals, stack, caller_context_node, m.UndefinedConstant()); parameters, locals, stack, caller_context_node, m.UndefinedConstant());
Handle<Context> context(deopt_function->context(), CcTest::i_isolate()); Handle<Context> context(deopt_function->context(), CcTest::i_isolate());
Unique<Object> context_constant = Unique<Context> context_constant =
Unique<Object>::CreateUninitialized(context); Unique<Context>::CreateUninitialized(context);
Node* context_node = m.NewNode(common.HeapConstant(context_constant)); Node* context_node = m.NewNode(common.HeapConstant(context_constant));
m.CallJS0(deopt_fun_node, m.UndefinedConstant(), context_node, state_node); m.CallJS0(deopt_fun_node, m.UndefinedConstant(), context_node, state_node);
...@@ -245,13 +245,13 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester { ...@@ -245,13 +245,13 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester {
CSignature1<Object*, Object*> sig; CSignature1<Object*, Object*> sig;
RawMachineAssembler m(graph, &sig); RawMachineAssembler m(graph, &sig);
Unique<Object> this_fun_constant = Unique<HeapObject> this_fun_constant =
Unique<Object>::CreateUninitialized(function); Unique<HeapObject>::CreateUninitialized(function);
Node* this_fun_node = m.NewNode(common.HeapConstant(this_fun_constant)); Node* this_fun_node = m.NewNode(common.HeapConstant(this_fun_constant));
Handle<Context> context(function->context(), CcTest::i_isolate()); Handle<Context> context(function->context(), CcTest::i_isolate());
Unique<Object> context_constant = Unique<HeapObject> context_constant =
Unique<Object>::CreateUninitialized(context); Unique<HeapObject>::CreateUninitialized(context);
Node* context_node = m.NewNode(common.HeapConstant(context_constant)); Node* context_node = m.NewNode(common.HeapConstant(context_constant));
bailout_id = GetCallBailoutId(); bailout_id = GetCallBailoutId();
......
...@@ -49,13 +49,14 @@ class JSTypedLoweringTester : public HandleAndZoneScope { ...@@ -49,13 +49,14 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
} }
Node* UndefinedConstant() { Node* UndefinedConstant() {
Unique<Object> unique = Unique<HeapObject> unique = Unique<HeapObject>::CreateImmovable(
Unique<Object>::CreateImmovable(isolate->factory()->undefined_value()); isolate->factory()->undefined_value());
return graph.NewNode(common.HeapConstant(unique)); return graph.NewNode(common.HeapConstant(unique));
} }
Node* HeapConstant(Handle<Object> constant) { Node* HeapConstant(Handle<HeapObject> constant) {
Unique<Object> unique = Unique<Object>::CreateUninitialized(constant); Unique<HeapObject> unique =
Unique<HeapObject>::CreateUninitialized(constant);
return graph.NewNode(common.HeapConstant(unique)); return graph.NewNode(common.HeapConstant(unique));
} }
......
...@@ -91,13 +91,13 @@ TEST(TestOperator1intHash) { ...@@ -91,13 +91,13 @@ TEST(TestOperator1intHash) {
Operator1<int> op1a(23, Operator::kNoProperties, 0, 0, "Wolfie", 11); Operator1<int> op1a(23, Operator::kNoProperties, 0, 0, "Wolfie", 11);
Operator1<int> op1b(23, Operator::kFoldable, 2, 2, "Doggie", 11); Operator1<int> op1b(23, Operator::kFoldable, 2, 2, "Doggie", 11);
CHECK_EQ(op1a.HashCode(), op1b.HashCode()); CHECK(op1a.HashCode() == op1b.HashCode());
Operator1<int> op2a(24, Operator::kNoProperties, 0, 0, "Arfie", 3); Operator1<int> op2a(24, Operator::kNoProperties, 0, 0, "Arfie", 3);
Operator1<int> op2b(24, Operator::kNoProperties, 0, 0, "Arfie", 4); Operator1<int> op2b(24, Operator::kNoProperties, 0, 0, "Arfie", 4);
CHECK_NE(op1a.HashCode(), op2a.HashCode()); CHECK(op1a.HashCode() != op2a.HashCode());
CHECK_NE(op2a.HashCode(), op2b.HashCode()); CHECK(op2a.HashCode() != op2b.HashCode());
} }
...@@ -161,13 +161,13 @@ TEST(TestOperator1doubleHash) { ...@@ -161,13 +161,13 @@ TEST(TestOperator1doubleHash) {
Operator1<double> op1a(23, Operator::kNoProperties, 0, 0, "Wolfie", 11.77); Operator1<double> op1a(23, Operator::kNoProperties, 0, 0, "Wolfie", 11.77);
Operator1<double> op1b(23, Operator::kFoldable, 2, 2, "Doggie", 11.77); Operator1<double> op1b(23, Operator::kFoldable, 2, 2, "Doggie", 11.77);
CHECK_EQ(op1a.HashCode(), op1b.HashCode()); CHECK(op1a.HashCode() == op1b.HashCode());
Operator1<double> op2a(24, Operator::kNoProperties, 0, 0, "Arfie", -6.7); Operator1<double> op2a(24, Operator::kNoProperties, 0, 0, "Arfie", -6.7);
Operator1<double> op2b(24, Operator::kNoProperties, 0, 0, "Arfie", -6.8); Operator1<double> op2b(24, Operator::kNoProperties, 0, 0, "Arfie", -6.8);
CHECK_NE(op1a.HashCode(), op2a.HashCode()); CHECK(op1a.HashCode() != op2a.HashCode());
CHECK_NE(op2a.HashCode(), op2b.HashCode()); CHECK(op2a.HashCode() != op2b.HashCode());
} }
......
...@@ -680,9 +680,10 @@ TEST(BuildScheduleIfSplitWithEffects) { ...@@ -680,9 +680,10 @@ TEST(BuildScheduleIfSplitWithEffects) {
JSOperatorBuilder js_builder(scope.main_zone()); JSOperatorBuilder js_builder(scope.main_zone());
const Operator* op; const Operator* op;
Handle<Object> object = Handle<HeapObject> object =
Handle<Object>(isolate->heap()->undefined_value(), isolate); Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object); Unique<HeapObject> unique_constant =
Unique<HeapObject>::CreateUninitialized(object);
// Manually transcripted code for: // Manually transcripted code for:
// function turbo_fan_test(a, b, c, y) { // function turbo_fan_test(a, b, c, y) {
...@@ -825,9 +826,10 @@ TEST(BuildScheduleSimpleLoop) { ...@@ -825,9 +826,10 @@ TEST(BuildScheduleSimpleLoop) {
JSOperatorBuilder js_builder(scope.main_zone()); JSOperatorBuilder js_builder(scope.main_zone());
const Operator* op; const Operator* op;
Handle<Object> object = Handle<HeapObject> object =
Handle<Object>(isolate->heap()->undefined_value(), isolate); Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object); Unique<HeapObject> unique_constant =
Unique<HeapObject>::CreateUninitialized(object);
// Manually transcripted code for: // Manually transcripted code for:
// function turbo_fan_test(a, b) { // function turbo_fan_test(a, b) {
...@@ -937,9 +939,10 @@ TEST(BuildScheduleComplexLoops) { ...@@ -937,9 +939,10 @@ TEST(BuildScheduleComplexLoops) {
JSOperatorBuilder js_builder(scope.main_zone()); JSOperatorBuilder js_builder(scope.main_zone());
const Operator* op; const Operator* op;
Handle<Object> object = Handle<HeapObject> object =
Handle<Object>(isolate->heap()->undefined_value(), isolate); Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object); Unique<HeapObject> unique_constant =
Unique<HeapObject>::CreateUninitialized(object);
// Manually transcripted code for: // Manually transcripted code for:
// function turbo_fan_test(a, b, c) { // function turbo_fan_test(a, b, c) {
...@@ -1184,9 +1187,10 @@ TEST(BuildScheduleBreakAndContinue) { ...@@ -1184,9 +1187,10 @@ TEST(BuildScheduleBreakAndContinue) {
JSOperatorBuilder js_builder(scope.main_zone()); JSOperatorBuilder js_builder(scope.main_zone());
const Operator* op; const Operator* op;
Handle<Object> object = Handle<HeapObject> object =
Handle<Object>(isolate->heap()->undefined_value(), isolate); Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object); Unique<HeapObject> unique_constant =
Unique<HeapObject>::CreateUninitialized(object);
// Manually transcripted code for: // Manually transcripted code for:
// function turbo_fan_test(a, b, c) { // function turbo_fan_test(a, b, c) {
...@@ -1514,9 +1518,10 @@ TEST(BuildScheduleSimpleLoopWithCodeMotion) { ...@@ -1514,9 +1518,10 @@ TEST(BuildScheduleSimpleLoopWithCodeMotion) {
MachineOperatorBuilder machine_builder; MachineOperatorBuilder machine_builder;
const Operator* op; const Operator* op;
Handle<Object> object = Handle<HeapObject> object =
Handle<Object>(isolate->heap()->undefined_value(), isolate); Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object); Unique<HeapObject> unique_constant =
Unique<HeapObject>::CreateUninitialized(object);
// Manually transcripted code for: // Manually transcripted code for:
// function turbo_fan_test(a, b, c) { // function turbo_fan_test(a, b, c) {
......
...@@ -17,18 +17,6 @@ using testing::StringMatchResultListener; ...@@ -17,18 +17,6 @@ using testing::StringMatchResultListener;
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// TODO(bmeurer): Find a new home for these functions.
template <typename T>
inline std::ostream& operator<<(std::ostream& os, const Unique<T>& value) {
return os << *value.handle();
}
inline std::ostream& operator<<(std::ostream& os,
const ExternalReference& value) {
compiler::StaticParameterTraits<ExternalReference>::PrintTo(os, value);
return os;
}
namespace compiler { namespace compiler {
GraphTest::GraphTest(int num_parameters) : common_(zone()), graph_(zone()) { GraphTest::GraphTest(int num_parameters) : common_(zone()), graph_(zone()) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment