| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index 36d62d271ce7d1b8451324cc923827a2586b6f26..85a58b391000f1805a6e9ff2f66cf9e07c4a9d3c 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -1753,7 +1753,10 @@ HAllocate* HGraphBuilder::BuildAllocate(
|
| // Compute the effective allocation size.
|
| HValue* size = object_size;
|
| if (allocation_mode.CreateAllocationMementos()) {
|
| - size = AddUncasted<HAdd>(size, Add<HConstant>(AllocationMemento::kSize));
|
| + NoObservableSideEffectsScope no_effects(this);
|
| + size = AddInstruction(
|
| + HAdd::New(zone(), context(), object_size,
|
| + Add<HConstant>(AllocationMemento::kSize)));
|
| size->ClearFlag(HValue::kCanOverflow);
|
| }
|
|
|
| @@ -2798,6 +2801,7 @@ void HGraphBuilder::BuildCreateAllocationMemento(
|
| HValue* previous_object,
|
| HValue* previous_object_size,
|
| HValue* allocation_site) {
|
| + NoObservableSideEffectsScope no_effects(this);
|
| ASSERT(allocation_site != NULL);
|
| HInnerAllocatedObject* allocation_memento = Add<HInnerAllocatedObject>(
|
| previous_object, previous_object_size, HType::HeapObject());
|
| @@ -5164,7 +5168,9 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
|
|
| if (!boilerplate.is_null() &&
|
| IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) {
|
| - AllocationSiteUsageContext usage_context(isolate(), site, false);
|
| + bool emit_mementos = FLAG_allocation_site_pretenuring &&
|
| + site->emit_mementos();
|
| + AllocationSiteUsageContext usage_context(isolate(), site, emit_mementos);
|
| usage_context.EnterNewScope();
|
| literal = BuildFastLiteral(boilerplate, &usage_context);
|
| usage_context.ExitScope(site, boilerplate);
|
| @@ -5321,7 +5327,9 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
| if (IsFastLiteral(boilerplate_object,
|
| kMaxFastLiteralDepth,
|
| &max_properties)) {
|
| - AllocationSiteUsageContext usage_context(isolate(), site, false);
|
| + bool emit_mementos = FLAG_allocation_site_pretenuring &&
|
| + site->emit_mementos();
|
| + AllocationSiteUsageContext usage_context(isolate(), site, emit_mementos);
|
| usage_context.EnterNewScope();
|
| literal = BuildFastLiteral(boilerplate_object, &usage_context);
|
| usage_context.ExitScope(site, boilerplate_object);
|
| @@ -8327,16 +8335,17 @@ HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function,
|
| void HOptimizedGraphBuilder::BuildArrayCall(Expression* expression,
|
| int arguments_count,
|
| HValue* function,
|
| - Handle<AllocationSite> site) {
|
| + Handle<AllocationSite> site,
|
| + HAllocationMode mode) {
|
| Add<HCheckValue>(function, array_function());
|
|
|
| if (IsCallArrayInlineable(arguments_count, site)) {
|
| - BuildInlinedCallArray(expression, arguments_count, site);
|
| + BuildInlinedCallArray(expression, arguments_count, mode, site);
|
| return;
|
| }
|
|
|
| HInstruction* call = PreProcessCall(New<HCallNewArray>(
|
| - function, arguments_count + 1, site->GetElementsKind()));
|
| + function, arguments_count + 1, site->GetElementsKind(), mode));
|
| if (expression->IsCall()) {
|
| Drop(1);
|
| }
|
| @@ -8497,13 +8506,15 @@ bool HOptimizedGraphBuilder::TryHandleArrayCall(Call* expr, HValue* function) {
|
| BuildArrayCall(expr,
|
| expr->arguments()->length(),
|
| function,
|
| - site);
|
| + site,
|
| + HAllocationMode());
|
| return true;
|
| }
|
|
|
|
|
| bool HOptimizedGraphBuilder::TryHandleArrayCallNew(CallNew* expr,
|
| - HValue* function) {
|
| + HValue* function,
|
| + HAllocationMode mode) {
|
| if (!array_function().is_identical_to(expr->target())) {
|
| return false;
|
| }
|
| @@ -8511,7 +8522,8 @@ bool HOptimizedGraphBuilder::TryHandleArrayCallNew(CallNew* expr,
|
| BuildArrayCall(expr,
|
| expr->arguments()->length(),
|
| function,
|
| - expr->allocation_site());
|
| + expr->allocation_site(),
|
| + mode);
|
| return true;
|
| }
|
|
|
| @@ -8697,6 +8709,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
|
| void HOptimizedGraphBuilder::BuildInlinedCallArray(
|
| Expression* expression,
|
| int argument_count,
|
| + HAllocationMode mode,
|
| Handle<AllocationSite> site) {
|
| ASSERT(!site.is_null());
|
| ASSERT(argument_count >= 0 && argument_count <= 1);
|
| @@ -8725,12 +8738,17 @@ void HOptimizedGraphBuilder::BuildInlinedCallArray(
|
| }
|
| }
|
|
|
| - // Build the array.
|
| + // Build the array. Should we emit mementos?
|
| + AllocationSiteOverrideMode site_mode = mode.CreateAllocationMementos()
|
| + ? DONT_OVERRIDE
|
| + : DISABLE_ALLOCATION_SITES;
|
| +
|
| JSArrayBuilder array_builder(this,
|
| kind,
|
| site_instruction,
|
| constructor,
|
| - DISABLE_ALLOCATION_SITES);
|
| + site_mode);
|
| +
|
| HValue* new_object = argument_count == 0
|
| ? array_builder.AllocateEmptyArray()
|
| : BuildAllocateArrayFromLength(&array_builder, Top());
|
| @@ -8796,6 +8814,30 @@ bool HOptimizedGraphBuilder::IsCallArrayInlineable(
|
| }
|
|
|
|
|
| +void HOptimizedGraphBuilder::InitializeAllocationModeForCallNew(
|
| + CallNew* expr,
|
| + HAllocationMode* mode) {
|
| + if (FLAG_pretenuring_call_new) {
|
| + if (FLAG_allocation_site_pretenuring) {
|
| + Handle<AllocationSite> allocation_site = expr->allocation_site();
|
| + HConstant* site_constant = NULL;
|
| + // By passing a non-null HConstant AllocationSite to HAllocationMode,
|
| + // we ensure that a memento will be emitted.
|
| + if (allocation_site->emit_mementos()) {
|
| + site_constant = Add<HConstant>(allocation_site);
|
| + }
|
| + // Try to use pretenuring feedback.
|
| + *mode = HAllocationMode(allocation_site, site_constant);
|
| + // Take a dependency on allocation site.
|
| + AllocationSite::AddDependentCompilationInfo(allocation_site,
|
| + AllocationSite::TENURING,
|
| + top_info());
|
| + }
|
| + }
|
| + // No else case, the mode will be left at it's default.
|
| +}
|
| +
|
| +
|
| void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
|
| ASSERT(!HasStackOverflow());
|
| ASSERT(current_block() != NULL);
|
| @@ -8831,17 +8873,7 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
|
| // Allocate an instance of the implicit receiver object.
|
| HValue* size_in_bytes = Add<HConstant>(instance_size);
|
| HAllocationMode allocation_mode;
|
| - if (FLAG_pretenuring_call_new) {
|
| - if (FLAG_allocation_site_pretenuring) {
|
| - // Try to use pretenuring feedback.
|
| - Handle<AllocationSite> allocation_site = expr->allocation_site();
|
| - allocation_mode = HAllocationMode(allocation_site);
|
| - // Take a dependency on allocation site.
|
| - AllocationSite::AddDependentCompilationInfo(allocation_site,
|
| - AllocationSite::TENURING,
|
| - top_info());
|
| - }
|
| - }
|
| + InitializeAllocationModeForCallNew(expr, &allocation_mode);
|
|
|
| HAllocate* receiver = BuildAllocate(
|
| size_in_bytes, HType::JSObject(), JS_OBJECT_TYPE, allocation_mode);
|
| @@ -8893,22 +8925,40 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
|
| // arguments in case inlining failed. What we actually should do is for
|
| // inlining to try to build a subgraph without mutating the parent graph.
|
| HInstruction* instr = current_block()->last();
|
| - do {
|
| +
|
| + // If we decided to emit a memento for this allocation, we need to
|
| + // remember the instruction of the HConstant for the site added
|
| + // in InitializeAllocationModeForCallNew().
|
| + HValue* delete_to_this_instruction =
|
| + allocation_mode.CreateAllocationMementos()
|
| + ? allocation_mode.current_site()
|
| + : receiver;
|
| + ASSERT(delete_to_this_instruction != NULL);
|
| + while (instr != delete_to_this_instruction) {
|
| HInstruction* prev_instr = instr->previous();
|
| instr->DeleteAndReplaceWith(NULL);
|
| instr = prev_instr;
|
| - } while (instr != check);
|
| + }
|
| + // initial_map_value->DeleteAndReplaceWith(NULL);
|
| + if (delete_to_this_instruction == receiver) {
|
| + receiver->DeleteAndReplaceWith(NULL);
|
| + }
|
| + check->DeleteAndReplaceWith(NULL);
|
| environment()->SetExpressionStackAt(receiver_index, function);
|
| - HInstruction* call =
|
| - PreProcessCall(New<HCallNew>(function, argument_count));
|
| + HInstruction* call = PreProcessCall(
|
| + New<HCallNew>(function, argument_count, allocation_mode));
|
| return ast_context()->ReturnInstruction(call, expr->id());
|
| } else {
|
| + HAllocationMode allocation_mode;
|
| + InitializeAllocationModeForCallNew(expr, &allocation_mode);
|
| +
|
| // The constructor function is both an operand to the instruction and an
|
| // argument to the construct call.
|
| - if (TryHandleArrayCallNew(expr, function)) return;
|
| + if (TryHandleArrayCallNew(expr, function, allocation_mode)) return;
|
|
|
| HInstruction* call =
|
| - PreProcessCall(New<HCallNew>(function, argument_count));
|
| + PreProcessCall(New<HCallNew>(function, argument_count,
|
| + allocation_mode));
|
| return ast_context()->ReturnInstruction(call, expr->id());
|
| }
|
| }
|
| @@ -9774,6 +9824,16 @@ HValue* HOptimizedGraphBuilder::BuildBinaryOperation(
|
| allocation_mode = HAllocationMode(allocation_site);
|
| }
|
|
|
| + if (FLAG_allocation_site_pretenuring &&
|
| + !allocation_site.is_null() &&
|
| + allocation_site->emit_mementos()) {
|
| + // This allows crankshaft to continue emitting mementos if a pretenuring
|
| + // decision wasn't made yet. A dependency is registered on the site in
|
| + // the BuildBinaryOperation call below.
|
| + HConstant* site_constant = Add<HConstant>(allocation_site);
|
| + allocation_mode = HAllocationMode(allocation_site, site_constant);
|
| + }
|
| +
|
| HValue* result = HGraphBuilder::BuildBinaryOperation(
|
| expr->op(), left, right, left_type, right_type, result_type,
|
| fixed_right_arg, allocation_mode);
|
| @@ -10476,8 +10536,14 @@ HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
|
|
|
| HType type = instance_type == JS_ARRAY_TYPE
|
| ? HType::JSArray() : HType::JSObject();
|
| - HValue* object_size_constant = Add<HConstant>(
|
| - boilerplate_object->map()->instance_size());
|
| + int instance_size = boilerplate_object->map()->instance_size();
|
| + bool emit_memento = site_context->ShouldCreateMemento(boilerplate_object);
|
| + // Should the object allocation include a manually folded memento?
|
| + int alloc_size = emit_memento
|
| + ? instance_size + AllocationMemento::kSize
|
| + : instance_size;
|
| + HValue* alloc_size_constant = Add<HConstant>(alloc_size);
|
| + HValue* allocation_site_constant = Add<HConstant>(site_context->current());
|
|
|
| PretenureFlag pretenure_flag = NOT_TENURED;
|
| if (FLAG_allocation_site_pretenuring) {
|
| @@ -10487,7 +10553,7 @@ HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
|
| site, AllocationSite::TENURING, top_info());
|
| }
|
|
|
| - HInstruction* object = Add<HAllocate>(object_size_constant, type,
|
| + HInstruction* object = Add<HAllocate>(alloc_size_constant, type,
|
| pretenure_flag, instance_type, site_context->current());
|
|
|
| // If allocation folding reaches Page::kMaxRegularHeapObjectSize the
|
| @@ -10500,6 +10566,11 @@ HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
|
| empty_fixed_array);
|
|
|
| BuildEmitObjectHeader(boilerplate_object, object);
|
| + if (emit_memento) {
|
| + BuildCreateAllocationMemento(object,
|
| + Add<HConstant>(instance_size),
|
| + allocation_site_constant);
|
| + }
|
|
|
| Handle<FixedArrayBase> elements(boilerplate_object->elements());
|
| int elements_size = (elements->length() > 0 &&
|
|
|