Count closures using the feedback vector cell map, specialize if count==1.
This introduces new maps to track whether we have created at most one closure. If we have created just one closure, Turbofan will specialize the code to its context. Review-Url: https://codereview.chromium.org/2680313002 Cr-Commit-Position: refs/heads/master@{#43108}
This commit is contained in:
parent
0a9d4a3b0c
commit
36ed494784
@ -126,6 +126,26 @@ Node* ConstructorBuiltinsAssembler::EmitFastNewClosure(Node* shared_info,
|
|||||||
empty_fixed_array);
|
empty_fixed_array);
|
||||||
Node* literals_cell = LoadFixedArrayElement(
|
Node* literals_cell = LoadFixedArrayElement(
|
||||||
feedback_vector, slot, 0, CodeStubAssembler::SMI_PARAMETERS);
|
feedback_vector, slot, 0, CodeStubAssembler::SMI_PARAMETERS);
|
||||||
|
{
|
||||||
|
// Bump the closure counter encoded in the cell's map.
|
||||||
|
Node* cell_map = LoadMap(literals_cell);
|
||||||
|
Label no_closures(this), one_closure(this), cell_done(this);
|
||||||
|
|
||||||
|
GotoIf(IsNoClosuresCellMap(cell_map), &no_closures);
|
||||||
|
GotoIf(IsOneClosureCellMap(cell_map), &one_closure);
|
||||||
|
CSA_ASSERT(this, IsManyClosuresCellMap(cell_map));
|
||||||
|
Goto(&cell_done);
|
||||||
|
|
||||||
|
Bind(&no_closures);
|
||||||
|
StoreMapNoWriteBarrier(literals_cell, Heap::kOneClosureCellMapRootIndex);
|
||||||
|
Goto(&cell_done);
|
||||||
|
|
||||||
|
Bind(&one_closure);
|
||||||
|
StoreMapNoWriteBarrier(literals_cell, Heap::kManyClosuresCellMapRootIndex);
|
||||||
|
Goto(&cell_done);
|
||||||
|
|
||||||
|
Bind(&cell_done);
|
||||||
|
}
|
||||||
StoreObjectFieldNoWriteBarrier(result, JSFunction::kFeedbackVectorOffset,
|
StoreObjectFieldNoWriteBarrier(result, JSFunction::kFeedbackVectorOffset,
|
||||||
literals_cell);
|
literals_cell);
|
||||||
StoreObjectFieldNoWriteBarrier(
|
StoreObjectFieldNoWriteBarrier(
|
||||||
|
@ -34,6 +34,9 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
|
|||||||
V(FixedDoubleArrayMap, FixedDoubleArrayMap) \
|
V(FixedDoubleArrayMap, FixedDoubleArrayMap) \
|
||||||
V(FunctionTemplateInfoMap, FunctionTemplateInfoMap) \
|
V(FunctionTemplateInfoMap, FunctionTemplateInfoMap) \
|
||||||
V(HeapNumberMap, HeapNumberMap) \
|
V(HeapNumberMap, HeapNumberMap) \
|
||||||
|
V(NoClosuresCellMap, NoClosuresCellMap) \
|
||||||
|
V(OneClosureCellMap, OneClosureCellMap) \
|
||||||
|
V(ManyClosuresCellMap, ManyClosuresCellMap) \
|
||||||
V(MinusZeroValue, MinusZero) \
|
V(MinusZeroValue, MinusZero) \
|
||||||
V(NanValue, Nan) \
|
V(NanValue, Nan) \
|
||||||
V(NullValue, Null) \
|
V(NullValue, Null) \
|
||||||
|
@ -210,8 +210,6 @@ Reduction JSCreateLowering::Reduce(Node* node) {
|
|||||||
return ReduceJSCreateArguments(node);
|
return ReduceJSCreateArguments(node);
|
||||||
case IrOpcode::kJSCreateArray:
|
case IrOpcode::kJSCreateArray:
|
||||||
return ReduceJSCreateArray(node);
|
return ReduceJSCreateArray(node);
|
||||||
case IrOpcode::kJSCreateClosure:
|
|
||||||
return ReduceJSCreateClosure(node);
|
|
||||||
case IrOpcode::kJSCreateIterResultObject:
|
case IrOpcode::kJSCreateIterResultObject:
|
||||||
return ReduceJSCreateIterResultObject(node);
|
return ReduceJSCreateIterResultObject(node);
|
||||||
case IrOpcode::kJSCreateKeyValueArray:
|
case IrOpcode::kJSCreateKeyValueArray:
|
||||||
@ -752,48 +750,6 @@ Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
|
|||||||
return ReduceNewArrayToStubCall(node, site);
|
return ReduceNewArrayToStubCall(node, site);
|
||||||
}
|
}
|
||||||
|
|
||||||
Reduction JSCreateLowering::ReduceJSCreateClosure(Node* node) {
|
|
||||||
if (!FLAG_turbo_lower_create_closure) return NoChange();
|
|
||||||
DCHECK_EQ(IrOpcode::kJSCreateClosure, node->opcode());
|
|
||||||
CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
|
|
||||||
Handle<SharedFunctionInfo> shared = p.shared_info();
|
|
||||||
Node* effect = NodeProperties::GetEffectInput(node);
|
|
||||||
Node* control = NodeProperties::GetControlInput(node);
|
|
||||||
Node* context = NodeProperties::GetContextInput(node);
|
|
||||||
|
|
||||||
int const function_map_index =
|
|
||||||
Context::FunctionMapIndex(shared->language_mode(), shared->kind());
|
|
||||||
Node* function_map = jsgraph()->HeapConstant(
|
|
||||||
handle(Map::cast(native_context()->get(function_map_index)), isolate()));
|
|
||||||
|
|
||||||
FeedbackSlot slot = p.feedback().slot();
|
|
||||||
Node* literals_cell = jsgraph()->HeapConstant(
|
|
||||||
handle(Cell::cast(p.feedback().vector()->Get(slot)), isolate()));
|
|
||||||
|
|
||||||
// Note that it is only safe to embed the raw entry point of the compile
|
|
||||||
// lazy stub into the code, because that stub is immortal and immovable.
|
|
||||||
Node* compile_entry = jsgraph()->PointerConstant(
|
|
||||||
jsgraph()->isolate()->builtins()->CompileLazy()->entry());
|
|
||||||
Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant();
|
|
||||||
Node* the_hole = jsgraph()->TheHoleConstant();
|
|
||||||
Node* undefined = jsgraph()->UndefinedConstant();
|
|
||||||
AllocationBuilder a(jsgraph(), effect, control);
|
|
||||||
STATIC_ASSERT(JSFunction::kSize == 9 * kPointerSize);
|
|
||||||
a.Allocate(JSFunction::kSize, p.pretenure());
|
|
||||||
a.Store(AccessBuilder::ForMap(), function_map);
|
|
||||||
a.Store(AccessBuilder::ForJSObjectProperties(), empty_fixed_array);
|
|
||||||
a.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array);
|
|
||||||
a.Store(AccessBuilder::ForJSFunctionFeedbackVector(), literals_cell);
|
|
||||||
a.Store(AccessBuilder::ForJSFunctionPrototypeOrInitialMap(), the_hole);
|
|
||||||
a.Store(AccessBuilder::ForJSFunctionSharedFunctionInfo(), shared);
|
|
||||||
a.Store(AccessBuilder::ForJSFunctionContext(), context);
|
|
||||||
a.Store(AccessBuilder::ForJSFunctionCodeEntry(), compile_entry);
|
|
||||||
a.Store(AccessBuilder::ForJSFunctionNextFunctionLink(), undefined);
|
|
||||||
RelaxControls(node);
|
|
||||||
a.FinishAndChange(node);
|
|
||||||
return Changed(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
Reduction JSCreateLowering::ReduceJSCreateIterResultObject(Node* node) {
|
Reduction JSCreateLowering::ReduceJSCreateIterResultObject(Node* node) {
|
||||||
DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode());
|
DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode());
|
||||||
Node* value = NodeProperties::GetValueInput(node, 0);
|
Node* value = NodeProperties::GetValueInput(node, 0);
|
||||||
|
@ -50,7 +50,6 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
|
|||||||
Reduction ReduceJSCreate(Node* node);
|
Reduction ReduceJSCreate(Node* node);
|
||||||
Reduction ReduceJSCreateArguments(Node* node);
|
Reduction ReduceJSCreateArguments(Node* node);
|
||||||
Reduction ReduceJSCreateArray(Node* node);
|
Reduction ReduceJSCreateArray(Node* node);
|
||||||
Reduction ReduceJSCreateClosure(Node* node);
|
|
||||||
Reduction ReduceJSCreateIterResultObject(Node* node);
|
Reduction ReduceJSCreateIterResultObject(Node* node);
|
||||||
Reduction ReduceJSCreateKeyValueArray(Node* node);
|
Reduction ReduceJSCreateKeyValueArray(Node* node);
|
||||||
Reduction ReduceJSCreateLiteral(Node* node);
|
Reduction ReduceJSCreateLiteral(Node* node);
|
||||||
|
@ -594,6 +594,10 @@ PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl() {
|
|||||||
if (FLAG_inline_accessors) {
|
if (FLAG_inline_accessors) {
|
||||||
info()->MarkAsAccessorInliningEnabled();
|
info()->MarkAsAccessorInliningEnabled();
|
||||||
}
|
}
|
||||||
|
if (info()->closure()->feedback_vector_cell()->map() ==
|
||||||
|
isolate()->heap()->one_closure_cell_map()) {
|
||||||
|
info()->MarkAsFunctionContextSpecializing();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!info()->is_optimizing_from_bytecode()) {
|
if (!info()->is_optimizing_from_bytecode()) {
|
||||||
if (!Compiler::EnsureDeoptimizationSupport(info())) return FAILED;
|
if (!Compiler::EnsureDeoptimizationSupport(info())) return FAILED;
|
||||||
|
@ -761,7 +761,9 @@ class FeedbackVectorFixer {
|
|||||||
|
|
||||||
for (int i = 0; i < function_instances->length(); i++) {
|
for (int i = 0; i < function_instances->length(); i++) {
|
||||||
Handle<JSFunction> fun(JSFunction::cast(function_instances->get(i)));
|
Handle<JSFunction> fun(JSFunction::cast(function_instances->get(i)));
|
||||||
fun->set_feedback_vector_cell(isolate->heap()->undefined_cell());
|
Handle<Cell> new_cell = isolate->factory()->NewManyClosuresCell(
|
||||||
|
isolate->factory()->undefined_value());
|
||||||
|
fun->set_feedback_vector_cell(*new_cell);
|
||||||
// Only create feedback vectors if we already have the metadata.
|
// Only create feedback vectors if we already have the metadata.
|
||||||
if (shared_info->is_compiled()) JSFunction::EnsureLiterals(fun);
|
if (shared_info->is_compiled()) JSFunction::EnsureLiterals(fun);
|
||||||
}
|
}
|
||||||
|
@ -1173,6 +1173,24 @@ Handle<Cell> Factory::NewCell(Handle<Object> value) {
|
|||||||
Cell);
|
Cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Handle<Cell> Factory::NewNoClosuresCell(Handle<Object> value) {
|
||||||
|
Handle<Cell> cell = NewCell(value);
|
||||||
|
cell->set_map_no_write_barrier(*no_closures_cell_map());
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<Cell> Factory::NewOneClosureCell(Handle<Object> value) {
|
||||||
|
Handle<Cell> cell = NewCell(value);
|
||||||
|
cell->set_map_no_write_barrier(*one_closure_cell_map());
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<Cell> Factory::NewManyClosuresCell(Handle<Object> value) {
|
||||||
|
Handle<Cell> cell = NewCell(value);
|
||||||
|
cell->set_map_no_write_barrier(*many_closures_cell_map());
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
Handle<PropertyCell> Factory::NewPropertyCell() {
|
Handle<PropertyCell> Factory::NewPropertyCell() {
|
||||||
CALL_HEAP_FUNCTION(
|
CALL_HEAP_FUNCTION(
|
||||||
isolate(),
|
isolate(),
|
||||||
@ -1590,6 +1608,15 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
|
|||||||
Handle<JSFunction> result =
|
Handle<JSFunction> result =
|
||||||
NewFunction(initial_map, info, context_or_undefined, pretenure);
|
NewFunction(initial_map, info, context_or_undefined, pretenure);
|
||||||
|
|
||||||
|
// Bump the closure count that is encoded in the vector cell's map.
|
||||||
|
if (vector->map() == *no_closures_cell_map()) {
|
||||||
|
vector->set_map(*one_closure_cell_map());
|
||||||
|
} else if (vector->map() == *one_closure_cell_map()) {
|
||||||
|
vector->set_map(*many_closures_cell_map());
|
||||||
|
} else {
|
||||||
|
DCHECK_EQ(vector->map(), *many_closures_cell_map());
|
||||||
|
}
|
||||||
|
|
||||||
result->set_feedback_vector_cell(*vector);
|
result->set_feedback_vector_cell(*vector);
|
||||||
if (info->ic_age() != isolate()->heap()->global_ic_age()) {
|
if (info->ic_age() != isolate()->heap()->global_ic_age()) {
|
||||||
info->ResetForNewContext(isolate()->heap()->global_ic_age());
|
info->ResetForNewContext(isolate()->heap()->global_ic_age());
|
||||||
|
@ -373,6 +373,10 @@ class V8_EXPORT_PRIVATE Factory final {
|
|||||||
|
|
||||||
Handle<WeakCell> NewWeakCell(Handle<HeapObject> value);
|
Handle<WeakCell> NewWeakCell(Handle<HeapObject> value);
|
||||||
|
|
||||||
|
Handle<Cell> NewNoClosuresCell(Handle<Object> value);
|
||||||
|
Handle<Cell> NewOneClosureCell(Handle<Object> value);
|
||||||
|
Handle<Cell> NewManyClosuresCell(Handle<Object> value);
|
||||||
|
|
||||||
Handle<TransitionArray> NewTransitionArray(int capacity);
|
Handle<TransitionArray> NewTransitionArray(int capacity);
|
||||||
|
|
||||||
// Allocate a tenured AllocationSite. It's payload is null.
|
// Allocate a tenured AllocationSite. It's payload is null.
|
||||||
|
@ -197,7 +197,7 @@ Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
|
|||||||
array->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
|
array->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
|
||||||
break;
|
break;
|
||||||
case FeedbackSlotKind::kCreateClosure: {
|
case FeedbackSlotKind::kCreateClosure: {
|
||||||
Handle<Cell> cell = factory->NewCell(undefined_value);
|
Handle<Cell> cell = factory->NewNoClosuresCell(undefined_value);
|
||||||
array->set(index, *cell);
|
array->set(index, *cell);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -494,8 +494,6 @@ DEFINE_BOOL(turbo_stress_instruction_scheduling, false,
|
|||||||
"randomly schedule instructions to stress dependency tracking")
|
"randomly schedule instructions to stress dependency tracking")
|
||||||
DEFINE_BOOL(turbo_store_elimination, true,
|
DEFINE_BOOL(turbo_store_elimination, true,
|
||||||
"enable store-store elimination in TurboFan")
|
"enable store-store elimination in TurboFan")
|
||||||
DEFINE_BOOL(turbo_lower_create_closure, false,
|
|
||||||
"enable inline allocation for closure instantiation")
|
|
||||||
// TODO(turbofan): Rename --crankshaft to --optimize eventually.
|
// TODO(turbofan): Rename --crankshaft to --optimize eventually.
|
||||||
DEFINE_IMPLICATION(turbo, crankshaft)
|
DEFINE_IMPLICATION(turbo, crankshaft)
|
||||||
|
|
||||||
|
@ -2330,6 +2330,9 @@ bool Heap::CreateInitialMaps() {
|
|||||||
ALLOCATE_MAP(CELL_TYPE, Cell::kSize, cell)
|
ALLOCATE_MAP(CELL_TYPE, Cell::kSize, cell)
|
||||||
ALLOCATE_MAP(PROPERTY_CELL_TYPE, PropertyCell::kSize, global_property_cell)
|
ALLOCATE_MAP(PROPERTY_CELL_TYPE, PropertyCell::kSize, global_property_cell)
|
||||||
ALLOCATE_MAP(WEAK_CELL_TYPE, WeakCell::kSize, weak_cell)
|
ALLOCATE_MAP(WEAK_CELL_TYPE, WeakCell::kSize, weak_cell)
|
||||||
|
ALLOCATE_MAP(CELL_TYPE, Cell::kSize, no_closures_cell)
|
||||||
|
ALLOCATE_MAP(CELL_TYPE, Cell::kSize, one_closure_cell)
|
||||||
|
ALLOCATE_MAP(CELL_TYPE, Cell::kSize, many_closures_cell)
|
||||||
ALLOCATE_MAP(FILLER_TYPE, kPointerSize, one_pointer_filler)
|
ALLOCATE_MAP(FILLER_TYPE, kPointerSize, one_pointer_filler)
|
||||||
ALLOCATE_MAP(FILLER_TYPE, 2 * kPointerSize, two_pointer_filler)
|
ALLOCATE_MAP(FILLER_TYPE, 2 * kPointerSize, two_pointer_filler)
|
||||||
|
|
||||||
|
@ -93,6 +93,9 @@ using v8::MemoryPressureLevel;
|
|||||||
V(Map, external_map, ExternalMap) \
|
V(Map, external_map, ExternalMap) \
|
||||||
V(Map, bytecode_array_map, BytecodeArrayMap) \
|
V(Map, bytecode_array_map, BytecodeArrayMap) \
|
||||||
V(Map, module_info_map, ModuleInfoMap) \
|
V(Map, module_info_map, ModuleInfoMap) \
|
||||||
|
V(Map, no_closures_cell_map, NoClosuresCellMap) \
|
||||||
|
V(Map, one_closure_cell_map, OneClosureCellMap) \
|
||||||
|
V(Map, many_closures_cell_map, ManyClosuresCellMap) \
|
||||||
/* String maps */ \
|
/* String maps */ \
|
||||||
V(Map, native_source_string_map, NativeSourceStringMap) \
|
V(Map, native_source_string_map, NativeSourceStringMap) \
|
||||||
V(Map, string_map, StringMap) \
|
V(Map, string_map, StringMap) \
|
||||||
@ -319,6 +322,9 @@ using v8::MemoryPressureLevel;
|
|||||||
V(ArgumentsMarkerMap) \
|
V(ArgumentsMarkerMap) \
|
||||||
V(JSMessageObjectMap) \
|
V(JSMessageObjectMap) \
|
||||||
V(ForeignMap) \
|
V(ForeignMap) \
|
||||||
|
V(NoClosuresCellMap) \
|
||||||
|
V(OneClosureCellMap) \
|
||||||
|
V(ManyClosuresCellMap) \
|
||||||
V(NanValue) \
|
V(NanValue) \
|
||||||
V(InfinityValue) \
|
V(InfinityValue) \
|
||||||
V(MinusZeroValue) \
|
V(MinusZeroValue) \
|
||||||
|
@ -12156,7 +12156,8 @@ void JSFunction::EnsureLiterals(Handle<JSFunction> function) {
|
|||||||
// A top level script didn't get it's literals installed.
|
// A top level script didn't get it's literals installed.
|
||||||
Handle<FeedbackVector> feedback_vector =
|
Handle<FeedbackVector> feedback_vector =
|
||||||
FeedbackVector::New(isolate, shared);
|
FeedbackVector::New(isolate, shared);
|
||||||
Handle<Cell> new_cell = isolate->factory()->NewCell(feedback_vector);
|
Handle<Cell> new_cell =
|
||||||
|
isolate->factory()->NewOneClosureCell(feedback_vector);
|
||||||
function->set_feedback_vector_cell(*new_cell);
|
function->set_feedback_vector_cell(*new_cell);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -385,10 +385,12 @@ TEST(OptimizedCodeSharing1) {
|
|||||||
" return function() { return x; };"
|
" return function() { return x; };"
|
||||||
"}"
|
"}"
|
||||||
"var closure0 = MakeClosure();"
|
"var closure0 = MakeClosure();"
|
||||||
|
"var closure1 = MakeClosure();" // We only share optimized code
|
||||||
|
// if there are at least two closures.
|
||||||
"%DebugPrint(closure0());"
|
"%DebugPrint(closure0());"
|
||||||
"%OptimizeFunctionOnNextCall(closure0);"
|
"%OptimizeFunctionOnNextCall(closure0);"
|
||||||
"%DebugPrint(closure0());"
|
"%DebugPrint(closure0());"
|
||||||
"var closure1 = MakeClosure(); closure1();"
|
"closure1();"
|
||||||
"var closure2 = MakeClosure(); closure2();");
|
"var closure2 = MakeClosure(); closure2();");
|
||||||
Handle<JSFunction> fun1 = Handle<JSFunction>::cast(
|
Handle<JSFunction> fun1 = Handle<JSFunction>::cast(
|
||||||
v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
|
v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
|
||||||
|
@ -25,10 +25,10 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// Flags: --noalways-opt
|
||||||
|
|
||||||
Debug = debug.Debug
|
Debug = debug.Debug
|
||||||
|
|
||||||
|
|
||||||
function TestCase(test_scenario, expected_output) {
|
function TestCase(test_scenario, expected_output) {
|
||||||
// Global variable, accessed from eval'd script.
|
// Global variable, accessed from eval'd script.
|
||||||
test_output = "";
|
test_output = "";
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// Flags: --noalways-opt
|
||||||
|
|
||||||
|
|
||||||
var Debug = debug.Debug;
|
var Debug = debug.Debug;
|
||||||
|
|
||||||
|
@ -141,36 +141,6 @@ TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedRestArray) {
|
|||||||
IsFinishRegion(IsAllocate(IsNumberConstant(JSArray::kSize), _, _), _));
|
IsFinishRegion(IsAllocate(IsNumberConstant(JSArray::kSize), _, _), _));
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// JSCreateClosure
|
|
||||||
|
|
||||||
TEST_F(JSCreateLoweringTest, JSCreateClosureViaInlinedAllocation) {
|
|
||||||
if (!FLAG_turbo_lower_create_closure) return;
|
|
||||||
Node* const context = UndefinedConstant();
|
|
||||||
Node* const effect = graph()->start();
|
|
||||||
Node* const control = graph()->start();
|
|
||||||
Handle<SharedFunctionInfo> shared(isolate()->number_function()->shared());
|
|
||||||
|
|
||||||
// Create a mock feedback vector. It just has to be an array with an array
|
|
||||||
// in slot 0.
|
|
||||||
Handle<FixedArray> array = isolate()->factory()->NewFixedArray(
|
|
||||||
FeedbackVector::kReservedIndexCount + 1);
|
|
||||||
array->set_map_no_write_barrier(isolate()->heap()->feedback_vector_map());
|
|
||||||
Handle<FeedbackVector> vector = Handle<FeedbackVector>::cast(array);
|
|
||||||
FeedbackSlot slot(0);
|
|
||||||
vector->Set(slot, *vector);
|
|
||||||
VectorSlotPair pair(vector, slot);
|
|
||||||
|
|
||||||
Reduction r = Reduce(
|
|
||||||
graph()->NewNode(javascript()->CreateClosure(shared, pair, NOT_TENURED),
|
|
||||||
context, effect, control));
|
|
||||||
ASSERT_TRUE(r.Changed());
|
|
||||||
EXPECT_THAT(r.replacement(),
|
|
||||||
IsFinishRegion(IsAllocate(IsNumberConstant(JSFunction::kSize),
|
|
||||||
IsBeginRegion(_), control),
|
|
||||||
_));
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// JSCreateFunctionContext
|
// JSCreateFunctionContext
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user