- Specialized jscre on the type of the string involved.

- Specialized jscre on the type of the string involved.


git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@476 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
christian.plesner.hansen@gmail.com 2008-10-09 10:30:33 +00:00
parent 4f7b6654d4
commit a7230abb92
8 changed files with 1077 additions and 946 deletions

View File

@ -223,7 +223,6 @@ void Heap::ReportStatisticsAfterGC() {
void Heap::GarbageCollectionPrologue() {
RegExpImpl::NewSpaceCollectionPrologue();
gc_count_++;
#ifdef DEBUG
ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
@ -424,7 +423,6 @@ void Heap::MarkCompact(GCTracer* tracer) {
void Heap::MarkCompactPrologue() {
CompilationCache::MarkCompactPrologue();
RegExpImpl::OldSpaceCollectionPrologue();
Top::MarkCompactPrologue();
ThreadManager::MarkCompactPrologue();
}

View File

@ -65,27 +65,6 @@ static void JSREFree(void* p) {
}
String* RegExpImpl::last_ascii_string_ = NULL;
String* RegExpImpl::two_byte_cached_string_ = NULL;
void RegExpImpl::NewSpaceCollectionPrologue() {
// The two byte string is always in the old space. The Ascii string may be
// in either place. If it is in the old space we don't need to do anything.
if (Heap::InNewSpace(last_ascii_string_)) {
// Invalidate the cache.
last_ascii_string_ = NULL;
two_byte_cached_string_ = NULL;
}
}
void RegExpImpl::OldSpaceCollectionPrologue() {
last_ascii_string_ = NULL;
two_byte_cached_string_ = NULL;
}
Handle<Object> RegExpImpl::CreateRegExpLiteral(Handle<JSFunction> constructor,
Handle<String> pattern,
Handle<String> flags,
@ -102,47 +81,6 @@ Handle<Object> RegExpImpl::CreateRegExpLiteral(Handle<JSFunction> constructor,
}
// Converts a source string to a 16 bit flat string or a SlicedString containing
// a 16 bit flat string).
Handle<String> RegExpImpl::CachedStringToTwoByte(Handle<String> subject) {
if (*subject == last_ascii_string_) {
ASSERT(two_byte_cached_string_ != NULL);
return Handle<String>(String::cast(two_byte_cached_string_));
}
Handle<String> two_byte_string = StringToTwoByte(subject);
last_ascii_string_ = *subject;
two_byte_cached_string_ = *two_byte_string;
return two_byte_string;
}
// Converts a source string to a 16 bit flat string or a SlicedString containing
// a 16 bit flat string).
Handle<String> RegExpImpl::StringToTwoByte(Handle<String> pattern) {
if (!pattern->IsFlat()) {
FlattenString(pattern);
}
Handle<String> flat_string(pattern->IsConsString() ?
String::cast(ConsString::cast(*pattern)->first()) :
*pattern);
ASSERT(!flat_string->IsConsString());
ASSERT(flat_string->IsSeqString() || flat_string->IsSlicedString() ||
flat_string->IsExternalString());
if (!flat_string->IsAsciiRepresentation()) {
return flat_string;
}
Handle<String> two_byte_string =
Factory::NewRawTwoByteString(flat_string->length(), TENURED);
static StringInputBuffer convert_to_two_byte_buffer;
convert_to_two_byte_buffer.Reset(*flat_string);
for (int i = 0; convert_to_two_byte_buffer.has_more(); i++) {
two_byte_string->Set(i, convert_to_two_byte_buffer.GetNext());
}
return two_byte_string;
}
unibrow::Predicate<unibrow::RegExpSpecialChar, 128> is_reg_exp_special_char;
@ -189,7 +127,14 @@ Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp,
Handle<String> subject) {
switch (regexp->type_tag()) {
case JSRegExp::JSCRE:
return JsreExecGlobal(regexp, subject);
FlattenString(subject);
if (subject->IsAsciiRepresentation()) {
Vector<const char> contents = subject->ToAsciiVector();
return JsreExecGlobal(regexp, subject, contents);
} else {
Vector<const uc16> contents = subject->ToUC16Vector();
return JsreExecGlobal(regexp, subject, contents);
}
case JSRegExp::ATOM:
return AtomExecGlobal(regexp, subject);
default:
@ -268,16 +213,34 @@ Handle<Object> RegExpImpl::JsreCompile(Handle<JSRegExp> re,
if (flags->Get(i) == 'm') multiline_option = JSRegExpMultiline;
}
Handle<String> two_byte_pattern = StringToTwoByte(pattern);
unsigned number_of_captures;
const char* error_message = NULL;
malloc_failure = Failure::Exception();
JscreRegExp* code = jsRegExpCompile(two_byte_pattern->GetTwoByteData(),
pattern->length(), case_option,
multiline_option, &number_of_captures,
&error_message, &JSREMalloc, &JSREFree);
JscreRegExp* code;
FlattenString(pattern);
if (pattern->IsAsciiRepresentation()) {
Vector<const char> contents = pattern->ToAsciiVector();
code = jsRegExpCompile(contents.start(),
contents.length(),
case_option,
multiline_option,
&number_of_captures,
&error_message,
&JSREMalloc,
&JSREFree);
} else {
Vector<const uc16> contents = pattern->ToUC16Vector();
code = jsRegExpCompile(contents.start(),
contents.length(),
case_option,
multiline_option,
&number_of_captures,
&error_message,
&JSREMalloc,
&JSREFree);
}
if (code == NULL && malloc_failure->IsRetryAfterGC()) {
// Performs a GC, then retries.
@ -287,10 +250,29 @@ Handle<Object> RegExpImpl::JsreCompile(Handle<JSRegExp> re,
V8::FatalProcessOutOfMemory("RegExpImpl::JsreCompile");
}
malloc_failure = Failure::Exception();
code = jsRegExpCompile(two_byte_pattern->GetTwoByteData(),
pattern->length(), case_option,
multiline_option, &number_of_captures,
&error_message, &JSREMalloc, &JSREFree);
if (pattern->IsAsciiRepresentation()) {
Vector<const char> contents = pattern->ToAsciiVector();
code = jsRegExpCompile(contents.start(),
contents.length(),
case_option,
multiline_option,
&number_of_captures,
&error_message,
&JSREMalloc,
&JSREFree);
} else {
Vector<const uc16> contents = pattern->ToUC16Vector();
code = jsRegExpCompile(contents.start(),
contents.length(),
case_option,
multiline_option,
&number_of_captures,
&error_message,
&JSREMalloc,
&JSREFree);
}
if (code == NULL && malloc_failure->IsRetryAfterGC()) {
// TODO(1181417): Fix this.
V8::FatalProcessOutOfMemory("RegExpImpl::JsreCompile");
@ -299,10 +281,8 @@ Handle<Object> RegExpImpl::JsreCompile(Handle<JSRegExp> re,
if (error_message != NULL) {
// Throw an exception.
SmartPointer<char> char_pattern =
two_byte_pattern->ToCString(DISALLOW_NULLS);
Handle<JSArray> array = Factory::NewJSArray(2);
SetElement(array, 0, Factory::NewStringFromUtf8(CStrVector(*char_pattern)));
SetElement(array, 0, pattern);
SetElement(array, 1, Factory::NewStringFromUtf8(CStrVector(error_message)));
Handle<Object> regexp_err =
Factory::NewSyntaxError("malformed_regexp", array);
@ -325,11 +305,12 @@ Handle<Object> RegExpImpl::JsreCompile(Handle<JSRegExp> re,
}
template <typename T>
Handle<Object> RegExpImpl::JsreExecOnce(Handle<JSRegExp> regexp,
int num_captures,
Handle<String> subject,
int previous_index,
const uc16* two_byte_subject,
Vector<const T> contents,
int* offsets_vector,
int offsets_vector_length) {
int rc;
@ -341,12 +322,12 @@ Handle<Object> RegExpImpl::JsreExecOnce(Handle<JSRegExp> regexp,
LOG(RegExpExecEvent(regexp, previous_index, subject));
rc = jsRegExpExecute(js_regexp,
two_byte_subject,
subject->length(),
previous_index,
offsets_vector,
offsets_vector_length);
rc = jsRegExpExecute<T>(js_regexp,
contents.start(),
contents.length(),
previous_index,
offsets_vector,
offsets_vector_length);
}
// The KJS JavaScript engine returns null (ie, a failed match) when
@ -428,19 +409,29 @@ Handle<Object> RegExpImpl::JsreExec(Handle<JSRegExp> regexp,
int previous_index = static_cast<int>(DoubleToInteger(index->Number()));
Handle<String> subject16 = CachedStringToTwoByte(subject);
Handle<Object> result(JsreExecOnce(regexp, num_captures, subject,
previous_index,
subject16->GetTwoByteData(),
offsets.vector(), offsets.length()));
return result;
FlattenString(subject);
if (subject->IsAsciiRepresentation()) {
Vector<const char> contents = subject->ToAsciiVector();
Handle<Object> result(JsreExecOnce(regexp, num_captures, subject,
previous_index,
contents,
offsets.vector(), offsets.length()));
return result;
} else {
Vector<const uc16> contents = subject->ToUC16Vector();
Handle<Object> result(JsreExecOnce(regexp, num_captures, subject,
previous_index,
contents,
offsets.vector(), offsets.length()));
return result;
}
}
template <typename T>
Handle<Object> RegExpImpl::JsreExecGlobal(Handle<JSRegExp> regexp,
Handle<String> subject) {
Handle<String> subject,
Vector<const T> contents) {
// Prepare space for the return values.
int num_captures = JsreCapture(regexp);
@ -452,17 +443,19 @@ Handle<Object> RegExpImpl::JsreExecGlobal(Handle<JSRegExp> regexp,
int i = 0;
Handle<Object> matches;
Handle<String> subject16 = CachedStringToTwoByte(subject);
do {
if (previous_index > subject->length() || previous_index < 0) {
// Per ECMA-262 15.10.6.2, if the previous index is greater than the
// string length, there is no match.
matches = Factory::null_value();
} else {
matches = JsreExecOnce(regexp, num_captures, subject, previous_index,
subject16->GetTwoByteData(),
offsets.vector(), offsets.length());
matches = JsreExecOnce<T>(regexp,
num_captures,
subject,
previous_index,
contents,
offsets.vector(),
offsets.length());
if (matches->IsJSArray()) {
SetElement(result, i, matches);

View File

@ -79,32 +79,24 @@ class RegExpImpl {
Handle<String> subject,
Handle<Object> index);
template <typename T>
static Handle<Object> JsreExecGlobal(Handle<JSRegExp> regexp,
Handle<String> subject);
static void NewSpaceCollectionPrologue();
static void OldSpaceCollectionPrologue();
Handle<String> subject,
Vector<const T> contents);
private:
// Converts a source string to a 16 bit flat string. The string
// will be either sequential or it will be a SlicedString backed
// by a flat string.
static Handle<String> StringToTwoByte(Handle<String> pattern);
static Handle<String> CachedStringToTwoByte(Handle<String> pattern);
static String* last_ascii_string_;
static String* two_byte_cached_string_;
// Returns the caputure from the re.
static int JsreCapture(Handle<JSRegExp> re);
static ByteArray* JsreInternal(Handle<JSRegExp> re);
// Call jsRegExpExecute once
template <typename T>
static Handle<Object> JsreExecOnce(Handle<JSRegExp> regexp,
int num_captures,
Handle<String> subject,
int previous_index,
const uc16* utf8_subject,
Vector<const T> contents,
int* ovector,
int ovector_length);

View File

@ -964,7 +964,21 @@ Object* JSObject::AddFastProperty(String* name,
return AddSlowProperty(name, value, attributes);
}
// Replace a CONSTANT_TRANSITION flag with a transition.
// Do this by removing it, and the standard code for adding a map transition
// will then run.
DescriptorArray* old_descriptors = map()->instance_descriptors();
int old_name_index = old_descriptors->Search(name);
bool constant_transition = false; // Only used in assertions.
if (old_name_index != DescriptorArray::kNotFound && CONSTANT_TRANSITION ==
PropertyDetails(old_descriptors->GetDetails(old_name_index)).type()) {
constant_transition = true;
Object* r = old_descriptors->CopyRemove(name);
if (r->IsFailure()) return r;
old_descriptors = DescriptorArray::cast(r);
old_name_index = DescriptorArray::kNotFound;
}
// Compute the new index for new field.
int index = map()->NextFreePropertyIndex();
@ -979,43 +993,64 @@ Object* JSObject::AddFastProperty(String* name,
bool allow_map_transition =
!old_descriptors->Contains(name) &&
(Top::context()->global_context()->object_function()->map() != map());
ASSERT(allow_map_transition || !constant_transition);
ASSERT(index < properties()->length() ||
map()->unused_property_fields() == 0);
// Allocate a new map for the object.
Object* r = map()->Copy();
if (r->IsFailure()) return r;
Map* new_map = Map::cast(r);
if (allow_map_transition) {
// Allocate new instance descriptors for the old map with map transition.
MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
if (map()->unused_property_fields() > 0) {
ASSERT(index < properties()->length());
// Allocate a new map for the object.
Object* r = map()->Copy();
if (r->IsFailure()) return r;
old_descriptors = DescriptorArray::cast(r);
}
Map* new_map = Map::cast(r);
if (allow_map_transition) {
// Allocate new instance descriptors for the old map with map transition.
MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
if (r->IsFailure()) return r;
old_descriptors = DescriptorArray::cast(r);
}
// We have now allocated all the necessary objects.
// All the changes can be applied at once, so they are atomic.
map()->set_instance_descriptors(old_descriptors);
new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
set_map(new_map);
properties()->set(index, value);
} else {
ASSERT(map()->unused_property_fields() == 0);
if (map()->unused_property_fields() == 0) {
if (properties()->length() > kMaxFastProperties) {
Object* obj = NormalizeProperties();
if (obj->IsFailure()) return obj;
return AddSlowProperty(name, value, attributes);
}
static const int kExtraFields = 3;
// Make room for the new value
Object* values =
properties()->CopySize(properties()->length() + kFieldsAdded);
properties()->CopySize(properties()->length() + kExtraFields);
if (values->IsFailure()) return values;
FixedArray::cast(values)->set(index, value);
// Allocate a new map for the object.
Object* r = map()->Copy();
if (r->IsFailure()) return r;
Map* new_map = Map::cast(r);
if (allow_map_transition) {
MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
// Allocate new instance descriptors for the old map with map transition.
Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
if (r->IsFailure()) return r;
old_descriptors = DescriptorArray::cast(r);
}
// We have now allocated all the necessary objects.
// All changes can be done at once, atomically.
map()->set_instance_descriptors(old_descriptors);
new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
new_map->set_unused_property_fields(kExtraFields - 1);
set_map(new_map);
set_properties(FixedArray::cast(values));
new_map->set_unused_property_fields(kFieldsAdded - 1);
} else {
new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
}
// We have now allocated all the necessary objects.
// All the changes can be applied at once, so they are atomic.
map()->set_instance_descriptors(old_descriptors);
new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
set_map(new_map);
properties()->set(index, value);
return value;
}
@ -1069,6 +1104,74 @@ Object* JSObject::AddConstantFunctionProperty(String* name,
}
Object* JSObject::ReplaceConstantFunctionProperty(String* name,
Object* value) {
// There are two situations to handle here:
// 1: Replace a constant function with another function.
// 2: Replace a constant function with an object.
if (value->IsJSFunction()) {
JSFunction* function = JSFunction::cast(value);
Object* new_map = map()->CopyDropTransitions();
if (new_map->IsFailure()) return new_map;
set_map(Map::cast(new_map));
// Replace the function entry
int index = map()->instance_descriptors()->Search(name);
ASSERT(index != DescriptorArray::kNotFound);
map()->instance_descriptors()->ReplaceConstantFunction(index, function);
} else {
// Allocate new instance descriptors with updated property index.
int index = map()->NextFreePropertyIndex();
Object* new_descriptors =
map()->instance_descriptors()->CopyReplace(name, index, NONE);
if (new_descriptors->IsFailure()) return new_descriptors;
if (map()->unused_property_fields() > 0) {
ASSERT(index < properties()->length());
// Allocate a new map for the object.
Object* new_map = map()->Copy();
if (new_map->IsFailure()) return new_map;
Map::cast(new_map)->
set_instance_descriptors(DescriptorArray::cast(new_descriptors));
Map::cast(new_map)->
set_unused_property_fields(map()->unused_property_fields()-1);
set_map(Map::cast(new_map));
properties()->set(index, value);
} else {
ASSERT(map()->unused_property_fields() == 0);
static const int kFastNofProperties = 20;
if (properties()->length() > kFastNofProperties) {
Object* obj = NormalizeProperties();
if (obj->IsFailure()) return obj;
return SetProperty(name, value, NONE);
}
static const int kExtraFields = 5;
// Make room for the more properties.
Object* values =
properties()->CopySize(properties()->length() + kExtraFields);
if (values->IsFailure()) return values;
FixedArray::cast(values)->set(index, value);
// Allocate a new map for the object.
Object* new_map = map()->Copy();
if (new_map->IsFailure()) return new_map;
Map::cast(new_map)->
set_instance_descriptors(DescriptorArray::cast(new_descriptors));
Map::cast(new_map)->
set_unused_property_fields(kExtraFields - 1);
set_map(Map::cast(new_map));
set_properties(FixedArray::cast(values));
}
}
return value;
}
// Add property in slow mode
Object* JSObject::AddSlowProperty(String* name,
Object* value,
@ -1120,103 +1223,6 @@ Object* JSObject::SetPropertyPostInterceptor(String* name,
}
Object* JSObject::ReplaceSlowProperty(String* name,
Object* value,
PropertyAttributes attributes) {
Dictionary* dictionary = property_dictionary();
PropertyDetails old_details =
dictionary->DetailsAt(dictionary->FindStringEntry(name));
int new_index = old_details.index();
if (old_details.IsTransition()) new_index = 0;
PropertyDetails new_details(attributes, NORMAL, old_details.index());
Object* result =
property_dictionary()->SetOrAddStringEntry(name, value, new_details);
if (result->IsFailure()) return result;
if (property_dictionary() != result) {
set_properties(Dictionary::cast(result));
}
return value;
}
Object* JSObject::ConvertDescriptorToFieldAndMapTransition(
String* name,
Object* new_value,
PropertyAttributes attributes) {
Map* old_map = map();
Object* result = ConvertDescriptorToField(name, new_value, attributes);
if (result->IsFailure()) return result;
// If we get to this point we have succeeded - do not return failure
// after this point. Later stuff is optional.
if (!HasFastProperties()) {
return result;
}
// Do not add transitions to the map of "new Object()".
if (map() == Top::context()->global_context()->object_function()->map()) {
return result;
}
MapTransitionDescriptor transition(name,
map(),
attributes);
Object* new_descriptors =
old_map->instance_descriptors()->
CopyInsert(&transition, KEEP_TRANSITIONS);
if (new_descriptors->IsFailure()) return result; // Yes, return _result_.
old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
return result;
}
Object* JSObject::ConvertDescriptorToField(String* name,
Object* new_value,
PropertyAttributes attributes) {
if (map()->unused_property_fields() == 0 &&
properties()->length() > kMaxFastProperties) {
Object* obj = NormalizeProperties();
if (obj->IsFailure()) return obj;
return ReplaceSlowProperty(name, new_value, attributes);
}
int index = map()->NextFreePropertyIndex();
FieldDescriptor new_field(name, index, attributes);
// Make a new DescriptorArray replacing an entry with FieldDescriptor.
Object* descriptors_unchecked = map()->instance_descriptors()->
CopyInsert(&new_field, REMOVE_TRANSITIONS);
if (descriptors_unchecked->IsFailure()) return descriptors_unchecked;
DescriptorArray* new_descriptors =
DescriptorArray::cast(descriptors_unchecked);
// Make a new map for the object.
Object* new_map_unchecked = map()->Copy();
if (new_map_unchecked->IsFailure()) return new_map_unchecked;
Map* new_map = Map::cast(new_map_unchecked);
new_map->set_instance_descriptors(new_descriptors);
// Make new properties array if necessary.
FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
int new_unused_property_fields = map()->unused_property_fields() - 1;
if (map()->unused_property_fields() == 0) {
new_unused_property_fields = kFieldsAdded - 1;
Object* new_properties_unchecked =
properties()->CopySize(properties()->length() + kFieldsAdded);
if (new_properties_unchecked->IsFailure()) return new_properties_unchecked;
new_properties = FixedArray::cast(new_properties_unchecked);
}
// Update pointers to commit changes.
// Object points to the new map.
new_map->set_unused_property_fields(new_unused_property_fields);
set_map(new_map);
if (new_properties) {
set_properties(FixedArray::cast(new_properties));
}
properties()->set(index, new_value);
return new_value;
}
Object* JSObject::SetPropertyWithInterceptor(String* name,
Object* value,
PropertyAttributes attributes) {
@ -1522,12 +1528,13 @@ Object* JSObject::SetProperty(LookupResult* result,
return AddFastPropertyUsingMap(result->GetTransitionMap(),
name,
value);
} else {
return AddFastProperty(name, value, attributes);
}
return ConvertDescriptorToField(name, value, attributes);
case CONSTANT_FUNCTION:
if (value == result->GetConstantFunction()) return value;
// Only replace the function if necessary.
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
return ReplaceConstantFunctionProperty(name, value);
case CALLBACKS:
return SetPropertyWithCallback(result->GetCallbackObject(),
name,
@ -1538,9 +1545,10 @@ Object* JSObject::SetProperty(LookupResult* result,
case CONSTANT_TRANSITION:
// Replace with a MAP_TRANSITION to a new map with a FIELD, even
// if the value is a function.
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
// AddProperty has been extended to do this, in this case.
return AddFastProperty(name, value, attributes);
case NULL_DESCRIPTOR:
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
UNREACHABLE();
default:
UNREACHABLE();
}
@ -1572,14 +1580,33 @@ Object* JSObject::IgnoreAttributesAndSetLocalProperty(
&& !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
return SetPropertyWithFailedAccessCheck(result, name, value);
}
// Check for accessor in prototype chain removed here in clone.
/*
REMOVED FROM CLONE
if (result->IsNotFound() || !result->IsProperty()) {
// We could not find a local property so let's check whether there is an
// accessor that wants to handle the property.
LookupResult accessor_result;
LookupCallbackSetterInPrototypes(name, &accessor_result);
if (accessor_result.IsValid()) {
return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
name,
value,
accessor_result.holder());
}
}
*/
if (result->IsNotFound()) {
return AddProperty(name, value, attributes);
}
if (!result->IsLoaded()) {
return SetLazyProperty(result, name, value, attributes);
}
// Check of IsReadOnly removed from here in clone.
/*
REMOVED FROM CLONE
if (result->IsReadOnly() && result->IsProperty()) return value;
*/
// This is a real property that is not read-only, or it is a
// transition or null descriptor and there are no setters in the prototypes.
switch (result->type()) {
case NORMAL:
property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
@ -1594,12 +1621,12 @@ Object* JSObject::IgnoreAttributesAndSetLocalProperty(
name,
value);
} else {
return ConvertDescriptorToField(name, value, attributes);
return AddFastProperty(name, value, attributes);
}
case CONSTANT_FUNCTION:
if (value == result->GetConstantFunction()) return value;
// Only replace the function if necessary.
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
return ReplaceConstantFunctionProperty(name, value);
case CALLBACKS:
return SetPropertyWithCallback(result->GetCallbackObject(),
name,
@ -1610,9 +1637,10 @@ Object* JSObject::IgnoreAttributesAndSetLocalProperty(
case CONSTANT_TRANSITION:
// Replace with a MAP_TRANSITION to a new map with a FIELD, even
// if the value is a function.
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
// AddProperty has been extended to do this, in this case.
return AddFastProperty(name, value, attributes);
case NULL_DESCRIPTOR:
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
UNREACHABLE();
default:
UNREACHABLE();
}
@ -2635,6 +2663,14 @@ void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
}
void DescriptorArray::ReplaceConstantFunction(int descriptor_number,
JSFunction* value) {
ASSERT(!Heap::InNewSpace(value));
FixedArray* content_array = GetContentArray();
fast_set(content_array, ToValueIndex(descriptor_number), value);
}
Object* DescriptorArray::CopyInsert(Descriptor* descriptor,
TransitionFlag transition_flag) {
// Transitions are only kept when inserting another transition.
@ -2735,6 +2771,69 @@ Object* DescriptorArray::CopyInsert(Descriptor* descriptor,
}
Object* DescriptorArray::CopyReplace(String* name,
int index,
PropertyAttributes attributes) {
// Allocate the new descriptor array.
Object* result = DescriptorArray::Allocate(number_of_descriptors());
if (result->IsFailure()) return result;
// Make sure only symbols are added to the instance descriptor.
if (!name->IsSymbol()) {
Object* result = Heap::LookupSymbol(name);
if (result->IsFailure()) return result;
name = String::cast(result);
}
DescriptorWriter w(DescriptorArray::cast(result));
for (DescriptorReader r(this); !r.eos(); r.advance()) {
if (r.Equals(name)) {
FieldDescriptor d(name, index, attributes);
d.SetEnumerationIndex(r.GetDetails().index());
w.Write(&d);
} else {
w.WriteFrom(&r);
}
}
// Copy the next enumeration index.
DescriptorArray::cast(result)->
SetNextEnumerationIndex(NextEnumerationIndex());
ASSERT(w.eos());
return result;
}
Object* DescriptorArray::CopyRemove(String* name) {
if (!name->IsSymbol()) {
Object* result = Heap::LookupSymbol(name);
if (result->IsFailure()) return result;
name = String::cast(result);
}
ASSERT(name->IsSymbol());
Object* result = Allocate(number_of_descriptors() - 1);
if (result->IsFailure()) return result;
DescriptorArray* new_descriptors = DescriptorArray::cast(result);
// Set the enumeration index in the descriptors and set the enumeration index
// in the result.
new_descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
// Write the old content and the descriptor information
DescriptorWriter w(new_descriptors);
DescriptorReader r(this);
while (!r.eos()) {
if (r.GetKey() != name) { // Both are symbols; object identity suffices.
w.WriteFrom(&r);
}
r.advance();
}
ASSERT(w.eos());
return new_descriptors;
}
Object* DescriptorArray::RemoveTransitions() {
// Remove all transitions. Return a copy of the array with all transitions
// removed, or a Failure object if the new array could not be allocated.

View File

@ -1303,26 +1303,9 @@ class JSObject: public HeapObject {
JSFunction* function,
PropertyAttributes attributes);
Object* ReplaceSlowProperty(String* name,
Object* value,
PropertyAttributes attributes);
// Converts a descriptor of any other type to a real field,
// backed by the properties array. Descriptors of visible
// types, such as CONSTANT_FUNCTION, keep their enumeration order.
// Converts the descriptor on the original object's map to a
// map transition, and the the new field is on the object's new map.
Object* ConvertDescriptorToFieldAndMapTransition(
String* name,
Object* new_value,
PropertyAttributes attributes);
// Converts a descriptor of any other type to a real field,
// backed by the properties array. Descriptors of visible
// types, such as CONSTANT_FUNCTION, keep their enumeration order.
Object* ConvertDescriptorToField(String* name,
Object* new_value,
PropertyAttributes attributes);
// Replace a constant function property on a fast-case object.
Object* ReplaceConstantFunctionProperty(String* name,
Object* value);
// Add a property to a fast-case object.
Object* AddFastProperty(String* name,
@ -1394,10 +1377,6 @@ class JSObject: public HeapObject {
static const uint32_t kMaxGap = 1024;
static const int kMaxFastElementsLength = 5000;
static const int kMaxFastProperties = 8;
// When extending the backing storage for property values, we increase
// its size by more than the 1 entry necessary, so sequentially adding fields
// to the same object requires fewer allocations and copies.
static const int kFieldsAdded = 3;
// Layout description.
static const int kPropertiesOffset = HeapObject::kHeaderSize;
@ -1583,6 +1562,7 @@ class DescriptorArray: public FixedArray {
inline void Get(int descriptor_number, Descriptor* desc);
inline void Set(int descriptor_number, Descriptor* desc);
void ReplaceConstantFunction(int descriptor_number, JSFunction* value);
// Copy the descriptor array, insert a new descriptor and optionally
// remove map transitions. If the descriptor is already present, it is
@ -1592,6 +1572,20 @@ class DescriptorArray: public FixedArray {
// a transition, they must not be removed. All null descriptors are removed.
Object* CopyInsert(Descriptor* descriptor, TransitionFlag transition_flag);
// Makes a copy of the descriptor array with the descriptor with key name
// removed. If name is the empty string, the descriptor array is copied.
// Transitions are removed if TransitionFlag is REMOVE_TRANSITIONS.
// All null descriptors are removed.
Object* CopyRemove(TransitionFlag remove_transitions, String* name);
// Copy the descriptor array, replace the property index and attributes
// of the named property, but preserve its enumeration index.
Object* CopyReplace(String* name, int index, PropertyAttributes attributes);
// Copy the descriptor array, removing the property index and attributes
// of the named property.
Object* CopyRemove(String* name);
// Remove all transitions. Return a copy of the array with all transitions
// removed, or a Failure object if the new array could not be allocated.
Object* RemoveTransitions();

View File

@ -66,13 +66,15 @@ const int JSRegExpErrorInternal = -4;
typedef void* malloc_t(size_t size);
typedef void free_t(void* address);
JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength,
template <typename Char>
JSRegExp* jsRegExpCompile(const Char* pattern, int patternLength,
JSRegExpIgnoreCaseOption, JSRegExpMultilineOption,
unsigned* numSubpatterns, const char** errorMessage,
malloc_t* allocate_function, free_t* free_function);
template <typename Char>
int jsRegExpExecute(const JSRegExp*,
const UChar* subject, int subjectLength, int startOffset,
const Char* subject, int subjectLength, int startOffset,
int* offsetsVector, int offsetsVectorLength);
void jsRegExpFree(JSRegExp*);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff