Handlify PropertyCell::SetValueInferType and friends.

This finally gets rid of the pesky trampoline in SetValueInferType and
enforces the layering between PropertyCell and Heap. It requires full
handlification of NewGlobalObject as well, which is only used when the
snapshot is created at compile-time.

R=rossberg@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17297 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mstarzinger@chromium.org 2013-10-21 13:55:24 +00:00
parent 5d8c7ebf37
commit 19b2ee1c40
7 changed files with 113 additions and 136 deletions

View File

@ -538,15 +538,22 @@ Handle<Cell> Factory::NewCell(Handle<Object> value) {
}
Handle<PropertyCell> Factory::NewPropertyCell(Handle<Object> value) {
AllowDeferredHandleDereference convert_to_cell;
Handle<PropertyCell> Factory::NewPropertyCellWithHole() {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocatePropertyCell(*value),
isolate()->heap()->AllocatePropertyCell(),
PropertyCell);
}
Handle<PropertyCell> Factory::NewPropertyCell(Handle<Object> value) {
AllowDeferredHandleDereference convert_to_cell;
Handle<PropertyCell> cell = NewPropertyCellWithHole();
PropertyCell::SetValueInferType(cell, value);
return cell;
}
Handle<AllocationSite> Factory::NewAllocationSite() {
CALL_HEAP_FUNCTION(
isolate(),
@ -1052,14 +1059,79 @@ Handle<JSModule> Factory::NewJSModule(Handle<Context> context,
}
Handle<GlobalObject> Factory::NewGlobalObject(
Handle<JSFunction> constructor) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->AllocateGlobalObject(*constructor),
// TODO(mstarzinger): Temporary wrapper until handlified.
static Handle<NameDictionary> NameDictionaryAdd(Handle<NameDictionary> dict,
Handle<Name> name,
Handle<Object> value,
PropertyDetails details) {
CALL_HEAP_FUNCTION(dict->GetIsolate(),
dict->Add(*name, *value, details),
NameDictionary);
}
static Handle<GlobalObject> NewGlobalObjectFromMap(Isolate* isolate,
Handle<Map> map) {
CALL_HEAP_FUNCTION(isolate,
isolate->heap()->Allocate(*map, OLD_POINTER_SPACE),
GlobalObject);
}
Handle<GlobalObject> Factory::NewGlobalObject(Handle<JSFunction> constructor) {
ASSERT(constructor->has_initial_map());
Handle<Map> map(constructor->initial_map());
ASSERT(map->is_dictionary_map());
// Make sure no field properties are described in the initial map.
// This guarantees us that normalizing the properties does not
// require us to change property values to PropertyCells.
ASSERT(map->NextFreePropertyIndex() == 0);
// Make sure we don't have a ton of pre-allocated slots in the
// global objects. They will be unused once we normalize the object.
ASSERT(map->unused_property_fields() == 0);
ASSERT(map->inobject_properties() == 0);
// Initial size of the backing store to avoid resize of the storage during
// bootstrapping. The size differs between the JS global object ad the
// builtins object.
int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
// Allocate a dictionary object for backing storage.
int at_least_space_for = map->NumberOfOwnDescriptors() * 2 + initial_size;
Handle<NameDictionary> dictionary = NewNameDictionary(at_least_space_for);
// The global object might be created from an object template with accessors.
// Fill these accessors into the dictionary.
Handle<DescriptorArray> descs(map->instance_descriptors());
for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
PropertyDetails details = descs->GetDetails(i);
ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
PropertyDetails d = PropertyDetails(details.attributes(), CALLBACKS, i + 1);
Handle<Name> name(descs->GetKey(i));
Handle<Object> value(descs->GetCallbacksObject(i), isolate());
Handle<PropertyCell> cell = NewPropertyCell(value);
NameDictionaryAdd(dictionary, name, cell, d);
}
// Allocate the global object and initialize it with the backing store.
Handle<GlobalObject> global = NewGlobalObjectFromMap(isolate(), map);
isolate()->heap()->InitializeJSObjectFromMap(*global, *dictionary, *map);
// Create a new map for the global object.
Handle<Map> new_map = Map::CopyDropDescriptors(map);
new_map->set_dictionary_map(true);
// Set up the global object as a normalized object.
global->set_map(*new_map);
global->set_properties(*dictionary);
// Make sure result is a global object with properties in dictionary.
ASSERT(global->IsGlobalObject() && !global->HasFastProperties());
return global;
}
Handle<JSObject> Factory::NewJSObjectFromMap(Handle<Map> map,
PretenureFlag pretenure,

View File

@ -248,6 +248,8 @@ class Factory {
Handle<Cell> NewCell(Handle<Object> value);
Handle<PropertyCell> NewPropertyCellWithHole();
Handle<PropertyCell> NewPropertyCell(Handle<Object> value);
Handle<AllocationSite> NewAllocationSite();
@ -306,7 +308,7 @@ class Factory {
Handle<JSObject> NewJSObject(Handle<JSFunction> constructor,
PretenureFlag pretenure = NOT_TENURED);
// Global objects are pretenured.
// Global objects are pretenured and initialized based on a constructor.
Handle<GlobalObject> NewGlobalObject(Handle<JSFunction> constructor);
// JS objects are pretenured when allocated by the bootstrapper and

View File

@ -2963,7 +2963,7 @@ MaybeObject* Heap::AllocateCell(Object* value) {
}
MaybeObject* Heap::AllocatePropertyCell(Object* value) {
MaybeObject* Heap::AllocatePropertyCell() {
Object* result;
MaybeObject* maybe_result = AllocateRawPropertyCell();
if (!maybe_result->ToObject(&result)) return maybe_result;
@ -2973,10 +2973,8 @@ MaybeObject* Heap::AllocatePropertyCell(Object* value) {
PropertyCell* cell = PropertyCell::cast(result);
cell->set_dependent_code(DependentCode::cast(empty_fixed_array()),
SKIP_WRITE_BARRIER);
cell->set_value(value);
cell->set_value(the_hole_value());
cell->set_type(Type::None());
maybe_result = cell->SetValueInferType(value);
if (maybe_result->IsFailure()) return maybe_result;
return result;
}
@ -4851,73 +4849,6 @@ MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler,
}
MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
ASSERT(constructor->has_initial_map());
Map* map = constructor->initial_map();
ASSERT(map->is_dictionary_map());
// Make sure no field properties are described in the initial map.
// This guarantees us that normalizing the properties does not
// require us to change property values to PropertyCells.
ASSERT(map->NextFreePropertyIndex() == 0);
// Make sure we don't have a ton of pre-allocated slots in the
// global objects. They will be unused once we normalize the object.
ASSERT(map->unused_property_fields() == 0);
ASSERT(map->inobject_properties() == 0);
// Initial size of the backing store to avoid resize of the storage during
// bootstrapping. The size differs between the JS global object ad the
// builtins object.
int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
// Allocate a dictionary object for backing storage.
NameDictionary* dictionary;
MaybeObject* maybe_dictionary =
NameDictionary::Allocate(
this,
map->NumberOfOwnDescriptors() * 2 + initial_size);
if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
// The global object might be created from an object template with accessors.
// Fill these accessors into the dictionary.
DescriptorArray* descs = map->instance_descriptors();
for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
PropertyDetails details = descs->GetDetails(i);
ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
PropertyDetails d = PropertyDetails(details.attributes(), CALLBACKS, i + 1);
Object* value = descs->GetCallbacksObject(i);
MaybeObject* maybe_value = AllocatePropertyCell(value);
if (!maybe_value->ToObject(&value)) return maybe_value;
MaybeObject* maybe_added = dictionary->Add(descs->GetKey(i), value, d);
if (!maybe_added->To(&dictionary)) return maybe_added;
}
// Allocate the global object and initialize it with the backing store.
JSObject* global;
MaybeObject* maybe_global = Allocate(map, OLD_POINTER_SPACE);
if (!maybe_global->To(&global)) return maybe_global;
InitializeJSObjectFromMap(global, dictionary, map);
// Create a new map for the global object.
Map* new_map;
MaybeObject* maybe_map = map->CopyDropDescriptors();
if (!maybe_map->To(&new_map)) return maybe_map;
new_map->set_dictionary_map(true);
// Set up the global object as a normalized object.
global->set_map(new_map);
global->set_properties(dictionary);
// Make sure result is a global object with properties in dictionary.
ASSERT(global->IsGlobalObject());
ASSERT(!global->HasFastProperties());
return global;
}
MaybeObject* Heap::CopyJSObject(JSObject* source, AllocationSite* site) {
// Never used to copy functions. If functions need to be copied we
// have to be careful to clear the literals array.

View File

@ -661,12 +661,6 @@ class Heap {
int length,
PretenureFlag pretenure = NOT_TENURED);
// Allocates and initializes a new global object based on a constructor.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* AllocateGlobalObject(JSFunction* constructor);
// Returns a deep copy of the JavaScript object.
// Properties and elements are copied too.
// Returns failure if allocation failed.
@ -888,22 +882,6 @@ class Heap {
// Please note this does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* AllocateSymbol();
// Allocate a tenured simple cell.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* AllocateCell(Object* value);
// Allocate a tenured JS global property cell.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* AllocatePropertyCell(Object* value);
// Allocate Box.
MUST_USE_RESULT MaybeObject* AllocateBox(Object* value,
PretenureFlag pretenure);
// Allocate a tenured AllocationSite. It's payload is null
MUST_USE_RESULT MaybeObject* AllocateAllocationSite();
@ -2165,6 +2143,16 @@ class Heap {
// Allocate empty fixed double array.
MUST_USE_RESULT MaybeObject* AllocateEmptyFixedDoubleArray();
// Allocate a tenured simple cell.
MUST_USE_RESULT MaybeObject* AllocateCell(Object* value);
// Allocate a tenured JS global property cell initialized with the hole.
MUST_USE_RESULT MaybeObject* AllocatePropertyCell();
// Allocate Box.
MUST_USE_RESULT MaybeObject* AllocateBox(Object* value,
PretenureFlag pretenure);
// Performs a minor collection in new generation.
void Scavenge();

View File

@ -16310,8 +16310,8 @@ void PropertyCell::set_type(Type* type, WriteBarrierMode ignored) {
}
Type* PropertyCell::UpdateType(Handle<PropertyCell> cell,
Handle<Object> value) {
Type* PropertyCell::UpdatedType(Handle<PropertyCell> cell,
Handle<Object> value) {
Isolate* isolate = cell->GetIsolate();
Handle<Type> old_type(cell->type(), isolate);
// TODO(2803): Do not track ConsString as constant because they cannot be
@ -16336,27 +16336,12 @@ Type* PropertyCell::UpdateType(Handle<PropertyCell> cell,
void PropertyCell::SetValueInferType(Handle<PropertyCell> cell,
Handle<Object> value,
WriteBarrierMode mode) {
CALL_HEAP_FUNCTION_VOID(cell->GetIsolate(),
cell->SetValueInferType(*value, mode));
}
MaybeObject* PropertyCell::SetValueInferType(Object* value,
WriteBarrierMode ignored) {
set_value(value, ignored);
if (!Type::Any()->Is(type())) {
IdempotentPointerToHandleCodeTrampoline trampoline(GetIsolate());
MaybeObject* maybe_type = trampoline.CallWithReturnValue(
&PropertyCell::UpdateType,
Handle<PropertyCell>(this),
Handle<Object>(value, GetIsolate()));
Type* new_type = NULL;
if (!maybe_type->To(&new_type)) return maybe_type;
set_type(new_type);
Handle<Object> value) {
cell->set_value(*value);
if (!Type::Any()->Is(cell->type())) {
Type* new_type = UpdatedType(cell, value);
cell->set_type(new_type);
}
return value;
}

View File

@ -9193,11 +9193,17 @@ class PropertyCell: public Cell {
// a change of the type of the cell's contents, code dependent on the cell
// will be deoptimized.
static void SetValueInferType(Handle<PropertyCell> cell,
Handle<Object> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
MUST_USE_RESULT MaybeObject* SetValueInferType(
Object* value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
Handle<Object> value);
// Computes the new type of the cell's contents for the given value, but
// without actually modifying the 'type' field.
// TODO(mstarzinger): Return value should be handlified.
static Type* UpdatedType(Handle<PropertyCell> cell,
Handle<Object> value);
void AddDependentCompilationInfo(CompilationInfo* info);
void AddDependentCode(Handle<Code> code);
// Casting.
static inline PropertyCell* cast(Object* obj);
@ -9222,13 +9228,6 @@ class PropertyCell: public Cell {
kSize,
kSize> BodyDescriptor;
void AddDependentCompilationInfo(CompilationInfo* info);
void AddDependentCode(Handle<Code> code);
static Type* UpdateType(Handle<PropertyCell> cell,
Handle<Object> value);
private:
DECL_ACCESSORS(type_raw, Object)
DISALLOW_IMPLICIT_CONSTRUCTORS(PropertyCell);

View File

@ -268,7 +268,7 @@ Handle<Code> StubCache::ComputeStoreGlobal(Handle<Name> name,
Handle<Object> value,
StrictModeFlag strict_mode) {
Isolate* isolate = cell->GetIsolate();
Handle<Type> union_type(PropertyCell::UpdateType(cell, value), isolate);
Handle<Type> union_type(PropertyCell::UpdatedType(cell, value), isolate);
bool is_constant = union_type->IsConstant();
StoreGlobalStub stub(strict_mode, is_constant);