Preserve constant function transition when adding the same function.
This should help in cases like: function Constructor() { this.foo = constFunction; this.bar = "baz"; } for (...) { o = new Constructor(); // Constant call IC will work. o.foo(); // Inlined property load will see the same map. use(o.bar); } This change also fixes a latent bug in custom call IC-s for strings exposed by string-charcodeat.js. Review URL: http://codereview.chromium.org/3160006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5254 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
5cd4a9b78d
commit
421db370d9
@ -1571,6 +1571,9 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
|
||||
// -- esp[(argc + 1) * 4] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
// If object is not a string, bail out to regular call.
|
||||
if (!object->IsString()) return Heap::undefined_value();
|
||||
|
||||
const int argc = arguments().immediate();
|
||||
|
||||
Label miss;
|
||||
@ -1581,6 +1584,7 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object,
|
||||
GenerateDirectLoadGlobalFunctionPrototype(masm(),
|
||||
Context::STRING_FUNCTION_INDEX,
|
||||
eax);
|
||||
ASSERT(object != holder);
|
||||
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
|
||||
ebx, edx, edi, name, &miss);
|
||||
|
||||
@ -1635,6 +1639,9 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
|
||||
// -- esp[(argc + 1) * 4] : receiver
|
||||
// -----------------------------------
|
||||
|
||||
// If object is not a string, bail out to regular call.
|
||||
if (!object->IsString()) return Heap::undefined_value();
|
||||
|
||||
const int argc = arguments().immediate();
|
||||
|
||||
Label miss;
|
||||
@ -1646,6 +1653,7 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
|
||||
GenerateDirectLoadGlobalFunctionPrototype(masm(),
|
||||
Context::STRING_FUNCTION_INDEX,
|
||||
eax);
|
||||
ASSERT(object != holder);
|
||||
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
|
||||
ebx, edx, edi, name, &miss);
|
||||
|
||||
|
@ -554,10 +554,11 @@ void MarkCompactCollector::MarkDescriptorArray(
|
||||
ASSERT(contents->IsFixedArray());
|
||||
ASSERT(contents->length() >= 2);
|
||||
SetMark(contents);
|
||||
// Contents contains (value, details) pairs. If the details say
|
||||
// that the type of descriptor is MAP_TRANSITION, CONSTANT_TRANSITION,
|
||||
// or NULL_DESCRIPTOR, we don't mark the value as live. Only for
|
||||
// type MAP_TRANSITION is the value a Object* (a Map*).
|
||||
// Contents contains (value, details) pairs. If the details say that
|
||||
// the type of descriptor is MAP_TRANSITION, CONSTANT_TRANSITION, or
|
||||
// NULL_DESCRIPTOR, we don't mark the value as live. Only for
|
||||
// MAP_TRANSITION and CONSTANT_TRANSITION is the value an Object* (a
|
||||
// Map*).
|
||||
for (int i = 0; i < contents->length(); i += 2) {
|
||||
// If the pair (value, details) at index i, i+1 is not
|
||||
// a transition or null descriptor, mark the value.
|
||||
|
@ -1493,6 +1493,16 @@ int DescriptorArray::Search(String* name) {
|
||||
}
|
||||
|
||||
|
||||
int DescriptorArray::SearchWithCache(String* name) {
|
||||
int number = DescriptorLookupCache::Lookup(this, name);
|
||||
if (number == DescriptorLookupCache::kAbsent) {
|
||||
number = Search(name);
|
||||
DescriptorLookupCache::Update(this, name, number);
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
|
||||
String* DescriptorArray::GetKey(int descriptor_number) {
|
||||
ASSERT(descriptor_number < number_of_descriptors());
|
||||
return String::cast(get(ToKeyIndex(descriptor_number)));
|
||||
|
@ -1330,7 +1330,7 @@ Object* JSObject::AddConstantFunctionProperty(String* name,
|
||||
if (attributes != NONE) {
|
||||
return function;
|
||||
}
|
||||
ConstTransitionDescriptor mark(name);
|
||||
ConstTransitionDescriptor mark(name, Map::cast(new_map));
|
||||
new_descriptors =
|
||||
old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
|
||||
if (new_descriptors->IsFailure()) {
|
||||
@ -1688,11 +1688,7 @@ bool JSObject::SetElementWithCallbackSetterInPrototypes(uint32_t index,
|
||||
|
||||
void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
|
||||
DescriptorArray* descriptors = map()->instance_descriptors();
|
||||
int number = DescriptorLookupCache::Lookup(descriptors, name);
|
||||
if (number == DescriptorLookupCache::kAbsent) {
|
||||
number = descriptors->Search(name);
|
||||
DescriptorLookupCache::Update(descriptors, name, number);
|
||||
}
|
||||
int number = descriptors->SearchWithCache(name);
|
||||
if (number != DescriptorArray::kNotFound) {
|
||||
result->DescriptorResult(this, descriptors->GetDetails(number), number);
|
||||
} else {
|
||||
@ -1889,10 +1885,25 @@ Object* JSObject::SetProperty(LookupResult* result,
|
||||
result->holder());
|
||||
case INTERCEPTOR:
|
||||
return SetPropertyWithInterceptor(name, value, attributes);
|
||||
case CONSTANT_TRANSITION:
|
||||
// Replace with a MAP_TRANSITION to a new map with a FIELD, even
|
||||
// if the value is a function.
|
||||
case CONSTANT_TRANSITION: {
|
||||
// If the same constant function is being added we can simply
|
||||
// transition to the target map.
|
||||
Map* target_map = result->GetTransitionMap();
|
||||
DescriptorArray* target_descriptors = target_map->instance_descriptors();
|
||||
int number = target_descriptors->SearchWithCache(name);
|
||||
ASSERT(number != DescriptorArray::kNotFound);
|
||||
ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
|
||||
JSFunction* function =
|
||||
JSFunction::cast(target_descriptors->GetValue(number));
|
||||
ASSERT(!Heap::InNewSpace(function));
|
||||
if (value == function) {
|
||||
set_map(target_map);
|
||||
return value;
|
||||
}
|
||||
// Otherwise, replace with a MAP_TRANSITION to a new map with a
|
||||
// FIELD, even if the value is a constant function.
|
||||
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
|
||||
}
|
||||
case NULL_DESCRIPTOR:
|
||||
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
|
||||
default:
|
||||
@ -4936,7 +4947,8 @@ void String::PrintOn(FILE* file) {
|
||||
void Map::CreateBackPointers() {
|
||||
DescriptorArray* descriptors = instance_descriptors();
|
||||
for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
|
||||
if (descriptors->GetType(i) == MAP_TRANSITION) {
|
||||
if (descriptors->GetType(i) == MAP_TRANSITION ||
|
||||
descriptors->GetType(i) == CONSTANT_TRANSITION) {
|
||||
// Get target.
|
||||
Map* target = Map::cast(descriptors->GetValue(i));
|
||||
#ifdef DEBUG
|
||||
@ -4977,7 +4989,8 @@ void Map::ClearNonLiveTransitions(Object* real_prototype) {
|
||||
// map is not reached again by following a back pointer from a
|
||||
// non-live object.
|
||||
PropertyDetails details(Smi::cast(contents->get(i + 1)));
|
||||
if (details.type() == MAP_TRANSITION) {
|
||||
if (details.type() == MAP_TRANSITION ||
|
||||
details.type() == CONSTANT_TRANSITION) {
|
||||
Map* target = reinterpret_cast<Map*>(contents->get(i));
|
||||
ASSERT(target->IsHeapObject());
|
||||
if (!target->IsMarked()) {
|
||||
|
@ -1865,6 +1865,10 @@ class DescriptorArray: public FixedArray {
|
||||
// Search the instance descriptors for given name.
|
||||
inline int Search(String* name);
|
||||
|
||||
// As the above, but uses DescriptorLookupCache and updates it when
|
||||
// necessary.
|
||||
inline int SearchWithCache(String* name);
|
||||
|
||||
// Tells whether the name is present int the array.
|
||||
bool Contains(String* name) { return kNotFound != Search(name); }
|
||||
|
||||
|
@ -115,8 +115,8 @@ class MapTransitionDescriptor: public Descriptor {
|
||||
// the same CONSTANT_FUNCTION field.
|
||||
class ConstTransitionDescriptor: public Descriptor {
|
||||
public:
|
||||
explicit ConstTransitionDescriptor(String* key)
|
||||
: Descriptor(key, Smi::FromInt(0), NONE, CONSTANT_TRANSITION) { }
|
||||
explicit ConstTransitionDescriptor(String* key, Map* map)
|
||||
: Descriptor(key, map, NONE, CONSTANT_TRANSITION) { }
|
||||
};
|
||||
|
||||
|
||||
@ -260,7 +260,7 @@ class LookupResult BASE_EMBEDDED {
|
||||
|
||||
Map* GetTransitionMap() {
|
||||
ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
|
||||
ASSERT(type() == MAP_TRANSITION);
|
||||
ASSERT(type() == MAP_TRANSITION || type() == CONSTANT_TRANSITION);
|
||||
return Map::cast(GetValue());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user