Commit 4a7eec59 authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[turbofan] Fix prototype mutation in Object.create lowering.

This makes sure the builtin lowering of Object.create doesn't invalidate
any previously taken dependencies. Aborting compilation after such cases
would lead to repeating optimization attempts without learning, hence we
disallow such situations.

R=verwaest@chromium.org
BUG=chromium:794394,chromium:786723

Change-Id: I6b6928cab19692bbbe3cd241ade862a2306eb0c7
Reviewed-on: https://chromium-review.googlesource.com/827066
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50128}
parent 436fe567
......@@ -2261,14 +2261,13 @@ Reduction JSBuiltinReducer::ReduceObjectCreate(Node* 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);
Handle<Map> instance_map;
MaybeHandle<Map> maybe_instance_map =
Map::TryGetObjectCreateMap(prototype_const);
if (!maybe_instance_map.ToHandle(&instance_map)) return NoChange();
Node* properties = jsgraph()->EmptyFixedArrayConstant();
if (instance_map->is_dictionary_map()) {
// Allocated an empty NameDictionary as backing store for the properties.
......
......@@ -5240,6 +5240,24 @@ Handle<Map> Map::GetObjectCreateMap(Handle<HeapObject> prototype) {
return Map::TransitionToPrototype(map, prototype);
}
// static
MaybeHandle<Map> Map::TryGetObjectCreateMap(Handle<HeapObject> prototype) {
Isolate* isolate = prototype->GetIsolate();
Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
isolate);
if (map->prototype() == *prototype) return map;
if (prototype->IsNull(isolate)) {
return isolate->slow_object_with_null_prototype_map();
}
if (!prototype->IsJSObject()) return MaybeHandle<Map>();
Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype);
if (!js_prototype->map()->is_prototype_map()) return MaybeHandle<Map>();
Handle<PrototypeInfo> info =
Map::GetOrCreatePrototypeInfo(js_prototype, isolate);
if (!info->HasObjectCreateMap()) return MaybeHandle<Map>();
return handle(info->ObjectCreateMap(), isolate);
}
template <class T>
static int AppendUniqueCallbacks(Handle<TemplateList> callbacks,
Handle<typename T::Array> array,
......
......@@ -689,8 +689,14 @@ class Map : public HeapObject {
static void EnsureDescriptorSlack(Handle<Map> map, int slack);
// Returns the map to be used for instances when the given {prototype} is
// passed to an Object.create call. Might transition the given {prototype}.
static Handle<Map> GetObjectCreateMap(Handle<HeapObject> prototype);
// Similar to {GetObjectCreateMap} but does not transition {prototype} and
// fails gracefully by returning an empty handle instead.
static MaybeHandle<Map> TryGetObjectCreateMap(Handle<HeapObject> prototype);
// Computes a hash value for this map, to be used in HashTables and such.
int Hash();
......
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --expose-gc --function-context-specialization
function f() {
var o = {};
function g() {
o.x = 1;
return Object.create(o);
};
gc();
o.x = 10;
%OptimizeFunctionOnNextCall(g);
g();
}
f();
f();
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