| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index 476317cae842c6aef80513a1592b1ef3441d7226..d9d1a68d0fb33db1086e4b2c8bab6a34c6c4ce53 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -6182,33 +6182,38 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
|
|
| // Check whether to use fast or slow deep-copying for boilerplate.
|
| int total_size = 0;
|
| - int max_properties = HFastLiteral::kMaxLiteralProperties;
|
| - Handle<Object> boilerplate(closure->literals()->get(expr->literal_index()),
|
| - isolate());
|
| - if (boilerplate->IsJSObject() &&
|
| - IsFastLiteral(Handle<JSObject>::cast(boilerplate),
|
| - HFastLiteral::kMaxLiteralDepth,
|
| + int max_properties = kMaxFastLiteralProperties;
|
| + Handle<Object> original_boilerplate(closure->literals()->get(
|
| + expr->literal_index()), isolate());
|
| + if (original_boilerplate->IsJSObject() &&
|
| + IsFastLiteral(Handle<JSObject>::cast(original_boilerplate),
|
| + kMaxFastLiteralDepth,
|
| &max_properties,
|
| &total_size)) {
|
| - Handle<JSObject> boilerplate_object = Handle<JSObject>::cast(boilerplate);
|
| - literal = new(zone()) HFastLiteral(context,
|
| - boilerplate_object,
|
| - total_size,
|
| - expr->literal_index(),
|
| - expr->depth(),
|
| - DONT_TRACK_ALLOCATION_SITE);
|
| + Handle<JSObject> original_boilerplate_object =
|
| + Handle<JSObject>::cast(original_boilerplate);
|
| + Handle<JSObject> boilerplate_object =
|
| + DeepCopy(original_boilerplate_object);
|
| +
|
| + literal = BuildFastLiteral(context,
|
| + boilerplate_object,
|
| + original_boilerplate_object,
|
| + total_size,
|
| + DONT_TRACK_ALLOCATION_SITE,
|
| + environment()->previous_ast_id());
|
| } else {
|
| - literal = new(zone()) HObjectLiteral(context,
|
| - expr->constant_properties(),
|
| - expr->fast_elements(),
|
| - expr->literal_index(),
|
| - expr->depth(),
|
| - expr->has_function());
|
| + literal = AddInstruction(
|
| + new(zone()) HObjectLiteral(context,
|
| + expr->constant_properties(),
|
| + expr->fast_elements(),
|
| + expr->literal_index(),
|
| + expr->depth(),
|
| + expr->has_function()));
|
| }
|
|
|
| // The object is expected in the bailout environment during computation
|
| // of the property values and is the value of the entire expression.
|
| - PushAndAdd(literal);
|
| + Push(literal);
|
|
|
| expr->CalculateEmitStore(zone());
|
|
|
| @@ -6305,9 +6310,10 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
| }
|
| }
|
|
|
| - Handle<JSObject> boilerplate = Handle<JSObject>::cast(raw_boilerplate);
|
| + Handle<JSObject> original_boilerplate_object =
|
| + Handle<JSObject>::cast(raw_boilerplate);
|
| ElementsKind boilerplate_elements_kind =
|
| - Handle<JSObject>::cast(boilerplate)->GetElementsKind();
|
| + Handle<JSObject>::cast(original_boilerplate_object)->GetElementsKind();
|
|
|
| // TODO(mvstanton): This heuristic is only a temporary solution. In the
|
| // end, we want to quit creating allocation site info after a certain number
|
| @@ -6317,32 +6323,35 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
|
|
|
| // Check whether to use fast or slow deep-copying for boilerplate.
|
| int total_size = 0;
|
| - int max_properties = HFastLiteral::kMaxLiteralProperties;
|
| - if (IsFastLiteral(boilerplate,
|
| - HFastLiteral::kMaxLiteralDepth,
|
| + int max_properties = kMaxFastLiteralProperties;
|
| + if (IsFastLiteral(original_boilerplate_object,
|
| + kMaxFastLiteralDepth,
|
| &max_properties,
|
| &total_size)) {
|
| if (mode == TRACK_ALLOCATION_SITE) {
|
| total_size += AllocationSiteInfo::kSize;
|
| }
|
| - literal = new(zone()) HFastLiteral(context,
|
| - boilerplate,
|
| - total_size,
|
| - expr->literal_index(),
|
| - expr->depth(),
|
| - mode);
|
| +
|
| + Handle<JSObject> boilerplate_object = DeepCopy(original_boilerplate_object);
|
| + literal = BuildFastLiteral(context,
|
| + boilerplate_object,
|
| + original_boilerplate_object,
|
| + total_size,
|
| + mode,
|
| + environment()->previous_ast_id());
|
| } else {
|
| - literal = new(zone()) HArrayLiteral(context,
|
| - boilerplate,
|
| - length,
|
| - expr->literal_index(),
|
| - expr->depth(),
|
| - mode);
|
| + literal = AddInstruction(
|
| + new(zone()) HArrayLiteral(context,
|
| + original_boilerplate_object,
|
| + length,
|
| + expr->literal_index(),
|
| + expr->depth(),
|
| + mode));
|
| }
|
|
|
| // The array is expected in the bailout environment during computation
|
| // of the property values and is the value of the entire expression.
|
| - PushAndAdd(literal);
|
| + Push(literal);
|
|
|
| HLoadElements* elements = NULL;
|
|
|
| @@ -10081,6 +10090,240 @@ HInstruction* HOptimizedGraphBuilder::BuildThisFunction() {
|
| }
|
|
|
|
|
| +HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
|
| + HValue* context,
|
| + Handle<JSObject> boilerplate_object,
|
| + Handle<JSObject> original_boilerplate_object,
|
| + int size,
|
| + AllocationSiteMode mode,
|
| + BailoutId id) {
|
| + Zone* zone = this->zone();
|
| +
|
| + HValue* size_in_bytes =
|
| + AddInstruction(new(zone) HConstant(size, Representation::Integer32()));
|
| + HInstruction* result =
|
| + AddInstruction(new(zone) HAllocate(context,
|
| + size_in_bytes,
|
| + HType::JSObject(),
|
| + HAllocate::CAN_ALLOCATE_IN_NEW_SPACE));
|
| + int offset = 0;
|
| + BuildEmitDeepCopy(boilerplate_object, original_boilerplate_object, result,
|
| + &offset, mode, id);
|
| + ASSERT_EQ(size, offset);
|
| + return result;
|
| +}
|
| +
|
| +
|
| +void HOptimizedGraphBuilder::BuildEmitDeepCopy(
|
| + Handle<JSObject> boilerplate_object,
|
| + Handle<JSObject> original_boilerplate_object,
|
| + HInstruction* target,
|
| + int* offset,
|
| + AllocationSiteMode mode,
|
| + BailoutId id) {
|
| + Zone* zone = this->zone();
|
| + Factory* factory = isolate()->factory();
|
| +
|
| + HInstruction* original_boilerplate = AddInstruction(new(zone) HConstant(
|
| + original_boilerplate_object, Representation::Tagged()));
|
| +
|
| + bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
|
| + boilerplate_object->map()->CanTrackAllocationSite();
|
| +
|
| + // Only elements backing stores for non-COW arrays need to be copied.
|
| + Handle<FixedArrayBase> elements(boilerplate_object->elements());
|
| + Handle<FixedArrayBase> original_elements(
|
| + original_boilerplate_object->elements());
|
| + ElementsKind kind = boilerplate_object->map()->elements_kind();
|
| +
|
| + // Increase the offset so that subsequent objects end up right after
|
| + // this object and its backing store.
|
| + int object_offset = *offset;
|
| + int object_size = boilerplate_object->map()->instance_size();
|
| + int elements_size = (elements->length() > 0 &&
|
| + elements->map() != isolate()->heap()->fixed_cow_array_map()) ?
|
| + elements->Size() : 0;
|
| + int elements_offset = *offset + object_size;
|
| + int inobject_properties = boilerplate_object->map()->inobject_properties();
|
| + if (create_allocation_site_info) {
|
| + elements_offset += AllocationSiteInfo::kSize;
|
| + *offset += AllocationSiteInfo::kSize;
|
| + }
|
| +
|
| + *offset += object_size + elements_size;
|
| +
|
| + HValue* object_elements = BuildCopyObjectHeader(boilerplate_object, target,
|
| + object_offset, elements_offset, elements_size, id);
|
| +
|
| + // Copy in-object properties.
|
| + HValue* object_properties =
|
| + AddInstruction(new(zone) HInnerAllocatedObject(target, object_offset));
|
| + for (int i = 0; i < inobject_properties; i++) {
|
| + Handle<Object> value =
|
| + Handle<Object>(boilerplate_object->InObjectPropertyAt(i),
|
| + isolate());
|
| + if (value->IsJSObject()) {
|
| + Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
| + Handle<JSObject> original_value_object = Handle<JSObject>::cast(
|
| + Handle<Object>(original_boilerplate_object->InObjectPropertyAt(i),
|
| + isolate()));
|
| + HInstruction* value_instruction =
|
| + AddInstruction(new(zone) HInnerAllocatedObject(target, *offset));
|
| + AddInstruction(new(zone) HStoreNamedField(
|
| + object_properties, factory->unknown_field_string(), value_instruction,
|
| + true, boilerplate_object->GetInObjectPropertyOffset(i)));
|
| + AddSimulate(id);
|
| + BuildEmitDeepCopy(value_object, original_value_object, target,
|
| + offset, DONT_TRACK_ALLOCATION_SITE, id);
|
| + } else {
|
| + HInstruction* value_instruction = AddInstruction(new(zone) HConstant(
|
| + value, Representation::Tagged()));
|
| + AddInstruction(new(zone) HStoreNamedField(
|
| + object_properties, factory->unknown_field_string(), value_instruction,
|
| + true, boilerplate_object->GetInObjectPropertyOffset(i)));
|
| + AddSimulate(id);
|
| + }
|
| + }
|
| +
|
| + // Build Allocation Site Info if desired
|
| + if (create_allocation_site_info) {
|
| + HValue* alloc_site =
|
| + AddInstruction(new(zone) HInnerAllocatedObject(target, JSArray::kSize));
|
| + Handle<Map> alloc_site_map(isolate()->heap()->allocation_site_info_map());
|
| + BuildStoreMap(alloc_site, alloc_site_map, id);
|
| + int alloc_payload_offset = AllocationSiteInfo::kPayloadOffset;
|
| + AddInstruction(new(zone) HStoreNamedField(alloc_site,
|
| + factory->payload_string(),
|
| + original_boilerplate,
|
| + true, alloc_payload_offset));
|
| + AddSimulate(id);
|
| + }
|
| +
|
| + if (object_elements != NULL) {
|
| + HInstruction* boilerplate_elements = AddInstruction(new(zone) HConstant(
|
| + elements, Representation::Tagged()));
|
| +
|
| + int elements_length = elements->length();
|
| + HValue* object_elements_length =
|
| + AddInstruction(new(zone) HConstant(
|
| + elements_length, Representation::Integer32()));
|
| +
|
| + BuildInitializeElements(object_elements, kind, object_elements_length);
|
| +
|
| + // Copy elements backing store content.
|
| + if (elements->IsFixedDoubleArray()) {
|
| + for (int i = 0; i < elements_length; i++) {
|
| + HValue* key_constant =
|
| + AddInstruction(new(zone) HConstant(i, Representation::Integer32()));
|
| + HInstruction* value_instruction =
|
| + AddInstruction(new(zone) HLoadKeyed(
|
| + boilerplate_elements, key_constant, NULL, kind));
|
| + AddInstruction(new(zone) HStoreKeyed(
|
| + object_elements, key_constant, value_instruction, kind));
|
| + AddSimulate(id);
|
| + }
|
| + } else if (elements->IsFixedArray()) {
|
| + Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
|
| + Handle<FixedArray> original_fast_elements =
|
| + Handle<FixedArray>::cast(original_elements);
|
| + for (int i = 0; i < elements_length; i++) {
|
| + Handle<Object> value(fast_elements->get(i), isolate());
|
| + HValue* key_constant =
|
| + AddInstruction(new(zone) HConstant(i, Representation::Integer32()));
|
| + if (value->IsJSObject()) {
|
| + Handle<JSObject> value_object = Handle<JSObject>::cast(value);
|
| + Handle<JSObject> original_value_object = Handle<JSObject>::cast(
|
| + Handle<Object>(original_fast_elements->get(i), isolate()));
|
| + HInstruction* value_instruction =
|
| + AddInstruction(new(zone) HInnerAllocatedObject(target, *offset));
|
| + AddInstruction(new(zone) HStoreKeyed(
|
| + object_elements, key_constant, value_instruction, kind));
|
| + AddSimulate(id);
|
| + BuildEmitDeepCopy(value_object, original_value_object, target,
|
| + offset, DONT_TRACK_ALLOCATION_SITE, id);
|
| + } else {
|
| + HInstruction* value_instruction =
|
| + AddInstruction(new(zone) HLoadKeyed(
|
| + boilerplate_elements, key_constant, NULL, kind));
|
| + AddInstruction(new(zone) HStoreKeyed(
|
| + object_elements, key_constant, value_instruction, kind));
|
| + AddSimulate(id);
|
| + }
|
| + }
|
| + } else {
|
| + UNREACHABLE();
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +HValue* HOptimizedGraphBuilder::BuildCopyObjectHeader(
|
| + Handle<JSObject> boilerplate_object,
|
| + HInstruction* target,
|
| + int object_offset,
|
| + int elements_offset,
|
| + int elements_size,
|
| + BailoutId id) {
|
| + ASSERT(boilerplate_object->properties()->length() == 0);
|
| + Zone* zone = this->zone();
|
| + Factory* factory = isolate()->factory();
|
| + HValue* result = NULL;
|
| +
|
| + HValue* object_header =
|
| + AddInstruction(new(zone) HInnerAllocatedObject(target, object_offset));
|
| + Handle<Map> boilerplate_object_map(boilerplate_object->map());
|
| + BuildStoreMap(object_header, boilerplate_object_map, id);
|
| +
|
| + HInstruction* elements;
|
| + if (elements_size == 0) {
|
| + Handle<Object> elements_field =
|
| + Handle<Object>(boilerplate_object->elements(), isolate());
|
| + elements = AddInstruction(new(zone) HConstant(
|
| + elements_field, Representation::Tagged()));
|
| + } else {
|
| + elements = AddInstruction(new(zone) HInnerAllocatedObject(
|
| + target, elements_offset));
|
| + result = elements;
|
| + }
|
| + HInstruction* elements_store = AddInstruction(new(zone) HStoreNamedField(
|
| + object_header,
|
| + factory->elements_field_string(),
|
| + elements,
|
| + true, JSObject::kElementsOffset));
|
| + elements_store->SetGVNFlag(kChangesElementsPointer);
|
| + AddSimulate(id);
|
| +
|
| + Handle<Object> properties_field =
|
| + Handle<Object>(boilerplate_object->properties(), isolate());
|
| + ASSERT(*properties_field == isolate()->heap()->empty_fixed_array());
|
| + HInstruction* properties = AddInstruction(new(zone) HConstant(
|
| + properties_field, Representation::None()));
|
| + AddInstruction(new(zone) HStoreNamedField(object_header,
|
| + factory->empty_string(),
|
| + properties,
|
| + true, JSObject::kPropertiesOffset));
|
| + AddSimulate(id);
|
| +
|
| + if (boilerplate_object->IsJSArray()) {
|
| + Handle<JSArray> boilerplate_array =
|
| + Handle<JSArray>::cast(boilerplate_object);
|
| + Handle<Object> length_field =
|
| + Handle<Object>(boilerplate_array->length(), isolate());
|
| + HInstruction* length = AddInstruction(new(zone) HConstant(
|
| + length_field, Representation::None()));
|
| + HInstruction* length_store = AddInstruction(new(zone) HStoreNamedField(
|
| + object_header,
|
| + factory->length_field_string(),
|
| + length,
|
| + true, JSArray::kLengthOffset));
|
| + length_store->SetGVNFlag(kChangesArrayLengths);
|
| + AddSimulate(id);
|
| + }
|
| +
|
| + return result;
|
| +}
|
| +
|
| +
|
| void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) {
|
| ASSERT(!HasStackOverflow());
|
| ASSERT(current_block() != NULL);
|
|
|