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:
parent
5d8c7ebf37
commit
19b2ee1c40
@ -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,
|
||||
|
@ -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
|
||||
|
73
src/heap.cc
73
src/heap.cc
@ -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.
|
||||
|
32
src/heap.h
32
src/heap.h
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user