| // 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/js-graph.h" |
| |
| #include "src/code-stubs.h" |
| #include "src/compiler/node-properties.h" |
| #include "src/compiler/typer.h" |
| #include "src/objects-inl.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace compiler { |
| |
| #define CACHED(name, expr) \ |
| cached_nodes_[name] ? cached_nodes_[name] : (cached_nodes_[name] = (expr)) |
| |
| Node* JSGraph::AllocateInNewSpaceStubConstant() { |
| return CACHED(kAllocateInNewSpaceStubConstant, |
| HeapConstant(BUILTIN_CODE(isolate(), AllocateInNewSpace))); |
| } |
| |
| Node* JSGraph::AllocateInOldSpaceStubConstant() { |
| return CACHED(kAllocateInOldSpaceStubConstant, |
| HeapConstant(BUILTIN_CODE(isolate(), AllocateInOldSpace))); |
| } |
| |
| Node* JSGraph::ArrayConstructorStubConstant() { |
| return CACHED(kArrayConstructorStubConstant, |
| HeapConstant(ArrayConstructorStub(isolate()).GetCode())); |
| } |
| |
| Node* JSGraph::ToNumberBuiltinConstant() { |
| return CACHED(kToNumberBuiltinConstant, |
| HeapConstant(BUILTIN_CODE(isolate(), ToNumber))); |
| } |
| |
| Node* JSGraph::CEntryStubConstant(int result_size, SaveFPRegsMode save_doubles, |
| ArgvMode argv_mode, bool builtin_exit_frame) { |
| if (save_doubles == kDontSaveFPRegs && argv_mode == kArgvOnStack) { |
| DCHECK(result_size >= 1 && result_size <= 3); |
| if (!builtin_exit_frame) { |
| CachedNode key; |
| if (result_size == 1) { |
| key = kCEntryStub1Constant; |
| } else if (result_size == 2) { |
| key = kCEntryStub2Constant; |
| } else { |
| DCHECK_EQ(3, result_size); |
| key = kCEntryStub3Constant; |
| } |
| return CACHED( |
| key, HeapConstant(CEntryStub(isolate(), result_size, save_doubles, |
| argv_mode, builtin_exit_frame) |
| .GetCode())); |
| } |
| CachedNode key = builtin_exit_frame |
| ? kCEntryStub1WithBuiltinExitFrameConstant |
| : kCEntryStub1Constant; |
| return CACHED(key, |
| HeapConstant(CEntryStub(isolate(), result_size, save_doubles, |
| argv_mode, builtin_exit_frame) |
| .GetCode())); |
| } |
| CEntryStub stub(isolate(), result_size, save_doubles, argv_mode, |
| builtin_exit_frame); |
| return HeapConstant(stub.GetCode()); |
| } |
| |
| Node* JSGraph::EmptyFixedArrayConstant() { |
| return CACHED(kEmptyFixedArrayConstant, |
| HeapConstant(factory()->empty_fixed_array())); |
| } |
| |
| Node* JSGraph::EmptyStringConstant() { |
| return CACHED(kEmptyStringConstant, HeapConstant(factory()->empty_string())); |
| } |
| |
| Node* JSGraph::FixedArrayMapConstant() { |
| return CACHED(kFixedArrayMapConstant, |
| HeapConstant(factory()->fixed_array_map())); |
| } |
| |
| Node* JSGraph::PropertyArrayMapConstant() { |
| return CACHED(kPropertyArrayMapConstant, |
| HeapConstant(factory()->property_array_map())); |
| } |
| |
| Node* JSGraph::FixedDoubleArrayMapConstant() { |
| return CACHED(kFixedDoubleArrayMapConstant, |
| HeapConstant(factory()->fixed_double_array_map())); |
| } |
| |
| Node* JSGraph::HeapNumberMapConstant() { |
| return CACHED(kHeapNumberMapConstant, |
| HeapConstant(factory()->heap_number_map())); |
| } |
| |
| Node* JSGraph::OptimizedOutConstant() { |
| return CACHED(kOptimizedOutConstant, |
| HeapConstant(factory()->optimized_out())); |
| } |
| |
| Node* JSGraph::StaleRegisterConstant() { |
| return CACHED(kStaleRegisterConstant, |
| HeapConstant(factory()->stale_register())); |
| } |
| |
| Node* JSGraph::UndefinedConstant() { |
| return CACHED(kUndefinedConstant, HeapConstant(factory()->undefined_value())); |
| } |
| |
| |
| Node* JSGraph::TheHoleConstant() { |
| return CACHED(kTheHoleConstant, HeapConstant(factory()->the_hole_value())); |
| } |
| |
| |
| Node* JSGraph::TrueConstant() { |
| return CACHED(kTrueConstant, HeapConstant(factory()->true_value())); |
| } |
| |
| |
| Node* JSGraph::FalseConstant() { |
| return CACHED(kFalseConstant, HeapConstant(factory()->false_value())); |
| } |
| |
| |
| Node* JSGraph::NullConstant() { |
| return CACHED(kNullConstant, HeapConstant(factory()->null_value())); |
| } |
| |
| |
| Node* JSGraph::ZeroConstant() { |
| return CACHED(kZeroConstant, NumberConstant(0.0)); |
| } |
| |
| Node* JSGraph::OneConstant() { |
| return CACHED(kOneConstant, NumberConstant(1.0)); |
| } |
| |
| Node* JSGraph::MinusOneConstant() { |
| return CACHED(kMinusOneConstant, NumberConstant(-1.0)); |
| } |
| |
| Node* JSGraph::NaNConstant() { |
| return CACHED(kNaNConstant, |
| NumberConstant(std::numeric_limits<double>::quiet_NaN())); |
| } |
| |
| |
| Node* JSGraph::HeapConstant(Handle<HeapObject> value) { |
| Node** loc = cache_.FindHeapConstant(value); |
| if (*loc == nullptr) { |
| *loc = graph()->NewNode(common()->HeapConstant(value)); |
| } |
| return *loc; |
| } |
| |
| |
| Node* JSGraph::Constant(Handle<Object> value) { |
| // Dereference the handle to determine if a number constant or other |
| // canonicalized node can be used. |
| if (value->IsNumber()) { |
| return Constant(value->Number()); |
| } else if (value->IsUndefined(isolate())) { |
| return UndefinedConstant(); |
| } else if (value->IsTrue(isolate())) { |
| return TrueConstant(); |
| } else if (value->IsFalse(isolate())) { |
| return FalseConstant(); |
| } else if (value->IsNull(isolate())) { |
| return NullConstant(); |
| } else if (value->IsTheHole(isolate())) { |
| return TheHoleConstant(); |
| } else { |
| return HeapConstant(Handle<HeapObject>::cast(value)); |
| } |
| } |
| |
| |
| Node* JSGraph::Constant(double value) { |
| if (bit_cast<int64_t>(value) == bit_cast<int64_t>(0.0)) return ZeroConstant(); |
| if (bit_cast<int64_t>(value) == bit_cast<int64_t>(1.0)) return OneConstant(); |
| return NumberConstant(value); |
| } |
| |
| |
| Node* JSGraph::Constant(int32_t value) { |
| if (value == 0) return ZeroConstant(); |
| if (value == 1) return OneConstant(); |
| return NumberConstant(value); |
| } |
| |
| Node* JSGraph::Constant(uint32_t value) { |
| if (value == 0) return ZeroConstant(); |
| if (value == 1) return OneConstant(); |
| return NumberConstant(value); |
| } |
| |
| Node* JSGraph::Int32Constant(int32_t value) { |
| Node** loc = cache_.FindInt32Constant(value); |
| if (*loc == nullptr) { |
| *loc = graph()->NewNode(common()->Int32Constant(value)); |
| } |
| return *loc; |
| } |
| |
| |
| Node* JSGraph::Int64Constant(int64_t value) { |
| Node** loc = cache_.FindInt64Constant(value); |
| if (*loc == nullptr) { |
| *loc = graph()->NewNode(common()->Int64Constant(value)); |
| } |
| return *loc; |
| } |
| |
| Node* JSGraph::RelocatableInt32Constant(int32_t value, RelocInfo::Mode rmode) { |
| Node** loc = cache_.FindRelocatableInt32Constant( |
| value, static_cast<RelocInfoMode>(rmode)); |
| if (*loc == nullptr) { |
| *loc = graph()->NewNode(common()->RelocatableInt32Constant(value, rmode)); |
| } |
| return *loc; |
| } |
| |
| Node* JSGraph::RelocatableInt64Constant(int64_t value, RelocInfo::Mode rmode) { |
| Node** loc = cache_.FindRelocatableInt64Constant( |
| value, static_cast<RelocInfoMode>(rmode)); |
| if (*loc == nullptr) { |
| *loc = graph()->NewNode(common()->RelocatableInt64Constant(value, rmode)); |
| } |
| return *loc; |
| } |
| |
| Node* JSGraph::RelocatableIntPtrConstant(intptr_t value, |
| RelocInfo::Mode rmode) { |
| return kPointerSize == 8 |
| ? RelocatableInt64Constant(value, rmode) |
| : RelocatableInt32Constant(static_cast<int>(value), rmode); |
| } |
| |
| Node* JSGraph::NumberConstant(double value) { |
| Node** loc = cache_.FindNumberConstant(value); |
| if (*loc == nullptr) { |
| *loc = graph()->NewNode(common()->NumberConstant(value)); |
| } |
| return *loc; |
| } |
| |
| |
| Node* JSGraph::Float32Constant(float value) { |
| Node** loc = cache_.FindFloat32Constant(value); |
| if (*loc == nullptr) { |
| *loc = graph()->NewNode(common()->Float32Constant(value)); |
| } |
| return *loc; |
| } |
| |
| |
| Node* JSGraph::Float64Constant(double value) { |
| Node** loc = cache_.FindFloat64Constant(value); |
| if (*loc == nullptr) { |
| *loc = graph()->NewNode(common()->Float64Constant(value)); |
| } |
| return *loc; |
| } |
| |
| Node* JSGraph::PointerConstant(intptr_t value) { |
| Node** loc = cache_.FindPointerConstant(value); |
| if (*loc == nullptr) { |
| *loc = graph()->NewNode(common()->PointerConstant(value)); |
| } |
| return *loc; |
| } |
| |
| Node* JSGraph::ExternalConstant(ExternalReference reference) { |
| Node** loc = cache_.FindExternalConstant(reference); |
| if (*loc == nullptr) { |
| *loc = graph()->NewNode(common()->ExternalConstant(reference)); |
| } |
| return *loc; |
| } |
| |
| |
| Node* JSGraph::ExternalConstant(Runtime::FunctionId function_id) { |
| return ExternalConstant(ExternalReference(function_id, isolate())); |
| } |
| |
| Node* JSGraph::EmptyStateValues() { |
| return CACHED(kEmptyStateValues, graph()->NewNode(common()->StateValues( |
| 0, SparseInputMask::Dense()))); |
| } |
| |
| Node* JSGraph::SingleDeadTypedStateValues() { |
| return CACHED(kSingleDeadTypedStateValues, |
| graph()->NewNode(common()->TypedStateValues( |
| new (graph()->zone()->New(sizeof(ZoneVector<MachineType>))) |
| ZoneVector<MachineType>(0, graph()->zone()), |
| SparseInputMask(SparseInputMask::kEndMarker << 1)))); |
| } |
| |
| Node* JSGraph::Dead() { |
| return CACHED(kDead, graph()->NewNode(common()->Dead())); |
| } |
| |
| void JSGraph::GetCachedNodes(NodeVector* nodes) { |
| cache_.GetCachedNodes(nodes); |
| for (size_t i = 0; i < arraysize(cached_nodes_); i++) { |
| if (Node* node = cached_nodes_[i]) { |
| if (!node->IsDead()) nodes->push_back(node); |
| } |
| } |
| } |
| |
| } // namespace compiler |
| } // namespace internal |
| } // namespace v8 |