Commit 6a51d311 authored by bmeurer's avatar bmeurer Committed by Commit bot

[runtime] Migrate Object.create to C++.

There's no point in keeping the ObjectCreate JavaScript wrapper
function, which even does allocation site pretenuring for the
instances created via Object.create (where ObjectCreate itself is
the AllocationSite), and does not offer any sane way forward.

Instead introduce a new ObjectCreate C++ builtin, which currently
serves as a baseline implementation, on top of which we can think
about ways to optimize Object.create for the common case (i.e.
frameworks such as Ember.js make heavy use of Object.create).

R=cbruni@chromium.org
TBR=hpayer@chromium.org

Review URL: https://codereview.chromium.org/1558433002

Cr-Commit-Position: refs/heads/master@{#33061}
parent 5a49eb01
......@@ -1079,9 +1079,10 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Handle<String> object_name = factory->Object_string();
JSObject::AddProperty(
global_object, object_name, isolate->object_function(), DONT_ENUM);
SimpleInstallFunction(isolate->object_function(),
isolate->factory()->InternalizeUtf8String("assign"),
SimpleInstallFunction(isolate->object_function(), factory->assign_string(),
Builtins::kObjectAssign, 2, false);
SimpleInstallFunction(isolate->object_function(), factory->create_string(),
Builtins::kObjectCreate, 2, false);
Handle<JSObject> global(native_context()->global_object());
......
......@@ -1489,6 +1489,39 @@ BUILTIN(ObjectAssign) {
}
// ES6 section 19.1.2.2 Object.create ( O [ , Properties ] )
BUILTIN(ObjectCreate) {
HandleScope scope(isolate);
Handle<Object> prototype = args.atOrUndefined(isolate, 1);
if (!prototype->IsNull() && !prototype->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, prototype));
}
// 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) {
map = Map::TransitionToPrototype(map, prototype, FAST_PROTOTYPE);
}
// Actually allocate the object.
Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(map);
// Define the properties if properties was specified and is not undefined.
Handle<Object> properties = args.atOrUndefined(isolate, 2);
if (!properties->IsUndefined()) {
RETURN_FAILURE_ON_EXCEPTION(
isolate, JSReceiver::DefineProperties(isolate, object, properties));
}
return *object;
}
namespace {
bool CodeGenerationFromStringsAllowed(Isolate* isolate,
......
......@@ -76,6 +76,7 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(GlobalEval, kTarget) \
\
V(ObjectAssign, kNone) \
V(ObjectCreate, kNone) \
V(ObjectProtoToString, kNone) \
\
V(ProxyConstructor, kNone) \
......
......@@ -212,6 +212,7 @@ namespace internal {
#define INTERNALIZED_STRING_LIST(V) \
V(anonymous_string, "anonymous") \
V(apply_string, "apply") \
V(assign_string, "assign") \
V(arguments_string, "arguments") \
V(Arguments_string, "Arguments") \
V(Array_string, "Array") \
......@@ -237,6 +238,7 @@ namespace internal {
V(configurable_string, "configurable") \
V(constructor_string, "constructor") \
V(construct_string, "construct") \
V(create_string, "create") \
V(Date_string, "Date") \
V(default_string, "default") \
V(defineProperty_string, "defineProperty") \
......
......@@ -793,18 +793,6 @@ function ObjectGetOwnPropertyNames(obj) {
}
// ES5 section 15.2.3.5.
function ObjectCreate(proto, properties) {
if (!IS_RECEIVER(proto) && proto !== null) {
throw MakeTypeError(kProtoObjectOrNull, proto);
}
var obj = {};
%InternalSetPrototype(obj, proto);
if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
return obj;
}
// ES5 section 15.2.3.6.
function ObjectDefineProperty(obj, p, attributes) {
// The new pure-C++ implementation doesn't support O.o.
......@@ -947,7 +935,6 @@ utils.InstallGetterSetter(GlobalObject.prototype, "__proto__", ObjectGetProto,
utils.InstallFunctions(GlobalObject, DONT_ENUM, [
// assign is added in bootstrapper.cc.
"keys", ObjectKeys,
"create", ObjectCreate,
"defineProperty", ObjectDefineProperty,
"defineProperties", ObjectDefineProperties,
"freeze", ObjectFreezeJS,
......
......@@ -6285,28 +6285,31 @@ Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object,
// ES6 19.1.2.3.1
// static
Object* JSReceiver::DefineProperties(Isolate* isolate, Handle<Object> object,
Handle<Object> properties) {
MaybeHandle<Object> JSReceiver::DefineProperties(Isolate* isolate,
Handle<Object> object,
Handle<Object> properties) {
// 1. If Type(O) is not Object, throw a TypeError exception.
if (!object->IsJSReceiver()) {
Handle<String> fun_name =
isolate->factory()->InternalizeUtf8String("Object.defineProperties");
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name));
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kCalledOnNonObject, fun_name),
Object);
}
// 2. Let props be ToObject(Properties).
// 3. ReturnIfAbrupt(props).
Handle<JSReceiver> props;
if (!Object::ToObject(isolate, properties).ToHandle(&props)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject));
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kUndefinedOrNullToObject),
Object);
}
// 4. Let keys be props.[[OwnPropertyKeys]]().
// 5. ReturnIfAbrupt(keys).
Handle<FixedArray> keys;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
ASSIGN_RETURN_ON_EXCEPTION(
isolate, keys,
JSReceiver::GetKeys(props, JSReceiver::OWN_ONLY, ALL_PROPERTIES));
JSReceiver::GetKeys(props, JSReceiver::OWN_ONLY, ALL_PROPERTIES), Object);
// 6. Let descriptors be an empty List.
int capacity = keys->length();
std::vector<PropertyDescriptor> descriptors(capacity);
......@@ -6321,7 +6324,7 @@ Object* JSReceiver::DefineProperties(Isolate* isolate, Handle<Object> object,
isolate, props, next_key, &success, LookupIterator::HIDDEN);
DCHECK(success);
Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
if (!maybe.IsJust()) return isolate->heap()->exception();
if (!maybe.IsJust()) return MaybeHandle<Object>();
PropertyAttributes attrs = maybe.FromJust();
// 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true:
if (attrs == ABSENT) continue;
......@@ -6329,13 +6332,13 @@ Object* JSReceiver::DefineProperties(Isolate* isolate, Handle<Object> object,
// 7c i. Let descObj be Get(props, nextKey).
// 7c ii. ReturnIfAbrupt(descObj).
Handle<Object> desc_obj;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, desc_obj,
Object::GetProperty(&it));
ASSIGN_RETURN_ON_EXCEPTION(isolate, desc_obj, Object::GetProperty(&it),
Object);
// 7c iii. Let desc be ToPropertyDescriptor(descObj).
success = PropertyDescriptor::ToPropertyDescriptor(
isolate, desc_obj, &descriptors[descriptors_index]);
// 7c iv. ReturnIfAbrupt(desc).
if (!success) return isolate->heap()->exception();
if (!success) return MaybeHandle<Object>();
// 7c v. Append the pair (a two element List) consisting of nextKey and
// desc to the end of descriptors.
descriptors[descriptors_index].set_name(next_key);
......@@ -6351,11 +6354,11 @@ Object* JSReceiver::DefineProperties(Isolate* isolate, Handle<Object> object,
DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object),
desc->name(), desc, THROW_ON_ERROR);
// 8d. ReturnIfAbrupt(status).
MAYBE_RETURN(status, isolate->heap()->exception());
if (!status.IsJust()) return MaybeHandle<Object>();
CHECK(status.FromJust());
}
// 9. Return o.
return *object;
return object;
}
......
......@@ -1836,9 +1836,8 @@ class JSReceiver: public HeapObject {
Handle<Object> object,
Handle<Object> name,
Handle<Object> attributes);
MUST_USE_RESULT static Object* DefineProperties(Isolate* isolate,
Handle<Object> object,
Handle<Object> properties);
MUST_USE_RESULT static MaybeHandle<Object> DefineProperties(
Isolate* isolate, Handle<Object> object, Handle<Object> properties);
// "virtual" dispatcher to the correct [[DefineOwnProperty]] implementation.
MUST_USE_RESULT static Maybe<bool> DefineOwnProperty(
......
......@@ -1415,7 +1415,10 @@ RUNTIME_FUNCTION(Runtime_ObjectDefineProperties) {
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(Object, o, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, properties, 1);
return JSReceiver::DefineProperties(isolate, o, properties);
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, o, JSReceiver::DefineProperties(isolate, o, properties));
return *o;
}
} // namespace internal
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment