Commit b7ff0d71 authored by cbruni's avatar cbruni Committed by Commit bot

[stubs] Implement TF builtin for Object.create fast paths

BUG=

Review-Url: https://chromiumcodereview.appspot.com/2385423005
Cr-Commit-Position: refs/heads/master@{#40429}
parent 3c10b97c
......@@ -1129,7 +1129,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
SimpleInstallFunction(object_function, factory->assign_string(),
Builtins::kObjectAssign, 2, false);
SimpleInstallFunction(object_function, factory->create_string(),
Builtins::kObjectCreate, 2, false);
Builtins::kObjectCreate, 2, true);
SimpleInstallFunction(object_function, "getOwnPropertyDescriptor",
Builtins::kObjectGetOwnPropertyDescriptor, 2, false);
SimpleInstallFunction(object_function, "getOwnPropertyNames",
......
......@@ -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
......
......@@ -522,7 +522,7 @@ namespace internal {
\
/* Object */ \
CPP(ObjectAssign) \
CPP(ObjectCreate) \
TFJ(ObjectCreate, 3) \
CPP(ObjectDefineGetter) \
CPP(ObjectDefineProperties) \
CPP(ObjectDefineProperty) \
......
// Copyright 2016 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.
#include "src/code-stub-assembler.h"
#include "src/code-factory.h"
#include "src/frames-inl.h"
......@@ -525,6 +524,11 @@ Node* CodeStubAssembler::WordIsPositiveSmi(Node* a) {
IntPtrConstant(0));
}
Node* CodeStubAssembler::WordIsWordAligned(Node* word) {
return WordEqual(IntPtrConstant(0),
WordAnd(word, IntPtrConstant((1 << kPointerSizeLog2) - 1)));
}
void CodeStubAssembler::BranchIfSimd128Equal(Node* lhs, Node* lhs_map,
Node* rhs, Node* rhs_map,
Label* if_equal,
......@@ -625,6 +629,24 @@ void CodeStubAssembler::BranchIfPrototypesHaveNoElements(
}
}
void CodeStubAssembler::BranchIfJSReceiver(Node* object, Label* if_true,
Label* if_false) {
GotoIf(TaggedIsSmi(object), if_false);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
Branch(Int32GreaterThanOrEqual(LoadInstanceType(object),
Int32Constant(FIRST_JS_RECEIVER_TYPE)),
if_true, if_false);
}
void CodeStubAssembler::BranchIfJSObject(Node* object, Label* if_true,
Label* if_false) {
GotoIf(TaggedIsSmi(object), if_false);
STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
Branch(Int32GreaterThanOrEqual(LoadInstanceType(object),
Int32Constant(FIRST_JS_OBJECT_TYPE)),
if_true, if_false);
}
void CodeStubAssembler::BranchIfFastJSArray(Node* object, Node* context,
Label* if_true, Label* if_false) {
// Bailout if receiver is a Smi.
......@@ -785,6 +807,11 @@ Node* CodeStubAssembler::InnerAllocate(Node* previous, int offset) {
return InnerAllocate(previous, IntPtrConstant(offset));
}
Node* CodeStubAssembler::IsRegularHeapObjectSize(Node* size) {
return UintPtrLessThanOrEqual(size,
IntPtrConstant(kMaxRegularHeapObjectSize));
}
void CodeStubAssembler::BranchIfToBooleanIsTrue(Node* value, Label* if_true,
Label* if_false) {
Label if_valueissmi(this), if_valueisnotsmi(this), if_valueisstring(this),
......@@ -950,10 +977,14 @@ Node* CodeStubAssembler::LoadInstanceType(Node* object) {
return LoadMapInstanceType(LoadMap(object));
}
Node* CodeStubAssembler::HasInstanceType(Node* object,
InstanceType instance_type) {
return Word32Equal(LoadInstanceType(object), Int32Constant(instance_type));
}
void CodeStubAssembler::AssertInstanceType(Node* object,
InstanceType instance_type) {
CSA_ASSERT(
Word32Equal(LoadInstanceType(object), Int32Constant(instance_type)));
CSA_ASSERT(HasInstanceType(object, instance_type));
}
Node* CodeStubAssembler::LoadProperties(Node* object) {
......@@ -1005,6 +1036,17 @@ Node* CodeStubAssembler::LoadMapPrototype(Node* map) {
return LoadObjectField(map, Map::kPrototypeOffset);
}
Node* CodeStubAssembler::LoadMapPrototypeInfo(Node* map,
Label* if_no_proto_info) {
Node* prototype_info =
LoadObjectField(map, Map::kTransitionsOrPrototypeInfoOffset);
GotoIf(TaggedIsSmi(prototype_info), if_no_proto_info);
GotoUnless(WordEqual(LoadMap(prototype_info),
LoadRoot(Heap::kPrototypeInfoMapRootIndex)),
if_no_proto_info);
return prototype_info;
}
Node* CodeStubAssembler::LoadMapInstanceSize(Node* map) {
return ChangeUint32ToWord(
LoadObjectField(map, Map::kInstanceSizeOffset, MachineType::Uint8()));
......@@ -1050,6 +1092,20 @@ Node* CodeStubAssembler::LoadMapConstructor(Node* map) {
return result.value();
}
Node* CodeStubAssembler::IsSpecialReceiverMap(Node* map) {
Node* bit_field = LoadMapBitField(map);
Node* mask = Int32Constant(1 << Map::kHasNamedInterceptor |
1 << Map::kIsAccessCheckNeeded);
Assert(Word32Equal(Word32And(bit_field, mask), Int32Constant(0)));
return IsSpecialReceiverInstanceType(LoadMapInstanceType(map));
}
Node* CodeStubAssembler::IsSpecialReceiverInstanceType(Node* instance_type) {
STATIC_ASSERT(JS_GLOBAL_OBJECT_TYPE <= LAST_SPECIAL_RECEIVER_TYPE);
return Int32LessThanOrEqual(instance_type,
Int32Constant(LAST_SPECIAL_RECEIVER_TYPE));
}
Node* CodeStubAssembler::LoadNameHashField(Node* name) {
return LoadObjectField(name, Name::kHashFieldOffset, MachineType::Uint32());
}
......@@ -1604,6 +1660,66 @@ Node* CodeStubAssembler::AllocateRegExpResult(Node* context, Node* length,
return result;
}
Node* CodeStubAssembler::AllocateJSObjectFromMap(Node* map, Node* properties,
Node* elements) {
Node* size =
IntPtrMul(LoadMapInstanceSize(map), IntPtrConstant(kPointerSize));
CSA_ASSERT(IsRegularHeapObjectSize(size));
Node* object = Allocate(size);
StoreMapNoWriteBarrier(object, map);
InitializeJSObjectFromMap(object, map, size, properties, elements);
return object;
}
void CodeStubAssembler::InitializeJSObjectFromMap(Node* object, Node* map,
Node* size, Node* properties,
Node* elements) {
// This helper assumes that the object is in new-space, as guarded by the
// check in AllocatedJSObjectFromMap.
if (properties == nullptr) {
StoreObjectFieldRoot(object, JSObject::kPropertiesOffset,
Heap::kEmptyFixedArrayRootIndex);
} else {
StoreObjectFieldNoWriteBarrier(object, JSObject::kPropertiesOffset,
properties);
}
if (elements == nullptr) {
StoreObjectFieldRoot(object, JSObject::kElementsOffset,
Heap::kEmptyFixedArrayRootIndex);
} else {
StoreObjectFieldNoWriteBarrier(object, JSObject::kElementsOffset, elements);
}
InitializeJSObjectBody(object, map, size, JSObject::kHeaderSize);
}
void CodeStubAssembler::InitializeJSObjectBody(Node* object, Node* map,
Node* size, int start_offset) {
// TODO(cbruni): activate in-object slack tracking machinery.
Comment("InitializeJSObjectBody");
Node* filler = LoadRoot(Heap::kUndefinedValueRootIndex);
// Calculate the untagged field addresses.
Node* start_address =
IntPtrAdd(object, IntPtrConstant(start_offset - kHeapObjectTag));
Node* end_address =
IntPtrSub(IntPtrAdd(object, size), IntPtrConstant(kHeapObjectTag));
StoreFieldsNoWriteBarrier(start_address, end_address, filler);
}
void CodeStubAssembler::StoreFieldsNoWriteBarrier(Node* start_address,
Node* end_address,
Node* value) {
Comment("StoreFieldsNoWriteBarrier");
CSA_ASSERT(WordIsWordAligned(start_address));
CSA_ASSERT(WordIsWordAligned(end_address));
BuildFastLoop(MachineType::PointerRepresentation(), start_address,
end_address,
[value](CodeStubAssembler* a, Node* current) {
a->StoreNoWriteBarrier(MachineType::PointerRepresentation(),
current, value);
},
kPointerSize, IndexAdvanceMode::kPost);
}
Node* CodeStubAssembler::AllocateUninitializedJSArrayWithoutElements(
ElementsKind kind, Node* array_map, Node* length, Node* allocation_site) {
Comment("begin allocation of JSArray without elements");
......
......@@ -156,6 +156,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* InnerAllocate(compiler::Node* previous, int offset);
compiler::Node* InnerAllocate(compiler::Node* previous,
compiler::Node* offset);
compiler::Node* IsRegularHeapObjectSize(compiler::Node* size);
void Assert(compiler::Node* condition, const char* string = nullptr,
const char* file = nullptr, int line = 0);
......@@ -164,6 +165,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* TaggedIsSmi(compiler::Node* a);
// Check that the value is a non-negative smi.
compiler::Node* WordIsPositiveSmi(compiler::Node* a);
// Check that a word has a word-aligned address.
compiler::Node* WordIsWordAligned(compiler::Node* word);
void BranchIfSmiEqual(compiler::Node* a, compiler::Node* b, Label* if_true,
Label* if_false) {
......@@ -199,6 +202,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
if_notequal);
}
void BranchIfJSReceiver(compiler::Node* object, Label* if_true,
Label* if_false);
void BranchIfJSObject(compiler::Node* object, Label* if_true,
Label* if_false);
void BranchIfFastJSArray(compiler::Node* object, compiler::Node* context,
Label* if_true, Label* if_false);
......@@ -234,6 +242,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* LoadMap(compiler::Node* object);
// Load the instance type of an HeapObject.
compiler::Node* LoadInstanceType(compiler::Node* object);
// Compare the instance the type of the object against the provided one.
compiler::Node* HasInstanceType(compiler::Node* object, InstanceType type);
// Checks that given heap object has given instance type.
void AssertInstanceType(compiler::Node* object, InstanceType instance_type);
// Load the properties backing store of a JSObject.
......@@ -260,6 +270,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* LoadMapDescriptors(compiler::Node* map);
// Load the prototype of a map.
compiler::Node* LoadMapPrototype(compiler::Node* map);
// Load the prototype info of a map. The result has to be checked if it is a
// prototype info object or not.
compiler::Node* LoadMapPrototypeInfo(compiler::Node* map,
Label* if_has_no_proto_info);
// Load the instance size of a Map.
compiler::Node* LoadMapInstanceSize(compiler::Node* map);
// Load the inobject properties count of a Map (valid only for JSObjects).
......@@ -268,6 +282,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* LoadMapConstructorFunctionIndex(compiler::Node* map);
// Load the constructor of a Map (equivalent to Map::GetConstructor()).
compiler::Node* LoadMapConstructor(compiler::Node* map);
// Check whether the map is for an object with special properties, such as a
// JSProxy or an object with interceptors.
compiler::Node* IsSpecialReceiverMap(compiler::Node* map);
compiler::Node* IsSpecialReceiverInstanceType(compiler::Node* instance_type);
// Load the hash field of a name as an uint32 value.
compiler::Node* LoadNameHashField(compiler::Node* name);
......@@ -350,6 +368,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* object, compiler::Node* index, compiler::Node* value,
ParameterMode parameter_mode = INTEGER_PARAMETERS);
void StoreFieldsNoWriteBarrier(compiler::Node* start_address,
compiler::Node* end_address,
compiler::Node* value);
// Allocate a HeapNumber without initializing its value.
compiler::Node* AllocateHeapNumber(MutableMode mode = IMMUTABLE);
// Allocate a HeapNumber with a specific value.
......@@ -409,6 +431,19 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* index,
compiler::Node* input);
compiler::Node* AllocateJSObjectFromMap(compiler::Node* map,
compiler::Node* properties = nullptr,
compiler::Node* elements = nullptr);
void InitializeJSObjectFromMap(compiler::Node* object, compiler::Node* map,
compiler::Node* size,
compiler::Node* properties = nullptr,
compiler::Node* elements = nullptr);
void InitializeJSObjectBody(compiler::Node* object, compiler::Node* map,
compiler::Node* size,
int start_offset = JSObject::kHeaderSize);
// Allocate a JSArray without elements and initialize the header fields.
compiler::Node* AllocateUninitializedJSArrayWithoutElements(
ElementsKind kind, compiler::Node* array_map, compiler::Node* length,
......
......@@ -58,6 +58,7 @@ class RawMachineLabel;
V(Uint32LessThanOrEqual) \
V(Uint32GreaterThanOrEqual) \
V(UintPtrLessThan) \
V(UintPtrLessThanOrEqual) \
V(UintPtrGreaterThan) \
V(UintPtrGreaterThanOrEqual) \
V(WordEqual) \
......
......@@ -1206,6 +1206,7 @@ void PrototypeInfo::PrototypeInfoPrint(std::ostream& os) { // NOLINT
os << "\n - prototype users: " << Brief(prototype_users());
os << "\n - registry slot: " << registry_slot();
os << "\n - validity cell: " << Brief(validity_cell());
os << "\n - object create map: " << Brief(object_create_map());
os << "\n";
}
......
......@@ -207,6 +207,59 @@ RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty) {
return isolate->heap()->false_value();
}
// 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.
RUNTIME_FUNCTION(Runtime_ObjectCreate) {
HandleScope scope(isolate);
Handle<Object> prototype = args.at<Object>(0);
if (!prototype->IsNull(isolate) && !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) {
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);
}
}
// 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.at<Object>(1);
if (!properties->IsUndefined(isolate)) {
RETURN_FAILURE_ON_EXCEPTION(
isolate, JSReceiver::DefineProperties(isolate, object, properties));
}
return *object;
}
MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
Handle<Object> object,
Handle<Object> key,
......
......@@ -378,6 +378,7 @@ namespace internal {
#define FOR_EACH_INTRINSIC_OBJECT(F) \
F(GetPrototype, 1, 1) \
F(ObjectHasOwnProperty, 2, 1) \
F(ObjectCreate, 2, 1) \
F(InternalSetPrototype, 2, 1) \
F(OptimizeObjectForAddingMultipleProperties, 2, 1) \
F(GetProperty, 2, 1) \
......
......@@ -1509,5 +1509,67 @@ TEST(GotoIfExceptionMultiple) {
CHECK(constructor->SameValue(*isolate->type_error_function()));
}
TEST(AllocateJSObjectFromMap) {
Isolate* isolate(CcTest::InitIsolateOnce());
Factory* factory = isolate->factory();
const int kNumParams = 3;
CodeStubAssemblerTester m(isolate, kNumParams);
{
Node* map = m.Parameter(0);
Node* properties = m.Parameter(1);
Node* elements = m.Parameter(2);
Node* result = m.AllocateJSObjectFromMap(map, properties, elements);
m.Return(result);
}
Handle<Code> code = m.GenerateCode();
FunctionTester ft(code, kNumParams);
Handle<Map> maps[] = {
isolate->object_with_null_prototype_map(),
handle(isolate->object_function()->initial_map(), isolate),
handle(isolate->array_function()->initial_map(), isolate),
};
#define VERIFY(result, map_value, properties_value, elements_value) \
CHECK_EQ(result->map(), map_value); \
CHECK_EQ(result->properties(), properties_value); \
CHECK_EQ(result->elements(), elements_value);
{
Handle<Object> empty_fixed_array = factory->empty_fixed_array();
for (int i = 0; i < arraysize(maps); i++) {
Handle<Map> map = maps[i];
Handle<JSObject> result = Handle<JSObject>::cast(
ft.Call(map, empty_fixed_array, empty_fixed_array).ToHandleChecked());
VERIFY(result, *map, *empty_fixed_array, *empty_fixed_array);
#ifdef VERIFY_HEAP
isolate->heap()->Verify();
#endif
}
}
{
// TODO(cbruni): handle in-object properties
Handle<JSObject> object = Handle<JSObject>::cast(
v8::Utils::OpenHandle(*CompileRun("var object = {a:1,b:2, 1:1, 2:2}; "
"object")));
JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
"Normalize");
Handle<JSObject> result = Handle<JSObject>::cast(
ft.Call(handle(object->map()), handle(object->properties()),
handle(object->elements()))
.ToHandleChecked());
VERIFY(result, object->map(), object->properties(), object->elements());
#ifdef VERIFY_HEAP
isolate->heap()->Verify();
#endif
}
}
} // namespace internal
} // namespace v8
......@@ -248,3 +248,14 @@ for (x in sonOfTricky) {
sum += sonOfTricky[x];
}
assertEquals(16, sum);
(function createWithEmptyProtoInfoCreateMap() {
var proto = {a:1};
var instance = {__proto__: proto };
// Try force creation of prototype info on proto by loading a proto property.
assertEquals(instance.a, 1);
var result = Object.create(proto, {});
assertEquals(result.a, 1);
assertEquals(result.__proto__, proto);
})()
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