Index: src/builtins/builtins-object.cc |
diff --git a/src/builtins/builtins-object.cc b/src/builtins/builtins-object.cc |
index b0bb1f043d6686ccccff6e397ddbcdd0327b92fd..6cc2d705b4f556585f60c1793fdfb8207a6d6d13 100644 |
--- a/src/builtins/builtins-object.cc |
+++ b/src/builtins/builtins-object.cc |
@@ -459,57 +459,96 @@ void Builtins::Generate_ObjectProtoToString(CodeStubAssembler* assembler) { |
} |
} |
-// ES6 section 19.1.2.2 Object.create ( O [ , Properties ] ) |
-// TODO(verwaest): Support the common cases with precached map directly in |
-// an Object.create stub. |
-BUILTIN(ObjectCreate) { |
- HandleScope scope(isolate); |
- Handle<Object> prototype = args.atOrUndefined(isolate, 1); |
- if (!prototype->IsNull(isolate) && !prototype->IsJSReceiver()) { |
- THROW_NEW_ERROR_RETURN_FAILURE( |
- isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, prototype)); |
+void Builtins::Generate_ObjectCreate(CodeStubAssembler* a) { |
+ typedef compiler::Node Node; |
+ typedef CodeStubAssembler::Label Label; |
+ typedef CodeStubAssembler::Variable Variable; |
+ |
+ Node* prototype = a->Parameter(1); |
+ Node* properties = a->Parameter(2); |
+ Node* context = a->Parameter(3 + 2); |
+ |
+ Label call_runtime(a, Label::kDeferred), prototype_valid(a), no_properties(a); |
+ { |
+ a->Comment("Argument 1 check: prototype"); |
+ a->GotoIf(a->WordEqual(prototype, a->NullConstant()), &prototype_valid); |
+ a->BranchIfJSReceiver(prototype, &prototype_valid, &call_runtime); |
} |
- // Generate the map with the specified {prototype} based on the Object |
- // function's initial map from the current native context. |
- // TODO(bmeurer): Use a dedicated cache for Object.create; think about |
- // slack tracking for Object.create. |
- Handle<Map> map(isolate->native_context()->object_function()->initial_map(), |
- isolate); |
- if (map->prototype() != *prototype) { |
- if (prototype->IsNull(isolate)) { |
- map = isolate->object_with_null_prototype_map(); |
- } else if (prototype->IsJSObject()) { |
- Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype); |
- if (!js_prototype->map()->is_prototype_map()) { |
- JSObject::OptimizeAsPrototype(js_prototype, FAST_PROTOTYPE); |
- } |
- Handle<PrototypeInfo> info = |
- Map::GetOrCreatePrototypeInfo(js_prototype, isolate); |
- // TODO(verwaest): Use inobject slack tracking for this map. |
- if (info->HasObjectCreateMap()) { |
- map = handle(info->ObjectCreateMap(), isolate); |
- } else { |
- map = Map::CopyInitialMap(map); |
- Map::SetPrototype(map, prototype, FAST_PROTOTYPE); |
- PrototypeInfo::SetObjectCreateMap(info, map); |
- } |
- } else { |
- map = Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE); |
- } |
+ a->Bind(&prototype_valid); |
+ { |
+ a->Comment("Argument 2 check: properties"); |
+ // Check that we have a simple object |
+ a->GotoIf(a->TaggedIsSmi(properties), &call_runtime); |
+ // Undefined implies no properties. |
+ a->GotoIf(a->WordEqual(properties, a->UndefinedConstant()), &no_properties); |
+ Node* properties_map = a->LoadMap(properties); |
+ a->GotoIf(a->IsSpecialReceiverMap(properties_map), &call_runtime); |
+ // Stay on the fast path only if there are no elements. |
+ a->GotoUnless(a->WordEqual(a->LoadElements(properties), |
+ a->LoadRoot(Heap::kEmptyFixedArrayRootIndex)), |
+ &call_runtime); |
+ // Jump to the runtime for slow objects. |
+ Node* bit_field3 = a->LoadMapBitField3(properties_map); |
+ Node* is_fast_map = a->Word32Equal( |
+ a->BitFieldDecode<Map::DictionaryMap>(bit_field3), a->Int32Constant(0)); |
+ a->GotoUnless(is_fast_map, &call_runtime); |
+ |
+ a->Branch( |
+ a->WordEqual( |
+ a->BitFieldDecodeWord<Map::NumberOfOwnDescriptorsBits>(bit_field3), |
+ a->IntPtrConstant(0)), |
+ &no_properties, &call_runtime); |
} |
- // Actually allocate the object. |
- Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(map); |
+ // Create a new object with the given prototype. |
+ a->Bind(&no_properties); |
+ { |
+ Variable map(a, MachineRepresentation::kTagged); |
+ Label non_null_proto(a), instantiate_map(a), good(a); |
+ |
+ a->Branch(a->WordEqual(prototype, a->NullConstant()), &good, |
+ &non_null_proto); |
- // Define the properties if properties was specified and is not undefined. |
- Handle<Object> properties = args.atOrUndefined(isolate, 2); |
- if (!properties->IsUndefined(isolate)) { |
- RETURN_FAILURE_ON_EXCEPTION( |
- isolate, JSReceiver::DefineProperties(isolate, object, properties)); |
+ a->Bind(&good); |
+ { |
+ map.Bind(a->LoadContextElement(context, |
+ Context::OBJECT_WITH_NULL_PROTOTYPE_MAP)); |
+ a->Goto(&instantiate_map); |
+ } |
+ |
+ a->Bind(&non_null_proto); |
+ { |
+ Node* object_function = |
+ a->LoadContextElement(context, Context::OBJECT_FUNCTION_INDEX); |
+ Node* object_function_map = a->LoadObjectField( |
+ object_function, JSFunction::kPrototypeOrInitialMapOffset); |
+ map.Bind(object_function_map); |
+ a->GotoIf(a->WordEqual(prototype, a->LoadMapPrototype(map.value())), |
+ &instantiate_map); |
+ // Try loading the prototype info. |
+ Node* prototype_info = |
+ a->LoadMapPrototypeInfo(a->LoadMap(prototype), &call_runtime); |
+ a->Comment("Load ObjectCreateMap from PrototypeInfo"); |
+ Node* weak_cell = |
+ a->LoadObjectField(prototype_info, PrototypeInfo::kObjectCreateMap); |
+ a->GotoIf(a->WordEqual(weak_cell, a->UndefinedConstant()), &call_runtime); |
+ map.Bind(a->LoadWeakCellValue(weak_cell, &call_runtime)); |
+ a->Goto(&instantiate_map); |
+ } |
+ |
+ a->Bind(&instantiate_map); |
+ { |
+ Node* instance = a->AllocateJSObjectFromMap(map.value()); |
+ a->Return(instance); |
+ } |
} |
- return *object; |
+ a->Bind(&call_runtime); |
+ { |
+ a->Return( |
+ a->CallRuntime(Runtime::kObjectCreate, context, prototype, properties)); |
+ } |
} |
// ES6 section 19.1.2.3 Object.defineProperties |