[turbofan]: Integrate basic type feedback for property accesses.
BUG= Review URL: https://codereview.chromium.org/1021713005 Cr-Commit-Position: refs/heads/master@{#27470}
This commit is contained in:
parent
1d81d82a74
commit
78abf9d9d9
2
BUILD.gn
2
BUILD.gn
@ -593,6 +593,8 @@ source_set("v8_base") {
|
||||
"src/compiler/js-intrinsic-lowering.h",
|
||||
"src/compiler/js-operator.cc",
|
||||
"src/compiler/js-operator.h",
|
||||
"src/compiler/js-type-feedback.cc",
|
||||
"src/compiler/js-type-feedback.h",
|
||||
"src/compiler/js-typed-lowering.cc",
|
||||
"src/compiler/js-typed-lowering.h",
|
||||
"src/compiler/jump-threading.cc",
|
||||
|
@ -440,6 +440,8 @@ OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
|
||||
|
||||
if (info()->shared_info()->asm_function()) {
|
||||
info()->MarkAsContextSpecializing();
|
||||
} else if (FLAG_turbo_type_feedback) {
|
||||
info()->MarkAsTypeFeedbackEnabled();
|
||||
}
|
||||
|
||||
Timer t(this, &time_taken_to_create_graph_);
|
||||
|
@ -124,7 +124,8 @@ class CompilationInfo {
|
||||
kTypingEnabled = 1 << 11,
|
||||
kDisableFutureOptimization = 1 << 12,
|
||||
kSplittingEnabled = 1 << 13,
|
||||
kBuiltinInliningEnabled = 1 << 14
|
||||
kBuiltinInliningEnabled = 1 << 14,
|
||||
kTypeFeedbackEnabled = 1 << 15
|
||||
};
|
||||
|
||||
explicit CompilationInfo(ParseInfo* parse_info);
|
||||
@ -209,6 +210,12 @@ class CompilationInfo {
|
||||
|
||||
bool is_context_specializing() const { return GetFlag(kContextSpecializing); }
|
||||
|
||||
void MarkAsTypeFeedbackEnabled() { SetFlag(kTypeFeedbackEnabled); }
|
||||
|
||||
bool is_type_feedback_enabled() const {
|
||||
return GetFlag(kTypeFeedbackEnabled);
|
||||
}
|
||||
|
||||
void MarkAsInliningEnabled() { SetFlag(kInliningEnabled); }
|
||||
|
||||
bool is_inlining_enabled() const { return GetFlag(kInliningEnabled); }
|
||||
|
@ -12,7 +12,7 @@ namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
// This access builder provides a set of static methods constructing commonly
|
||||
// used FieldAccess and ElementAccess descriptors. These descriptors server as
|
||||
// used FieldAccess and ElementAccess descriptors. These descriptors serve as
|
||||
// parameters to simplified load/store operators.
|
||||
class AccessBuilder FINAL : public AllStatic {
|
||||
public:
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "src/compiler.h"
|
||||
#include "src/compiler/ast-loop-assignment-analyzer.h"
|
||||
#include "src/compiler/control-builders.h"
|
||||
#include "src/compiler/js-type-feedback.h"
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/compiler/liveness-analyzer.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
@ -381,7 +382,8 @@ class AstGraphBuilder::ControlScopeForFinally : public ControlScope {
|
||||
|
||||
|
||||
AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
|
||||
JSGraph* jsgraph, LoopAssignmentAnalysis* loop)
|
||||
JSGraph* jsgraph, LoopAssignmentAnalysis* loop,
|
||||
JSTypeFeedbackTable* js_type_feedback)
|
||||
: local_zone_(local_zone),
|
||||
info_(info),
|
||||
jsgraph_(jsgraph),
|
||||
@ -397,7 +399,8 @@ AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
|
||||
loop_assignment_analysis_(loop),
|
||||
state_values_cache_(jsgraph),
|
||||
liveness_analyzer_(static_cast<size_t>(info->scope()->num_stack_slots()),
|
||||
local_zone) {
|
||||
local_zone),
|
||||
js_type_feedback_(js_type_feedback) {
|
||||
InitializeAstVisitor(info->isolate(), local_zone);
|
||||
}
|
||||
|
||||
@ -1663,7 +1666,8 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
VisitForValue(property->value());
|
||||
Node* value = environment()->Pop();
|
||||
Handle<Name> name = key->AsPropertyName();
|
||||
Node* store = BuildNamedStore(literal, name, value);
|
||||
Node* store =
|
||||
BuildNamedStore(literal, name, value, TypeFeedbackId::None());
|
||||
PrepareFrameState(store, key->id());
|
||||
BuildSetHomeObject(value, literal, property->value());
|
||||
} else {
|
||||
@ -1838,7 +1842,8 @@ void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
subexpr->id(), OutputFrameStateCombine::PokeAt(0));
|
||||
Node* value = environment()->Pop();
|
||||
Node* index = jsgraph()->Constant(i);
|
||||
Node* store = BuildKeyedStore(literal, index, value);
|
||||
Node* store =
|
||||
BuildKeyedStore(literal, index, value, TypeFeedbackId::None());
|
||||
PrepareFrameStateAfterAndBefore(store, expr->GetIdForElement(i),
|
||||
OutputFrameStateCombine::Ignore(),
|
||||
frame_state_before);
|
||||
@ -1870,7 +1875,8 @@ void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value,
|
||||
Node* object = environment()->Pop();
|
||||
value = environment()->Pop();
|
||||
Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
|
||||
Node* store = BuildNamedStore(object, name, value);
|
||||
Node* store =
|
||||
BuildNamedStore(object, name, value, TypeFeedbackId::None());
|
||||
PrepareFrameState(store, bailout_id);
|
||||
break;
|
||||
}
|
||||
@ -1881,7 +1887,7 @@ void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value,
|
||||
Node* key = environment()->Pop();
|
||||
Node* object = environment()->Pop();
|
||||
value = environment()->Pop();
|
||||
Node* store = BuildKeyedStore(object, key, value);
|
||||
Node* store = BuildKeyedStore(object, key, value, TypeFeedbackId::None());
|
||||
// TODO(jarin) Provide a real frame state before.
|
||||
PrepareFrameStateAfterAndBefore(store, bailout_id,
|
||||
OutputFrameStateCombine::Ignore(),
|
||||
@ -1933,7 +1939,8 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
|
||||
VectorSlotPair pair =
|
||||
CreateVectorSlotPair(property->PropertyFeedbackSlot());
|
||||
old_value = BuildNamedLoad(object, name, pair);
|
||||
old_value =
|
||||
BuildNamedLoad(object, name, pair, property->PropertyFeedbackId());
|
||||
PrepareFrameState(old_value, property->LoadId(),
|
||||
OutputFrameStateCombine::Push());
|
||||
break;
|
||||
@ -1943,7 +1950,8 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
Node* object = environment()->Peek(1);
|
||||
VectorSlotPair pair =
|
||||
CreateVectorSlotPair(property->PropertyFeedbackSlot());
|
||||
old_value = BuildKeyedLoad(object, key, pair);
|
||||
old_value =
|
||||
BuildKeyedLoad(object, key, pair, property->PropertyFeedbackId());
|
||||
PrepareFrameState(old_value, property->LoadId(),
|
||||
OutputFrameStateCombine::Push());
|
||||
break;
|
||||
@ -1988,14 +1996,16 @@ void AstGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
case NAMED_PROPERTY: {
|
||||
Node* object = environment()->Pop();
|
||||
Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
|
||||
Node* store = BuildNamedStore(object, name, value);
|
||||
Node* store =
|
||||
BuildNamedStore(object, name, value, expr->AssignmentFeedbackId());
|
||||
PrepareFrameState(store, expr->id(), ast_context()->GetStateCombine());
|
||||
break;
|
||||
}
|
||||
case KEYED_PROPERTY: {
|
||||
Node* key = environment()->Pop();
|
||||
Node* object = environment()->Pop();
|
||||
Node* store = BuildKeyedStore(object, key, value);
|
||||
Node* store =
|
||||
BuildKeyedStore(object, key, value, expr->AssignmentFeedbackId());
|
||||
PrepareFrameStateAfterAndBefore(store, expr->id(),
|
||||
ast_context()->GetStateCombine(),
|
||||
frame_state_before_store);
|
||||
@ -2029,13 +2039,13 @@ void AstGraphBuilder::VisitProperty(Property* expr) {
|
||||
VisitForValue(expr->obj());
|
||||
Node* object = environment()->Pop();
|
||||
Handle<Name> name = expr->key()->AsLiteral()->AsPropertyName();
|
||||
value = BuildNamedLoad(object, name, pair);
|
||||
value = BuildNamedLoad(object, name, pair, expr->PropertyFeedbackId());
|
||||
} else {
|
||||
VisitForValue(expr->obj());
|
||||
VisitForValue(expr->key());
|
||||
Node* key = environment()->Pop();
|
||||
Node* object = environment()->Pop();
|
||||
value = BuildKeyedLoad(object, key, pair);
|
||||
value = BuildKeyedLoad(object, key, pair, expr->PropertyFeedbackId());
|
||||
}
|
||||
PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
|
||||
ast_context()->ProduceValue(value);
|
||||
@ -2083,11 +2093,13 @@ void AstGraphBuilder::VisitCall(Call* expr) {
|
||||
CreateVectorSlotPair(property->PropertyFeedbackSlot());
|
||||
if (property->key()->IsPropertyName()) {
|
||||
Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
|
||||
callee_value = BuildNamedLoad(object, name, pair);
|
||||
callee_value =
|
||||
BuildNamedLoad(object, name, pair, property->PropertyFeedbackId());
|
||||
} else {
|
||||
VisitForValue(property->key());
|
||||
Node* key = environment()->Pop();
|
||||
callee_value = BuildKeyedLoad(object, key, pair);
|
||||
callee_value =
|
||||
BuildKeyedLoad(object, key, pair, property->PropertyFeedbackId());
|
||||
}
|
||||
PrepareFrameState(callee_value, property->LoadId(),
|
||||
OutputFrameStateCombine::Push());
|
||||
@ -2183,7 +2195,8 @@ void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) {
|
||||
CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS;
|
||||
Node* receiver_value = BuildLoadBuiltinsObject();
|
||||
VectorSlotPair pair = CreateVectorSlotPair(expr->CallRuntimeFeedbackSlot());
|
||||
Node* callee_value = BuildNamedLoad(receiver_value, name, pair);
|
||||
Node* callee_value =
|
||||
BuildNamedLoad(receiver_value, name, pair, expr->CallRuntimeFeedbackId());
|
||||
// TODO(jarin): Find/create a bailout id to deoptimize to (crankshaft
|
||||
// refuses to optimize functions with jsruntime calls).
|
||||
PrepareFrameState(callee_value, BailoutId::None(),
|
||||
@ -2271,7 +2284,8 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
||||
Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
|
||||
VectorSlotPair pair =
|
||||
CreateVectorSlotPair(property->PropertyFeedbackSlot());
|
||||
old_value = BuildNamedLoad(object, name, pair);
|
||||
old_value =
|
||||
BuildNamedLoad(object, name, pair, property->PropertyFeedbackId());
|
||||
PrepareFrameState(old_value, property->LoadId(),
|
||||
OutputFrameStateCombine::Push());
|
||||
stack_depth = 1;
|
||||
@ -2284,7 +2298,8 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
||||
Node* object = environment()->Peek(1);
|
||||
VectorSlotPair pair =
|
||||
CreateVectorSlotPair(property->PropertyFeedbackSlot());
|
||||
old_value = BuildKeyedLoad(object, key, pair);
|
||||
old_value =
|
||||
BuildKeyedLoad(object, key, pair, property->PropertyFeedbackId());
|
||||
PrepareFrameState(old_value, property->LoadId(),
|
||||
OutputFrameStateCombine::Push());
|
||||
stack_depth = 2;
|
||||
@ -2327,7 +2342,8 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
||||
case NAMED_PROPERTY: {
|
||||
Node* object = environment()->Pop();
|
||||
Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
|
||||
Node* store = BuildNamedStore(object, name, value);
|
||||
Node* store =
|
||||
BuildNamedStore(object, name, value, expr->CountStoreFeedbackId());
|
||||
environment()->Push(value);
|
||||
PrepareFrameState(store, expr->AssignmentId());
|
||||
environment()->Pop();
|
||||
@ -2336,7 +2352,8 @@ void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
||||
case KEYED_PROPERTY: {
|
||||
Node* key = environment()->Pop();
|
||||
Node* object = environment()->Pop();
|
||||
Node* store = BuildKeyedStore(object, key, value);
|
||||
Node* store =
|
||||
BuildKeyedStore(object, key, value, expr->CountStoreFeedbackId());
|
||||
environment()->Push(value);
|
||||
PrepareFrameStateAfterAndBefore(store, expr->AssignmentId(),
|
||||
OutputFrameStateCombine::Ignore(),
|
||||
@ -2745,7 +2762,8 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
|
||||
// Global var, const, or let variable.
|
||||
Node* global = BuildLoadGlobalObject();
|
||||
Handle<Name> name = variable->name();
|
||||
Node* node = BuildNamedLoad(global, name, feedback, contextual_mode);
|
||||
Node* node = BuildNamedLoad(global, name, feedback,
|
||||
TypeFeedbackId::None(), contextual_mode);
|
||||
PrepareFrameState(node, bailout_id, OutputFrameStateCombine::Push());
|
||||
return node;
|
||||
}
|
||||
@ -2852,7 +2870,8 @@ Node* AstGraphBuilder::BuildVariableAssignment(
|
||||
// Global var, const, or let variable.
|
||||
Node* global = BuildLoadGlobalObject();
|
||||
Handle<Name> name = variable->name();
|
||||
Node* store = BuildNamedStore(global, name, value);
|
||||
Node* store =
|
||||
BuildNamedStore(global, name, value, TypeFeedbackId::None());
|
||||
PrepareFrameState(store, bailout_id, combine);
|
||||
return store;
|
||||
}
|
||||
@ -2948,33 +2967,42 @@ Node* AstGraphBuilder::BuildVariableAssignment(
|
||||
}
|
||||
|
||||
|
||||
static inline Node* Record(JSTypeFeedbackTable* js_type_feedback, Node* node,
|
||||
TypeFeedbackId id) {
|
||||
if (js_type_feedback) js_type_feedback->Record(node, id);
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
Node* AstGraphBuilder::BuildKeyedLoad(Node* object, Node* key,
|
||||
const VectorSlotPair& feedback) {
|
||||
const VectorSlotPair& feedback,
|
||||
TypeFeedbackId id) {
|
||||
const Operator* op = javascript()->LoadProperty(feedback);
|
||||
return NewNode(op, object, key);
|
||||
return Record(js_type_feedback_, NewNode(op, object, key), id);
|
||||
}
|
||||
|
||||
|
||||
Node* AstGraphBuilder::BuildNamedLoad(Node* object, Handle<Name> name,
|
||||
const VectorSlotPair& feedback,
|
||||
ContextualMode mode) {
|
||||
TypeFeedbackId id, ContextualMode mode) {
|
||||
const Operator* op =
|
||||
javascript()->LoadNamed(MakeUnique(name), feedback, mode);
|
||||
return NewNode(op, object);
|
||||
return Record(js_type_feedback_, NewNode(op, object), id);
|
||||
}
|
||||
|
||||
|
||||
Node* AstGraphBuilder::BuildKeyedStore(Node* object, Node* key, Node* value) {
|
||||
Node* AstGraphBuilder::BuildKeyedStore(Node* object, Node* key, Node* value,
|
||||
TypeFeedbackId id) {
|
||||
const Operator* op = javascript()->StoreProperty(language_mode());
|
||||
return NewNode(op, object, key, value);
|
||||
return Record(js_type_feedback_, NewNode(op, object, key, value), id);
|
||||
}
|
||||
|
||||
|
||||
Node* AstGraphBuilder::BuildNamedStore(Node* object, Handle<Name> name,
|
||||
Node* value) {
|
||||
Node* value, TypeFeedbackId id) {
|
||||
const Operator* op =
|
||||
javascript()->StoreNamed(language_mode(), MakeUnique(name));
|
||||
return NewNode(op, object, value);
|
||||
return Record(js_type_feedback_, NewNode(op, object, value), id);
|
||||
}
|
||||
|
||||
|
||||
@ -3063,7 +3091,8 @@ Node* AstGraphBuilder::BuildSetHomeObject(Node* value, Node* home_object,
|
||||
Expression* expr) {
|
||||
if (!FunctionLiteral::NeedsHomeObject(expr)) return value;
|
||||
Handle<Name> name = isolate()->factory()->home_object_symbol();
|
||||
Node* store = BuildNamedStore(value, name, home_object);
|
||||
Node* store =
|
||||
BuildNamedStore(value, name, home_object, TypeFeedbackId::None());
|
||||
PrepareFrameState(store, BailoutId::None());
|
||||
return store;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ namespace compiler {
|
||||
|
||||
class ControlBuilder;
|
||||
class Graph;
|
||||
class JSTypeFeedbackTable;
|
||||
class LoopAssignmentAnalysis;
|
||||
class LoopBuilder;
|
||||
class Node;
|
||||
@ -30,7 +31,8 @@ class Node;
|
||||
class AstGraphBuilder : public AstVisitor {
|
||||
public:
|
||||
AstGraphBuilder(Zone* local_zone, CompilationInfo* info, JSGraph* jsgraph,
|
||||
LoopAssignmentAnalysis* loop_assignment = NULL);
|
||||
LoopAssignmentAnalysis* loop_assignment = NULL,
|
||||
JSTypeFeedbackTable* js_type_feedback = NULL);
|
||||
|
||||
// Creates a graph by visiting the entire AST.
|
||||
bool CreateGraph(bool constant_context, bool stack_check = true);
|
||||
@ -105,6 +107,9 @@ class AstGraphBuilder : public AstVisitor {
|
||||
// Analyzer of local variable liveness.
|
||||
LivenessAnalyzer liveness_analyzer_;
|
||||
|
||||
// Type feedback table.
|
||||
JSTypeFeedbackTable* js_type_feedback_;
|
||||
|
||||
// Growth increment for the temporary buffer used to construct input lists to
|
||||
// new nodes.
|
||||
static const int kInputBufferSizeIncrement = 64;
|
||||
@ -263,12 +268,14 @@ class AstGraphBuilder : public AstVisitor {
|
||||
|
||||
// Builders for property loads and stores.
|
||||
Node* BuildKeyedLoad(Node* receiver, Node* key,
|
||||
const VectorSlotPair& feedback);
|
||||
const VectorSlotPair& feedback, TypeFeedbackId id);
|
||||
Node* BuildNamedLoad(Node* receiver, Handle<Name> name,
|
||||
const VectorSlotPair& feedback,
|
||||
const VectorSlotPair& feedback, TypeFeedbackId id,
|
||||
ContextualMode mode = NOT_CONTEXTUAL);
|
||||
Node* BuildKeyedStore(Node* receiver, Node* key, Node* value);
|
||||
Node* BuildNamedStore(Node* receiver, Handle<Name>, Node* value);
|
||||
Node* BuildKeyedStore(Node* receiver, Node* key, Node* value,
|
||||
TypeFeedbackId id);
|
||||
Node* BuildNamedStore(Node* receiver, Handle<Name>, Node* value,
|
||||
TypeFeedbackId id);
|
||||
|
||||
// Builders for accessing the function context.
|
||||
Node* BuildLoadBuiltinsObject();
|
||||
|
@ -111,15 +111,7 @@ Reduction JSIntrinsicLowering::ReduceDeoptimizeNow(Node* node) {
|
||||
graph()->NewNode(common()->Deoptimize(), frame_state, effect, if_true);
|
||||
|
||||
// Connect the deopt to the merge exiting the graph.
|
||||
Node* end_pred = NodeProperties::GetControlInput(graph()->end());
|
||||
if (end_pred->opcode() == IrOpcode::kMerge) {
|
||||
int inputs = end_pred->op()->ControlInputCount() + 1;
|
||||
end_pred->AppendInput(graph()->zone(), deopt);
|
||||
end_pred->set_op(common()->Merge(inputs));
|
||||
} else {
|
||||
Node* merge = graph()->NewNode(common()->Merge(2), end_pred, deopt);
|
||||
NodeProperties::ReplaceControlInput(graph()->end(), merge);
|
||||
}
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), deopt);
|
||||
|
||||
return Changed(deopt);
|
||||
}
|
||||
|
256
src/compiler/js-type-feedback.cc
Normal file
256
src/compiler/js-type-feedback.cc
Normal file
@ -0,0 +1,256 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/compiler/js-type-feedback.h"
|
||||
|
||||
#include "src/property-details.h"
|
||||
|
||||
#include "src/accessors.h"
|
||||
#include "src/ast.h"
|
||||
#include "src/type-info.h"
|
||||
|
||||
#include "src/compiler/access-builder.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/node-aux-data.h"
|
||||
#include "src/compiler/simplified-operator.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
enum LoadOrStore { LOAD, STORE };
|
||||
|
||||
JSTypeFeedbackTable::JSTypeFeedbackTable(Zone* zone)
|
||||
: map_(TypeFeedbackIdMap::key_compare(),
|
||||
TypeFeedbackIdMap::allocator_type(zone)) {}
|
||||
|
||||
|
||||
void JSTypeFeedbackTable::Record(Node* node, TypeFeedbackId id) {
|
||||
map_.insert(std::make_pair(node->id(), id));
|
||||
}
|
||||
|
||||
|
||||
Reduction JSTypeFeedbackSpecializer::Reduce(Node* node) {
|
||||
// TODO(turbofan): type feedback currently requires deoptimization.
|
||||
if (!FLAG_turbo_deoptimization) return NoChange();
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kJSLoadProperty:
|
||||
return ReduceJSLoadProperty(node);
|
||||
case IrOpcode::kJSLoadNamed:
|
||||
return ReduceJSLoadNamed(node);
|
||||
case IrOpcode::kJSStoreNamed:
|
||||
return ReduceJSStoreNamed(node);
|
||||
case IrOpcode::kJSStoreProperty:
|
||||
return ReduceJSStoreProperty(node);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
|
||||
static bool GetInObjectFieldAccess(LoadOrStore mode, Handle<Map> map,
|
||||
Handle<Name> name, FieldAccess* access) {
|
||||
access->base_is_tagged = kTaggedBase;
|
||||
access->offset = -1;
|
||||
access->name = name;
|
||||
access->type = Type::Any();
|
||||
access->machine_type = kMachAnyTagged;
|
||||
|
||||
// Check for properties that have accessors but are JSObject fields.
|
||||
if (Accessors::IsJSObjectFieldAccessor(map, name, &access->offset)) {
|
||||
// TODO(turbofan): fill in types for special JSObject field accesses.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the map is a dictionary.
|
||||
if (map->is_dictionary_map()) return false;
|
||||
|
||||
// Search the descriptor array.
|
||||
DescriptorArray* descriptors = map->instance_descriptors();
|
||||
int number = descriptors->SearchWithCache(*name, *map);
|
||||
if (number == DescriptorArray::kNotFound) return false;
|
||||
PropertyDetails property_details = descriptors->GetDetails(number);
|
||||
|
||||
bool is_smi = property_details.representation().IsSmi();
|
||||
bool is_double = property_details.representation().IsDouble();
|
||||
|
||||
if (property_details.type() != DATA) {
|
||||
// TODO(turbofan): constant loads and stores.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mode == STORE) {
|
||||
if (property_details.IsReadOnly()) return false;
|
||||
if (is_smi) {
|
||||
// TODO(turbofan): SMI stores.
|
||||
return false;
|
||||
}
|
||||
if (is_double) {
|
||||
// TODO(turbofan): double stores.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Check property details for loads.
|
||||
if (is_smi) {
|
||||
access->type = Type::SignedSmall();
|
||||
access->machine_type = static_cast<MachineType>(kTypeInt32 | kRepTagged);
|
||||
}
|
||||
if (is_double) {
|
||||
access->type = Type::Number();
|
||||
access->machine_type = kMachFloat64;
|
||||
}
|
||||
}
|
||||
|
||||
int index = map->instance_descriptors()->GetFieldIndex(number);
|
||||
FieldIndex field_index = FieldIndex::ForPropertyIndex(*map, index, is_double);
|
||||
|
||||
if (field_index.is_inobject()) {
|
||||
access->offset = field_index.offset();
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(turbofan): handle out of object properties.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) {
|
||||
DCHECK(node->opcode() == IrOpcode::kJSLoadNamed);
|
||||
TypeFeedbackId id = js_type_feedback_->find(node);
|
||||
if (id.IsNone() || oracle()->LoadIsUninitialized(id)) return NoChange();
|
||||
|
||||
const LoadNamedParameters& p = LoadNamedParametersOf(node->op());
|
||||
SmallMapList maps;
|
||||
Handle<Name> name = p.name().handle();
|
||||
Node* receiver = node->InputAt(0);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
GatherReceiverTypes(receiver, effect, id, name, &maps);
|
||||
|
||||
if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism
|
||||
|
||||
Handle<Map> map = maps.first();
|
||||
FieldAccess field_access;
|
||||
if (!GetInObjectFieldAccess(LOAD, map, name, &field_access)) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
Node* check_success;
|
||||
Node* check_failed;
|
||||
BuildMapCheck(receiver, map, true, effect, control, &check_success,
|
||||
&check_failed);
|
||||
|
||||
// Build the actual load.
|
||||
Node* load = graph()->NewNode(simplified()->LoadField(field_access), receiver,
|
||||
effect, check_success);
|
||||
|
||||
// TODO(turbofan): handle slow case instead of deoptimizing.
|
||||
// TODO(titzer): frame state should be from before the load.
|
||||
Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
|
||||
Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect,
|
||||
check_failed);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), deopt);
|
||||
NodeProperties::ReplaceWithValue(node, load, load, check_success);
|
||||
return Replace(load);
|
||||
}
|
||||
|
||||
|
||||
Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
|
||||
Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) {
|
||||
DCHECK(node->opcode() == IrOpcode::kJSStoreNamed);
|
||||
TypeFeedbackId id = js_type_feedback_->find(node);
|
||||
if (id.IsNone() || oracle()->StoreIsUninitialized(id)) return NoChange();
|
||||
|
||||
const StoreNamedParameters& p = StoreNamedParametersOf(node->op());
|
||||
SmallMapList maps;
|
||||
Handle<Name> name = p.name().handle();
|
||||
Node* receiver = node->InputAt(0);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
GatherReceiverTypes(receiver, effect, id, name, &maps);
|
||||
|
||||
if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism
|
||||
|
||||
Handle<Map> map = maps.first();
|
||||
FieldAccess field_access;
|
||||
if (!GetInObjectFieldAccess(STORE, map, name, &field_access)) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
Node* check_success;
|
||||
Node* check_failed;
|
||||
BuildMapCheck(receiver, map, true, effect, control, &check_success,
|
||||
&check_failed);
|
||||
|
||||
// Build the actual load.
|
||||
Node* value = node->InputAt(1);
|
||||
Node* store = graph()->NewNode(simplified()->StoreField(field_access),
|
||||
receiver, value, effect, check_success);
|
||||
|
||||
// TODO(turbofan): handle slow case instead of deoptimizing.
|
||||
// TODO(titzer): frame state should be from before the store.
|
||||
Node* frame_state = NodeProperties::GetFrameStateInput(node, 0);
|
||||
Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect,
|
||||
check_failed);
|
||||
NodeProperties::MergeControlToEnd(graph(), common(), deopt);
|
||||
NodeProperties::ReplaceWithValue(node, store, store, check_success);
|
||||
return Replace(store);
|
||||
}
|
||||
|
||||
|
||||
Reduction JSTypeFeedbackSpecializer::ReduceJSStoreProperty(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
|
||||
void JSTypeFeedbackSpecializer::BuildMapCheck(Node* receiver, Handle<Map> map,
|
||||
bool smi_check, Node* effect,
|
||||
Node* control, Node** success,
|
||||
Node** fail) {
|
||||
Node* if_smi = nullptr;
|
||||
if (smi_check) {
|
||||
Node* branch_smi = graph()->NewNode(
|
||||
common()->Branch(BranchHint::kFalse),
|
||||
graph()->NewNode(simplified()->ObjectIsSmi(), receiver), control);
|
||||
if_smi = graph()->NewNode(common()->IfTrue(), branch_smi);
|
||||
control = graph()->NewNode(common()->IfFalse(), branch_smi);
|
||||
}
|
||||
|
||||
FieldAccess map_access = AccessBuilder::ForMap();
|
||||
Node* receiver_map = graph()->NewNode(simplified()->LoadField(map_access),
|
||||
receiver, effect, control);
|
||||
Node* map_const = jsgraph_->Constant(map);
|
||||
Node* cmp = graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
|
||||
receiver_map, map_const);
|
||||
Node* branch =
|
||||
graph()->NewNode(common()->Branch(BranchHint::kTrue), cmp, control);
|
||||
*success = graph()->NewNode(common()->IfTrue(), branch);
|
||||
*fail = graph()->NewNode(common()->IfFalse(), branch);
|
||||
|
||||
if (if_smi) {
|
||||
*fail = graph()->NewNode(common()->Merge(2), *fail, if_smi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void JSTypeFeedbackSpecializer::GatherReceiverTypes(Node* receiver,
|
||||
Node* effect,
|
||||
TypeFeedbackId id,
|
||||
Handle<Name> name,
|
||||
SmallMapList* maps) {
|
||||
// TODO(turbofan): filter maps by initial receiver map if known
|
||||
// TODO(turbofan): filter maps by native context (if specializing)
|
||||
// TODO(turbofan): filter maps by effect chain
|
||||
oracle()->PropertyReceiverTypes(id, name, maps);
|
||||
}
|
||||
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
91
src/compiler/js-type-feedback.h
Normal file
91
src/compiler/js-type-feedback.h
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_COMPILER_JS_TYPE_FEEDBACK_H_
|
||||
#define V8_COMPILER_JS_TYPE_FEEDBACK_H_
|
||||
|
||||
#include "src/utils.h"
|
||||
|
||||
#include "src/compiler/graph-reducer.h"
|
||||
#include "src/compiler/js-graph.h"
|
||||
#include "src/compiler/node-aux-data.h"
|
||||
#include "src/compiler/simplified-operator.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class TypeFeedbackOracle;
|
||||
class SmallMapList;
|
||||
|
||||
namespace compiler {
|
||||
|
||||
// Stores type feedback information for nodes in the graph in a separate
|
||||
// data structure.
|
||||
class JSTypeFeedbackTable : public ZoneObject {
|
||||
public:
|
||||
explicit JSTypeFeedbackTable(Zone* zone);
|
||||
|
||||
// TODO(titzer): support recording the feedback vector slot.
|
||||
|
||||
void Record(Node* node, TypeFeedbackId id);
|
||||
|
||||
private:
|
||||
friend class JSTypeFeedbackSpecializer;
|
||||
typedef std::map<NodeId, TypeFeedbackId, std::less<NodeId>,
|
||||
zone_allocator<TypeFeedbackId> > TypeFeedbackIdMap;
|
||||
|
||||
TypeFeedbackIdMap map_;
|
||||
|
||||
TypeFeedbackId find(Node* node) {
|
||||
TypeFeedbackIdMap::const_iterator it = map_.find(node->id());
|
||||
return it == map_.end() ? TypeFeedbackId::None() : it->second;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Specializes a graph to the type feedback recorded in the
|
||||
// {js_type_feedback} provided to the constructor.
|
||||
class JSTypeFeedbackSpecializer : public Reducer {
|
||||
public:
|
||||
JSTypeFeedbackSpecializer(JSGraph* jsgraph,
|
||||
JSTypeFeedbackTable* js_type_feedback,
|
||||
TypeFeedbackOracle* oracle)
|
||||
: jsgraph_(jsgraph),
|
||||
simplified_(jsgraph->graph()->zone()),
|
||||
js_type_feedback_(js_type_feedback),
|
||||
oracle_(oracle) {
|
||||
CHECK(js_type_feedback);
|
||||
}
|
||||
|
||||
Reduction Reduce(Node* node) OVERRIDE;
|
||||
|
||||
// Visible for unit testing.
|
||||
Reduction ReduceJSLoadNamed(Node* node);
|
||||
Reduction ReduceJSLoadProperty(Node* node);
|
||||
Reduction ReduceJSStoreNamed(Node* node);
|
||||
Reduction ReduceJSStoreProperty(Node* node);
|
||||
|
||||
private:
|
||||
JSGraph* jsgraph_;
|
||||
SimplifiedOperatorBuilder simplified_;
|
||||
JSTypeFeedbackTable* js_type_feedback_;
|
||||
TypeFeedbackOracle* oracle_;
|
||||
|
||||
TypeFeedbackOracle* oracle() { return oracle_; }
|
||||
Graph* graph() { return jsgraph_->graph(); }
|
||||
CommonOperatorBuilder* common() { return jsgraph_->common(); }
|
||||
SimplifiedOperatorBuilder* simplified() { return &simplified_; }
|
||||
|
||||
void BuildMapCheck(Node* receiver, Handle<Map> map, bool smi_check,
|
||||
Node* effect, Node* control, Node** success, Node** fail);
|
||||
|
||||
void GatherReceiverTypes(Node* receiver, Node* effect, TypeFeedbackId id,
|
||||
Handle<Name> property, SmallMapList* maps);
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif
|
@ -2,9 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/compiler/node-properties.h"
|
||||
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/node-properties.h"
|
||||
#include "src/compiler/operator-properties.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -151,6 +151,22 @@ void NodeProperties::RemoveNonValueInputs(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
void NodeProperties::MergeControlToEnd(Graph* graph,
|
||||
CommonOperatorBuilder* common,
|
||||
Node* node) {
|
||||
// Connect the node to the merge exiting the graph.
|
||||
Node* end_pred = NodeProperties::GetControlInput(graph->end());
|
||||
if (end_pred->opcode() == IrOpcode::kMerge) {
|
||||
int inputs = end_pred->op()->ControlInputCount() + 1;
|
||||
end_pred->AppendInput(graph->zone(), node);
|
||||
end_pred->set_op(common->Merge(inputs));
|
||||
} else {
|
||||
Node* merge = graph->NewNode(common->Merge(2), end_pred, node);
|
||||
NodeProperties::ReplaceControlInput(graph->end(), merge);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void NodeProperties::ReplaceWithValue(Node* node, Node* value, Node* effect,
|
||||
Node* control) {
|
||||
|
@ -12,7 +12,9 @@ namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
class Graph;
|
||||
class Operator;
|
||||
class CommonOperatorBuilder;
|
||||
|
||||
// A facade that simplifies access to the different kinds of inputs to a node.
|
||||
class NodeProperties FINAL {
|
||||
@ -80,6 +82,11 @@ class NodeProperties FINAL {
|
||||
static void ReplaceFrameStateInput(Node* node, int index, Node* frame_state);
|
||||
static void RemoveNonValueInputs(Node* node);
|
||||
|
||||
// Merge the control node {node} into the end of the graph, introducing a
|
||||
// merge node or expanding an existing merge node if necessary.
|
||||
static void MergeControlToEnd(Graph* graph, CommonOperatorBuilder* common,
|
||||
Node* node);
|
||||
|
||||
// Replace value uses of {node} with {value} and effect uses of {node} with
|
||||
// {effect}. If {effect == NULL}, then use the effect input to {node}. All
|
||||
// control uses will be relaxed assuming {node} cannot throw.
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "src/compiler/js-generic-lowering.h"
|
||||
#include "src/compiler/js-inlining.h"
|
||||
#include "src/compiler/js-intrinsic-lowering.h"
|
||||
#include "src/compiler/js-type-feedback.h"
|
||||
#include "src/compiler/js-typed-lowering.h"
|
||||
#include "src/compiler/jump-threading.h"
|
||||
#include "src/compiler/load-elimination.h"
|
||||
@ -46,6 +47,7 @@
|
||||
#include "src/compiler/verifier.h"
|
||||
#include "src/compiler/zone-pool.h"
|
||||
#include "src/ostreams.h"
|
||||
#include "src/type-info.h"
|
||||
#include "src/utils.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -72,6 +74,7 @@ class PipelineData {
|
||||
common_(nullptr),
|
||||
javascript_(nullptr),
|
||||
jsgraph_(nullptr),
|
||||
js_type_feedback_(nullptr),
|
||||
typer_(nullptr),
|
||||
schedule_(nullptr),
|
||||
instruction_zone_scope_(zone_pool_),
|
||||
@ -111,6 +114,7 @@ class PipelineData {
|
||||
common_(nullptr),
|
||||
javascript_(nullptr),
|
||||
jsgraph_(nullptr),
|
||||
js_type_feedback_(nullptr),
|
||||
typer_(nullptr),
|
||||
schedule_(schedule),
|
||||
instruction_zone_scope_(zone_pool_),
|
||||
@ -137,6 +141,7 @@ class PipelineData {
|
||||
common_(nullptr),
|
||||
javascript_(nullptr),
|
||||
jsgraph_(nullptr),
|
||||
js_type_feedback_(nullptr),
|
||||
typer_(nullptr),
|
||||
schedule_(nullptr),
|
||||
instruction_zone_scope_(zone_pool_),
|
||||
@ -174,6 +179,10 @@ class PipelineData {
|
||||
CommonOperatorBuilder* common() const { return common_; }
|
||||
JSOperatorBuilder* javascript() const { return javascript_; }
|
||||
JSGraph* jsgraph() const { return jsgraph_; }
|
||||
JSTypeFeedbackTable* js_type_feedback() { return js_type_feedback_; }
|
||||
void set_js_type_feedback(JSTypeFeedbackTable* js_type_feedback) {
|
||||
js_type_feedback_ = js_type_feedback;
|
||||
}
|
||||
Typer* typer() const { return typer_.get(); }
|
||||
|
||||
LoopAssignmentAnalysis* loop_assignment() const { return loop_assignment_; }
|
||||
@ -207,6 +216,7 @@ class PipelineData {
|
||||
common_ = nullptr;
|
||||
javascript_ = nullptr;
|
||||
jsgraph_ = nullptr;
|
||||
js_type_feedback_ = nullptr;
|
||||
schedule_ = nullptr;
|
||||
}
|
||||
|
||||
@ -259,6 +269,7 @@ class PipelineData {
|
||||
CommonOperatorBuilder* common_;
|
||||
JSOperatorBuilder* javascript_;
|
||||
JSGraph* jsgraph_;
|
||||
JSTypeFeedbackTable* js_type_feedback_;
|
||||
// TODO(dcarney): make this into a ZoneObject.
|
||||
SmartPointer<Typer> typer_;
|
||||
Schedule* schedule_;
|
||||
@ -310,8 +321,10 @@ class AstGraphBuilderWithPositions : public AstGraphBuilder {
|
||||
AstGraphBuilderWithPositions(Zone* local_zone, CompilationInfo* info,
|
||||
JSGraph* jsgraph,
|
||||
LoopAssignmentAnalysis* loop_assignment,
|
||||
JSTypeFeedbackTable* js_type_feedback,
|
||||
SourcePositionTable* source_positions)
|
||||
: AstGraphBuilder(local_zone, info, jsgraph, loop_assignment),
|
||||
: AstGraphBuilder(local_zone, info, jsgraph, loop_assignment,
|
||||
js_type_feedback),
|
||||
source_positions_(source_positions),
|
||||
start_position_(info->shared_info()->start_position()) {}
|
||||
|
||||
@ -419,7 +432,7 @@ struct GraphBuilderPhase {
|
||||
void Run(PipelineData* data, Zone* temp_zone, bool constant_context) {
|
||||
AstGraphBuilderWithPositions graph_builder(
|
||||
temp_zone, data->info(), data->jsgraph(), data->loop_assignment(),
|
||||
data->source_positions());
|
||||
data->js_type_feedback(), data->source_positions());
|
||||
bool stack_check = !data->info()->IsStub();
|
||||
if (!graph_builder.CreateGraph(constant_context, stack_check)) {
|
||||
data->set_compilation_failed();
|
||||
@ -480,6 +493,25 @@ struct OsrDeconstructionPhase {
|
||||
};
|
||||
|
||||
|
||||
struct JSTypeFeedbackPhase {
|
||||
static const char* phase_name() { return "type feedback specializing"; }
|
||||
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
SourcePositionTable::Scope pos(data->source_positions(),
|
||||
SourcePosition::Unknown());
|
||||
Handle<Context> native_context(data->info()->context()->native_context());
|
||||
TypeFeedbackOracle oracle(data->isolate(), temp_zone,
|
||||
data->info()->unoptimized_code(),
|
||||
data->info()->feedback_vector(), native_context);
|
||||
GraphReducer graph_reducer(data->graph(), temp_zone);
|
||||
JSTypeFeedbackSpecializer specializer(data->jsgraph(),
|
||||
data->js_type_feedback(), &oracle);
|
||||
AddReducer(data, &graph_reducer, &specializer);
|
||||
graph_reducer.ReduceGraph();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct TypedLoweringPhase {
|
||||
static const char* phase_name() { return "typed lowering"; }
|
||||
|
||||
@ -884,6 +916,11 @@ Handle<Code> Pipeline::GenerateCode() {
|
||||
PipelineData data(&zone_pool, info(), pipeline_statistics.get());
|
||||
this->data_ = &data;
|
||||
|
||||
if (info()->is_type_feedback_enabled()) {
|
||||
data.set_js_type_feedback(new (data.graph_zone())
|
||||
JSTypeFeedbackTable(data.graph_zone()));
|
||||
}
|
||||
|
||||
BeginPhaseKind("graph creation");
|
||||
|
||||
if (FLAG_trace_turbo) {
|
||||
@ -951,6 +988,11 @@ Handle<Code> Pipeline::GenerateCode() {
|
||||
RunPrintAndVerify("OSR deconstruction");
|
||||
}
|
||||
|
||||
if (info()->is_type_feedback_enabled()) {
|
||||
Run<JSTypeFeedbackPhase>();
|
||||
RunPrintAndVerify("JSType feedback");
|
||||
}
|
||||
|
||||
// Lower simplified operators and insert changes.
|
||||
Run<SimplifiedLoweringPhase>();
|
||||
RunPrintAndVerify("Lowered simplified");
|
||||
@ -963,7 +1005,7 @@ Handle<Code> Pipeline::GenerateCode() {
|
||||
|
||||
// Lower changes that have been inserted before.
|
||||
Run<ChangeLoweringPhase>();
|
||||
// // TODO(jarin, rossberg): Remove UNTYPED once machine typing works.
|
||||
// TODO(jarin, rossberg): Remove UNTYPED once machine typing works.
|
||||
RunPrintAndVerify("Lowered changes", true);
|
||||
|
||||
Run<LateControlReductionPhase>();
|
||||
|
@ -618,10 +618,6 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
case IrOpcode::kReferenceEqual: {
|
||||
// (Unique, Any) -> Boolean and
|
||||
// (Any, Unique) -> Boolean
|
||||
if (typing == TYPED) {
|
||||
CHECK(bounds(ValueInput(node, 0)).upper->Is(Type::Unique()) ||
|
||||
bounds(ValueInput(node, 1)).upper->Is(Type::Unique()));
|
||||
}
|
||||
CheckUpperIs(node, Type::Boolean());
|
||||
break;
|
||||
}
|
||||
|
@ -398,6 +398,7 @@ DEFINE_BOOL(turbo_verify, DEBUG_BOOL, "verify TurboFan graphs at each phase")
|
||||
DEFINE_BOOL(turbo_stats, false, "print TurboFan statistics")
|
||||
DEFINE_BOOL(turbo_splitting, true, "split nodes during scheduling in TurboFan")
|
||||
DEFINE_BOOL(turbo_types, true, "use typed lowering in TurboFan")
|
||||
DEFINE_BOOL(turbo_type_feedback, false, "use type feedback in TurboFan")
|
||||
DEFINE_BOOL(turbo_source_positions, false,
|
||||
"track source code positions when building TurboFan IR")
|
||||
DEFINE_IMPLICATION(trace_turbo, turbo_source_positions)
|
||||
|
@ -267,7 +267,7 @@ TypeImpl<Config>::BitsetType::Lub(i::Map* map) {
|
||||
// Also, it doesn't apply elsewhere. 8-(
|
||||
// We ought to find a cleaner solution for compiling stubs parameterised
|
||||
// over type or class variables, esp ones with bounds...
|
||||
return kDetectable;
|
||||
return kDetectable & kTaggedPointer;
|
||||
case DECLARED_ACCESSOR_INFO_TYPE:
|
||||
case EXECUTABLE_ACCESSOR_INFO_TYPE:
|
||||
case SHARED_FUNCTION_INFO_TYPE:
|
||||
|
@ -471,6 +471,8 @@
|
||||
'../../src/compiler/js-intrinsic-lowering.h',
|
||||
'../../src/compiler/js-operator.cc',
|
||||
'../../src/compiler/js-operator.h',
|
||||
'../../src/compiler/js-type-feedback.cc',
|
||||
'../../src/compiler/js-type-feedback.h',
|
||||
'../../src/compiler/js-typed-lowering.cc',
|
||||
'../../src/compiler/js-typed-lowering.h',
|
||||
'../../src/compiler/jump-threading.cc',
|
||||
|
Loading…
Reference in New Issue
Block a user