mirror of https://github.com/lukechilds/node.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
300 lines
10 KiB
300 lines
10 KiB
// Copyright 2012 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/simplified-operator.h"
|
|
|
|
#include "src/base/lazy-instance.h"
|
|
#include "src/compiler/opcodes.h"
|
|
#include "src/compiler/operator.h"
|
|
#include "src/types-inl.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace compiler {
|
|
|
|
std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) {
|
|
switch (base_taggedness) {
|
|
case kUntaggedBase:
|
|
return os << "untagged base";
|
|
case kTaggedBase:
|
|
return os << "tagged base";
|
|
}
|
|
UNREACHABLE();
|
|
return os;
|
|
}
|
|
|
|
|
|
MachineType BufferAccess::machine_type() const {
|
|
switch (external_array_type_) {
|
|
case kExternalUint8Array:
|
|
case kExternalUint8ClampedArray:
|
|
return kMachUint8;
|
|
case kExternalInt8Array:
|
|
return kMachInt8;
|
|
case kExternalUint16Array:
|
|
return kMachUint16;
|
|
case kExternalInt16Array:
|
|
return kMachInt16;
|
|
case kExternalUint32Array:
|
|
return kMachUint32;
|
|
case kExternalInt32Array:
|
|
return kMachInt32;
|
|
case kExternalFloat32Array:
|
|
return kMachFloat32;
|
|
case kExternalFloat64Array:
|
|
return kMachFloat64;
|
|
}
|
|
UNREACHABLE();
|
|
return kMachNone;
|
|
}
|
|
|
|
|
|
bool operator==(BufferAccess lhs, BufferAccess rhs) {
|
|
return lhs.external_array_type() == rhs.external_array_type();
|
|
}
|
|
|
|
|
|
bool operator!=(BufferAccess lhs, BufferAccess rhs) { return !(lhs == rhs); }
|
|
|
|
|
|
size_t hash_value(BufferAccess access) {
|
|
return base::hash<ExternalArrayType>()(access.external_array_type());
|
|
}
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, BufferAccess access) {
|
|
switch (access.external_array_type()) {
|
|
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
|
|
case kExternal##Type##Array: \
|
|
return os << #Type;
|
|
TYPED_ARRAYS(TYPED_ARRAY_CASE)
|
|
#undef TYPED_ARRAY_CASE
|
|
}
|
|
UNREACHABLE();
|
|
return os;
|
|
}
|
|
|
|
|
|
BufferAccess const BufferAccessOf(const Operator* op) {
|
|
DCHECK(op->opcode() == IrOpcode::kLoadBuffer ||
|
|
op->opcode() == IrOpcode::kStoreBuffer);
|
|
return OpParameter<BufferAccess>(op);
|
|
}
|
|
|
|
|
|
bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) {
|
|
return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset &&
|
|
lhs.machine_type == rhs.machine_type;
|
|
}
|
|
|
|
|
|
bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs) {
|
|
return !(lhs == 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) {
|
|
os << "[" << access.base_is_tagged << ", " << access.offset << ", ";
|
|
#ifdef OBJECT_PRINT
|
|
Handle<Name> name;
|
|
if (access.name.ToHandle(&name)) {
|
|
name->Print(os);
|
|
os << ", ";
|
|
}
|
|
#endif
|
|
access.type->PrintTo(os);
|
|
os << ", " << access.machine_type << "]";
|
|
return os;
|
|
}
|
|
|
|
|
|
bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) {
|
|
return lhs.base_is_tagged == rhs.base_is_tagged &&
|
|
lhs.header_size == rhs.header_size &&
|
|
lhs.machine_type == rhs.machine_type;
|
|
}
|
|
|
|
|
|
bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) {
|
|
return !(lhs == 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) {
|
|
os << access.base_is_tagged << ", " << access.header_size << ", ";
|
|
access.type->PrintTo(os);
|
|
os << ", " << access.machine_type;
|
|
return os;
|
|
}
|
|
|
|
|
|
const FieldAccess& FieldAccessOf(const Operator* op) {
|
|
DCHECK_NOT_NULL(op);
|
|
DCHECK(op->opcode() == IrOpcode::kLoadField ||
|
|
op->opcode() == IrOpcode::kStoreField);
|
|
return OpParameter<FieldAccess>(op);
|
|
}
|
|
|
|
|
|
const ElementAccess& ElementAccessOf(const Operator* op) {
|
|
DCHECK_NOT_NULL(op);
|
|
DCHECK(op->opcode() == IrOpcode::kLoadElement ||
|
|
op->opcode() == IrOpcode::kStoreElement);
|
|
return OpParameter<ElementAccess>(op);
|
|
}
|
|
|
|
|
|
#define PURE_OP_LIST(V) \
|
|
V(BooleanNot, Operator::kNoProperties, 1) \
|
|
V(BooleanToNumber, Operator::kNoProperties, 1) \
|
|
V(NumberEqual, Operator::kCommutative, 2) \
|
|
V(NumberLessThan, Operator::kNoProperties, 2) \
|
|
V(NumberLessThanOrEqual, Operator::kNoProperties, 2) \
|
|
V(NumberAdd, Operator::kCommutative, 2) \
|
|
V(NumberSubtract, Operator::kNoProperties, 2) \
|
|
V(NumberMultiply, Operator::kCommutative, 2) \
|
|
V(NumberDivide, Operator::kNoProperties, 2) \
|
|
V(NumberModulus, Operator::kNoProperties, 2) \
|
|
V(NumberShiftLeft, Operator::kNoProperties, 2) \
|
|
V(NumberShiftRight, Operator::kNoProperties, 2) \
|
|
V(NumberShiftRightLogical, Operator::kNoProperties, 2) \
|
|
V(NumberToInt32, Operator::kNoProperties, 1) \
|
|
V(NumberToUint32, Operator::kNoProperties, 1) \
|
|
V(PlainPrimitiveToNumber, Operator::kNoProperties, 1) \
|
|
V(StringEqual, Operator::kCommutative, 2) \
|
|
V(StringLessThan, Operator::kNoProperties, 2) \
|
|
V(StringLessThanOrEqual, Operator::kNoProperties, 2) \
|
|
V(ChangeTaggedToInt32, Operator::kNoProperties, 1) \
|
|
V(ChangeTaggedToUint32, Operator::kNoProperties, 1) \
|
|
V(ChangeTaggedToFloat64, Operator::kNoProperties, 1) \
|
|
V(ChangeInt32ToTagged, Operator::kNoProperties, 1) \
|
|
V(ChangeUint32ToTagged, Operator::kNoProperties, 1) \
|
|
V(ChangeFloat64ToTagged, Operator::kNoProperties, 1) \
|
|
V(ChangeBoolToBit, Operator::kNoProperties, 1) \
|
|
V(ChangeBitToBool, Operator::kNoProperties, 1) \
|
|
V(ObjectIsSmi, Operator::kNoProperties, 1) \
|
|
V(ObjectIsNonNegativeSmi, Operator::kNoProperties, 1)
|
|
|
|
|
|
struct SimplifiedOperatorGlobalCache final {
|
|
#define PURE(Name, properties, input_count) \
|
|
struct Name##Operator final : public Operator { \
|
|
Name##Operator() \
|
|
: Operator(IrOpcode::k##Name, Operator::kPure | properties, #Name, \
|
|
input_count, 0, 0, 1, 0, 0) {} \
|
|
}; \
|
|
Name##Operator k##Name;
|
|
PURE_OP_LIST(PURE)
|
|
#undef PURE
|
|
|
|
#define BUFFER_ACCESS(Type, type, TYPE, ctype, size) \
|
|
struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> { \
|
|
LoadBuffer##Type##Operator() \
|
|
: Operator1<BufferAccess>(IrOpcode::kLoadBuffer, \
|
|
Operator::kNoThrow | Operator::kNoWrite, \
|
|
"LoadBuffer", 3, 1, 1, 1, 1, 0, \
|
|
BufferAccess(kExternal##Type##Array)) {} \
|
|
}; \
|
|
struct StoreBuffer##Type##Operator final : public Operator1<BufferAccess> { \
|
|
StoreBuffer##Type##Operator() \
|
|
: Operator1<BufferAccess>(IrOpcode::kStoreBuffer, \
|
|
Operator::kNoRead | Operator::kNoThrow, \
|
|
"StoreBuffer", 4, 1, 1, 0, 1, 0, \
|
|
BufferAccess(kExternal##Type##Array)) {} \
|
|
}; \
|
|
LoadBuffer##Type##Operator kLoadBuffer##Type; \
|
|
StoreBuffer##Type##Operator kStoreBuffer##Type;
|
|
TYPED_ARRAYS(BUFFER_ACCESS)
|
|
#undef BUFFER_ACCESS
|
|
};
|
|
|
|
|
|
static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache =
|
|
LAZY_INSTANCE_INITIALIZER;
|
|
|
|
|
|
SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone)
|
|
: cache_(kCache.Get()), zone_(zone) {}
|
|
|
|
|
|
#define PURE(Name, properties, input_count) \
|
|
const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; }
|
|
PURE_OP_LIST(PURE)
|
|
#undef PURE
|
|
|
|
|
|
const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) {
|
|
// TODO(titzer): What about the type parameter?
|
|
return new (zone()) Operator(IrOpcode::kReferenceEqual,
|
|
Operator::kCommutative | Operator::kPure,
|
|
"ReferenceEqual", 2, 0, 0, 1, 0, 0);
|
|
}
|
|
|
|
|
|
const Operator* SimplifiedOperatorBuilder::Allocate(PretenureFlag pretenure) {
|
|
return new (zone())
|
|
Operator1<PretenureFlag>(IrOpcode::kAllocate, Operator::kNoThrow,
|
|
"Allocate", 1, 1, 1, 1, 1, 0, pretenure);
|
|
}
|
|
|
|
|
|
const Operator* SimplifiedOperatorBuilder::LoadBuffer(BufferAccess access) {
|
|
switch (access.external_array_type()) {
|
|
#define LOAD_BUFFER(Type, type, TYPE, ctype, size) \
|
|
case kExternal##Type##Array: \
|
|
return &cache_.kLoadBuffer##Type;
|
|
TYPED_ARRAYS(LOAD_BUFFER)
|
|
#undef LOAD_BUFFER
|
|
}
|
|
UNREACHABLE();
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) {
|
|
switch (access.external_array_type()) {
|
|
#define STORE_BUFFER(Type, type, TYPE, ctype, size) \
|
|
case kExternal##Type##Array: \
|
|
return &cache_.kStoreBuffer##Type;
|
|
TYPED_ARRAYS(STORE_BUFFER)
|
|
#undef STORE_BUFFER
|
|
}
|
|
UNREACHABLE();
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
#define ACCESS_OP_LIST(V) \
|
|
V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1) \
|
|
V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0) \
|
|
V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \
|
|
V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0)
|
|
|
|
|
|
#define ACCESS(Name, Type, properties, value_input_count, control_input_count, \
|
|
output_count) \
|
|
const Operator* SimplifiedOperatorBuilder::Name(const Type& access) { \
|
|
return new (zone()) \
|
|
Operator1<Type>(IrOpcode::k##Name, Operator::kNoThrow | properties, \
|
|
#Name, value_input_count, 1, control_input_count, \
|
|
output_count, 1, 0, access); \
|
|
}
|
|
ACCESS_OP_LIST(ACCESS)
|
|
#undef ACCESS
|
|
|
|
} // namespace compiler
|
|
} // namespace internal
|
|
} // namespace v8
|
|
|