Index: src/compiler/js-builtin-reducer.cc |
diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc |
index 6698408f94b5778e49a0decd4688215e788e8c07..d782340baf81bdb1fa9dc9afbd1d52bb537f52b6 100644 |
--- a/src/compiler/js-builtin-reducer.cc |
+++ b/src/compiler/js-builtin-reducer.cc |
@@ -4,6 +4,7 @@ |
#include "src/compiler/js-builtin-reducer.h" |
+#include "src/base/bits.h" |
#include "src/compilation-dependencies.h" |
#include "src/compiler/access-builder.h" |
#include "src/compiler/js-graph.h" |
@@ -1485,6 +1486,117 @@ Reduction JSBuiltinReducer::ReduceNumberParseInt(Node* node) { |
return NoChange(); |
} |
+// ES6 section #sec-object.create Object.create(proto, properties) |
+Reduction JSBuiltinReducer::ReduceObjectCreate(Node* node) { |
+ // We need exactly target, receiver and value parameters. |
+ int arg_count = node->op()->ValueInputCount(); |
+ if (arg_count != 3) return NoChange(); |
+ Node* effect = NodeProperties::GetEffectInput(node); |
+ Node* control = NodeProperties::GetControlInput(node); |
+ Node* prototype = NodeProperties::GetValueInput(node, 2); |
+ Type* prototype_type = NodeProperties::GetType(prototype); |
+ Handle<Map> instance_map; |
+ if (!prototype_type->IsHeapConstant()) return NoChange(); |
+ Handle<HeapObject> prototype_const = |
+ prototype_type->AsHeapConstant()->Value(); |
+ if (!prototype_const->IsNull(isolate()) && !prototype_const->IsJSReceiver()) { |
+ return NoChange(); |
+ } |
+ instance_map = Map::GetObjectCreateMap(prototype_const); |
+ Node* properties = jsgraph()->EmptyFixedArrayConstant(); |
+ if (instance_map->is_dictionary_map()) { |
+ // Allocated an empty NameDictionary as backing store for the properties. |
+ Handle<Map> map(isolate()->heap()->hash_table_map(), isolate()); |
+ int capacity = |
+ NameDictionary::ComputeCapacity(NameDictionary::kInitialCapacity); |
+ DCHECK(base::bits::IsPowerOfTwo32(capacity)); |
+ int length = NameDictionary::EntryToIndex(capacity); |
+ int size = NameDictionary::SizeFor(length); |
+ |
+ effect = graph()->NewNode( |
+ common()->BeginRegion(RegionObservability::kNotObservable), effect); |
+ |
+ Node* value = effect = |
+ graph()->NewNode(simplified()->Allocate(NOT_TENURED), |
+ jsgraph()->Constant(size), effect, control); |
+ effect = |
+ graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), |
+ value, jsgraph()->HeapConstant(map), effect, control); |
+ |
+ // Initialize FixedArray fields. |
+ effect = graph()->NewNode( |
+ simplified()->StoreField(AccessBuilder::ForFixedArrayLength()), value, |
+ jsgraph()->SmiConstant(length), effect, control); |
+ // Initialize HashTable fields. |
+ effect = |
+ graph()->NewNode(simplified()->StoreField( |
+ AccessBuilder::ForHashTableBaseNumberOfElements()), |
+ value, jsgraph()->SmiConstant(0), effect, control); |
+ effect = graph()->NewNode( |
+ simplified()->StoreField( |
+ AccessBuilder::ForHashTableBaseNumberOfDeletedElement()), |
+ value, jsgraph()->SmiConstant(0), effect, control); |
+ effect = graph()->NewNode( |
+ simplified()->StoreField(AccessBuilder::ForHashTableBaseCapacity()), |
+ value, jsgraph()->SmiConstant(capacity), effect, control); |
+ // Initialize Dictionary fields. |
+ Node* undefined = jsgraph()->UndefinedConstant(); |
+ effect = graph()->NewNode( |
+ simplified()->StoreField(AccessBuilder::ForDictionaryMaxNumberKey()), |
+ value, undefined, effect, control); |
+ effect = graph()->NewNode( |
+ simplified()->StoreField( |
+ AccessBuilder::ForDictionaryNextEnumerationIndex()), |
+ value, jsgraph()->SmiConstant(PropertyDetails::kInitialIndex), effect, |
+ control); |
+ // Initialize hte Properties fields. |
+ for (int index = NameDictionary::kNextEnumerationIndexIndex + 1; |
+ index < length; index++) { |
+ effect = graph()->NewNode( |
+ simplified()->StoreField( |
+ AccessBuilder::ForFixedArraySlot(index, kNoWriteBarrier)), |
+ value, undefined, effect, control); |
+ } |
+ properties = effect = |
+ graph()->NewNode(common()->FinishRegion(), value, effect); |
+ } |
+ |
+ int const instance_size = instance_map->instance_size(); |
+ if (instance_size > kMaxRegularHeapObjectSize) return NoChange(); |
+ dependencies()->AssumeInitialMapCantChange(instance_map); |
+ |
+ // Emit code to allocate the JSObject instance for the given |
+ // {instance_map}. |
+ effect = graph()->NewNode( |
+ common()->BeginRegion(RegionObservability::kNotObservable), effect); |
+ Node* value = effect = |
+ graph()->NewNode(simplified()->Allocate(NOT_TENURED), |
+ jsgraph()->Constant(instance_size), effect, control); |
+ effect = |
+ graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), value, |
+ jsgraph()->HeapConstant(instance_map), effect, control); |
+ effect = graph()->NewNode( |
+ simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value, |
+ properties, effect, control); |
+ effect = graph()->NewNode( |
+ simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value, |
+ jsgraph()->EmptyFixedArrayConstant(), effect, control); |
+ // Initialize Object fields. |
+ Node* undefined = jsgraph()->UndefinedConstant(); |
+ for (int offset = JSObject::kHeaderSize; offset < instance_size; |
+ offset += kPointerSize) { |
+ effect = graph()->NewNode( |
+ simplified()->StoreField( |
+ AccessBuilder::ForJSObjectOffset(offset, kNoWriteBarrier)), |
+ value, undefined, effect, control); |
+ } |
+ value = effect = graph()->NewNode(common()->FinishRegion(), value, effect); |
+ |
+ // replace it |
+ ReplaceWithValue(node, value, effect, control); |
+ return Replace(value); |
+} |
+ |
// ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits ) |
Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) { |
JSCallReduction r(node); |
@@ -1990,6 +2102,9 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { |
case kNumberParseInt: |
reduction = ReduceNumberParseInt(node); |
break; |
+ case kObjectCreate: |
+ reduction = ReduceObjectCreate(node); |
+ break; |
case kStringFromCharCode: |
reduction = ReduceStringFromCharCode(node); |
break; |