Reverted the changes to jscre because the arm cross-compiler dies with

an internal error when compiling templateified jscre.  We really need
to update that damn arm compiler.


git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@478 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 89ac41af
......@@ -223,6 +223,7 @@ void Heap::ReportStatisticsAfterGC() {
void Heap::GarbageCollectionPrologue() {
RegExpImpl::NewSpaceCollectionPrologue();
gc_count_++;
#ifdef DEBUG
ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
......@@ -423,6 +424,7 @@ void Heap::MarkCompact(GCTracer* tracer) {
void Heap::MarkCompactPrologue() {
CompilationCache::MarkCompactPrologue();
RegExpImpl::OldSpaceCollectionPrologue();
Top::MarkCompactPrologue();
ThreadManager::MarkCompactPrologue();
}
......
......@@ -65,6 +65,27 @@ 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,
......@@ -81,6 +102,47 @@ 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;
......@@ -127,14 +189,7 @@ Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp,
Handle<String> subject) {
switch (regexp->type_tag()) {
case JSRegExp::JSCRE:
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);
}
return JsreExecGlobal(regexp, subject);
case JSRegExp::ATOM:
return AtomExecGlobal(regexp, subject);
default:
......@@ -213,6 +268,8 @@ 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;
......@@ -222,31 +279,14 @@ Handle<Object> RegExpImpl::JsreCompile(Handle<JSRegExp> re,
bool first_time = true;
while (true) {
first_time = false;
malloc_failure = Failure::Exception();
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);
}
code = jsRegExpCompile(two_byte_pattern->GetTwoByteData(),
pattern->length(), case_option,
multiline_option, &number_of_captures,
&error_message, &JSREMalloc, &JSREFree);
if (code == NULL) {
if (first_time && malloc_failure->IsRetryAfterGC()) {
first_time = false;
if (!Heap::CollectGarbage(malloc_failure->requested(),
malloc_failure->allocation_space())) {
// TODO(1181417): Fix this.
......@@ -287,12 +327,11 @@ 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,
Vector<const T> contents,
const uc16* two_byte_subject,
int* offsets_vector,
int offsets_vector_length) {
int rc;
......@@ -304,9 +343,9 @@ Handle<Object> RegExpImpl::JsreExecOnce(Handle<JSRegExp> regexp,
LOG(RegExpExecEvent(regexp, previous_index, subject));
rc = jsRegExpExecute<T>(js_regexp,
contents.start(),
contents.length(),
rc = jsRegExpExecute(js_regexp,
two_byte_subject,
subject->length(),
previous_index,
offsets_vector,
offsets_vector_length);
......@@ -391,29 +430,19 @@ Handle<Object> RegExpImpl::JsreExec(Handle<JSRegExp> regexp,
int previous_index = static_cast<int>(DoubleToInteger(index->Number()));
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<String> subject16 = CachedStringToTwoByte(subject);
Handle<Object> result(JsreExecOnce(regexp, num_captures, subject,
previous_index,
contents,
subject16->GetTwoByteData(),
offsets.vector(), offsets.length()));
return result;
}
}
template <typename T>
Handle<Object> RegExpImpl::JsreExecGlobal(Handle<JSRegExp> regexp,
Handle<String> subject,
Vector<const T> contents) {
Handle<String> subject) {
// Prepare space for the return values.
int num_captures = JsreCapture(regexp);
......@@ -425,19 +454,17 @@ 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<T>(regexp,
num_captures,
subject,
previous_index,
contents,
offsets.vector(),
offsets.length());
matches = JsreExecOnce(regexp, num_captures, subject, previous_index,
subject16->GetTwoByteData(),
offsets.vector(), offsets.length());
if (matches->IsJSArray()) {
SetElement(result, i, matches);
......
......@@ -79,24 +79,32 @@ class RegExpImpl {
Handle<String> subject,
Handle<Object> index);
template <typename T>
static Handle<Object> JsreExecGlobal(Handle<JSRegExp> regexp,
Handle<String> subject,
Vector<const T> contents);
Handle<String> subject);
static void NewSpaceCollectionPrologue();
static void OldSpaceCollectionPrologue();
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,
Vector<const T> contents,
const uc16* utf8_subject,
int* ovector,
int ovector_length);
......
......@@ -964,21 +964,7 @@ 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();
......@@ -993,10 +979,9 @@ 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);
if (map()->unused_property_fields() > 0) {
ASSERT(index < properties()->length());
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;
......@@ -1008,49 +993,29 @@ Object* JSObject::AddFastProperty(String* name,
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() + kExtraFields);
properties()->CopySize(properties()->length() + kFieldsAdded);
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);
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 changes can be done at once, atomically.
// 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(kExtraFields - 1);
set_map(new_map);
set_properties(FixedArray::cast(values));
}
properties()->set(index, value);
return value;
}
......@@ -1104,74 +1069,6 @@ 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,
......@@ -1223,6 +1120,103 @@ 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) {
......@@ -1528,13 +1522,12 @@ 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 ReplaceConstantFunctionProperty(name, value);
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
case CALLBACKS:
return SetPropertyWithCallback(result->GetCallbackObject(),
name,
......@@ -1545,10 +1538,9 @@ 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.
// AddProperty has been extended to do this, in this case.
return AddFastProperty(name, value, attributes);
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
case NULL_DESCRIPTOR:
UNREACHABLE();
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
default:
UNREACHABLE();
}
......@@ -1580,33 +1572,14 @@ Object* JSObject::IgnoreAttributesAndSetLocalProperty(
&& !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
return SetPropertyWithFailedAccessCheck(result, name, value);
}
/*
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());
}
}
*/
// Check for accessor in prototype chain removed here in clone.
if (result->IsNotFound()) {
return AddProperty(name, value, attributes);
}
if (!result->IsLoaded()) {
return SetLazyProperty(result, name, value, attributes);
}
/*
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.
// Check of IsReadOnly removed from here in clone.
switch (result->type()) {
case NORMAL:
property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
......@@ -1621,12 +1594,12 @@ Object* JSObject::IgnoreAttributesAndSetLocalProperty(
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 ReplaceConstantFunctionProperty(name, value);
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
case CALLBACKS:
return SetPropertyWithCallback(result->GetCallbackObject(),
name,
......@@ -1637,10 +1610,9 @@ 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.
// AddProperty has been extended to do this, in this case.
return AddFastProperty(name, value, attributes);
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
case NULL_DESCRIPTOR:
UNREACHABLE();
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
default:
UNREACHABLE();
}
......@@ -2663,14 +2635,6 @@ 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.
......@@ -2771,69 +2735,6 @@ 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.
......
......@@ -1304,9 +1304,26 @@ class JSObject: public HeapObject {
JSFunction* function,
PropertyAttributes attributes);
// Replace a constant function property on a fast-case object.
Object* ReplaceConstantFunctionProperty(String* name,
Object* value);
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);
// Add a property to a fast-case object.
Object* AddFastProperty(String* name,
......@@ -1378,6 +1395,10 @@ 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;
......@@ -1563,7 +1584,6 @@ 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
......@@ -1573,20 +1593,6 @@ 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();
......
......@@ -66,15 +66,13 @@ const int JSRegExpErrorInternal = -4;
typedef void* malloc_t(size_t size);
typedef void free_t(void* address);
template <typename Char>
JSRegExp* jsRegExpCompile(const Char* pattern, int patternLength,
JSRegExp* jsRegExpCompile(const UChar* 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 Char* subject, int subjectLength, int startOffset,
const UChar* subject, int subjectLength, int startOffset,
int* offsetsVector, int offsetsVectorLength);
void jsRegExpFree(JSRegExp*);
......
......@@ -147,8 +147,7 @@ struct CompileData {
/* Definitions to allow mutual recursion */
template <typename Char>
static bool compileBracket(int, int*, unsigned char**, const Char**, const Char*, ErrorCode*, int, int*, int*, CompileData&);
static bool compileBracket(int, int*, unsigned char**, const UChar**, const UChar*, ErrorCode*, int, int*, int*, CompileData&);
static bool bracketIsAnchored(const unsigned char* code);
static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap);
static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert);
......@@ -175,10 +174,9 @@ Returns: zero or positive => a data character
on error, errorptr is set
*/
template <typename Char>
static int checkEscape(const Char** ptrptr, const Char* patternEnd, ErrorCode* errorcodeptr, int bracount, bool isclass)
static int checkEscape(const UChar** ptrptr, const UChar* patternEnd, ErrorCode* errorcodeptr, int bracount, bool isclass)
{
const Char* ptr = *ptrptr + 1;
const UChar* ptr = *ptrptr + 1;
/* If backslash is at the end of the pattern, it's an error. */
if (ptr == patternEnd) {
......@@ -221,7 +219,7 @@ static int checkEscape(const Char** ptrptr, const Char* patternEnd, ErrorCode* e
or when we overflow 0-255, whichever comes first. */
if (!isclass) {
const Char* oldptr = ptr;
const UChar* oldptr = ptr;
c -= '0';
while ((ptr + 1 < patternEnd) && isASCIIDigit(ptr[1]) && c <= bracount)
c = c * 10 + *(++ptr) - '0';
......@@ -325,8 +323,7 @@ Arguments:
Returns: true or false
*/
template <typename Char>
static bool isCountedRepeat(const Char* p, const Char* patternEnd)
static bool isCountedRepeat(const UChar* p, const UChar* patternEnd)
{
if (p >= patternEnd || !isASCIIDigit(*p))
return false;
......@@ -369,8 +366,7 @@ Returns: pointer to '}' on success;
current ptr on error, with errorcodeptr set non-zero
*/
template <typename Char>
static const Char* readRepeatCounts(const Char* p, int* minp, int* maxp, ErrorCode* errorcodeptr)
static const UChar* readRepeatCounts(const UChar* p, int* minp, int* maxp, ErrorCode* errorcodeptr)
{
int min = 0;
int max = -1;
......@@ -549,16 +545,14 @@ Returns: true on success
false, with *errorcodeptr set non-zero on error
*/
template <typename Char>
static inline bool safelyCheckNextChar(const Char* ptr, const Char* patternEnd, char expected)
static inline bool safelyCheckNextChar(const UChar* ptr, const UChar* patternEnd, UChar expected)
{
return ((ptr + 1 < patternEnd) && ptr[1] == expected);
}
template <typename Char>
static bool
compileBranch(int options, int* brackets, unsigned char** codeptr,
const Char** ptrptr, const Char* patternEnd, ErrorCode* errorcodeptr, int *firstbyteptr,
const UChar** ptrptr, const UChar* patternEnd, ErrorCode* errorcodeptr, int *firstbyteptr,
int* reqbyteptr, CompileData& cd)
{
int repeat_type, op_type;
......@@ -569,8 +563,8 @@ compileBranch(int options, int* brackets, unsigned char** codeptr,
unsigned char* code = *codeptr;
unsigned char* tempcode;
bool groupsetfirstbyte = false;
const Char* ptr = *ptrptr;
const Char* tempptr;
const UChar* ptr = *ptrptr;
const UChar* tempptr;
unsigned char* previous = NULL;
unsigned char classbits[32];
......@@ -800,7 +794,7 @@ compileBranch(int options, int* brackets, unsigned char** codeptr,
in such circumstances. */
if (d == '\\') {
const Char* oldptr = ptr;
const UChar* oldptr = ptr;
d = checkEscape(&ptr, patternEnd, errorcodeptr, cd.numCapturingBrackets, true);
/* \X is literal X; any other special means the '-' was literal */
......@@ -1709,13 +1703,12 @@ Argument:
Returns: true on success
*/
template <typename Char>
static bool
compileBracket(int options, int* brackets, unsigned char** codeptr,
const Char** ptrptr, const Char* patternEnd, ErrorCode* errorcodeptr, int skipbytes,
const UChar** ptrptr, const UChar* patternEnd, ErrorCode* errorcodeptr, int skipbytes,
int* firstbyteptr, int* reqbyteptr, CompileData& cd)
{
const Char* ptr = *ptrptr;
const UChar* ptr = *ptrptr;
unsigned char* code = *codeptr;
unsigned char* last_branch = code;
unsigned char* start_bracket = code;
......@@ -2002,8 +1995,7 @@ static inline int multiplyWithOverflowCheck(int a, int b)
return a * b;
}
template <typename Char>
static int calculateCompiledPatternLength(const Char* pattern, int patternLength, JSRegExpIgnoreCaseOption ignoreCase,
static int calculateCompiledPatternLength(const UChar* pattern, int patternLength, JSRegExpIgnoreCaseOption ignoreCase,
CompileData& cd, ErrorCode& errorcode)
{
/* Make a pass over the pattern to compute the
......@@ -2023,8 +2015,8 @@ static int calculateCompiledPatternLength(const Char* pattern, int patternLength
unsigned char bralenstack[BRASTACK_SIZE];
int bracount = 0;
const Char* ptr = (const Char*)(pattern - 1);
const Char* patternEnd = (const Char*)(pattern + patternLength);
const UChar* ptr = (const UChar*)(pattern - 1);
const UChar* patternEnd = (const UChar*)(pattern + patternLength);
while (++ptr < patternEnd) {
int minRepeats = 0, maxRepeats = 0;
......@@ -2200,7 +2192,7 @@ static int calculateCompiledPatternLength(const Char* pattern, int patternLength
int d = -1;
if (safelyCheckNextChar(ptr, patternEnd, '-')) {
Char const *hyptr = ptr++;
UChar const *hyptr = ptr++;
if (safelyCheckNextChar(ptr, patternEnd, '\\')) {
ptr++;
d = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true);
......@@ -2545,8 +2537,7 @@ static inline JSRegExp* returnError(ErrorCode errorcode, const char** errorptr)
return 0;
}
template <typename Char>
JSRegExp* jsRegExpCompile(const Char* pattern, int patternLength,
JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength,
JSRegExpIgnoreCaseOption ignoreCase, JSRegExpMultilineOption multiline,
unsigned* numSubpatterns, const char** errorptr,
malloc_t* allocate_function, free_t* free_function)
......@@ -2587,8 +2578,8 @@ JSRegExp* jsRegExpCompile(const Char* pattern, int patternLength,
error, errorcode will be set non-zero, so we don't need to look at the result
of the function here. */
const Char* ptr = (const Char*)pattern;
const Char* patternEnd = pattern + patternLength;
const UChar* ptr = (const UChar*)pattern;
const UChar* patternEnd = pattern + patternLength;
unsigned char* code = (unsigned char*)codeStart;
int firstbyte, reqbyte;
int bracketCount = 0;
......@@ -2676,26 +2667,6 @@ JSRegExp* jsRegExpCompile(const Char* pattern, int patternLength,
return re;
}
template
JSRegExp* jsRegExpCompile<unsigned short>(const unsigned short* pattern,
int patternLength,
JSRegExpIgnoreCaseOption ignoreCase,
JSRegExpMultilineOption multiline,
unsigned* numSubpatterns,
const char** errorptr,
malloc_t* allocate_function,
free_t* free_function);
template
JSRegExp* jsRegExpCompile<char>(const char* pattern,
int patternLength,
JSRegExpIgnoreCaseOption ignoreCase,
JSRegExpMultilineOption multiline,
unsigned* numSubpatterns,
const char** errorptr,
malloc_t* allocate_function,
free_t* free_function);
void jsRegExpFree(JSRegExp* re, free_t* free_function)
{
(*free_function)(reinterpret_cast<void*>(re));
......
......@@ -70,23 +70,21 @@ typedef void* ReturnLocation;
/* Structure for building a chain of data for holding the values of
the subject pointer at the start of each bracket, used to detect when
an empty string has been matched by a bracket to break infinite loops. */
template <typename Char>
struct BracketChainNode {
BracketChainNode<Char>* previousBracket;
const Char* bracketStart;
BracketChainNode* previousBracket;
const UChar* bracketStart;
};
template <typename Char>
struct MatchFrame {
ReturnLocation returnLocation;
struct MatchFrame<Char>* previousFrame;
struct MatchFrame* previousFrame;
/* Function arguments that may change */
struct {
const Char* subjectPtr;
const UChar* subjectPtr;
const unsigned char* instructionPtr;
int offsetTop;
BracketChainNode<Char>* bracketChain;
BracketChainNode* bracketChain;
} args;
......@@ -96,7 +94,7 @@ struct MatchFrame {
struct {
const unsigned char* data;
const unsigned char* startOfRepeatingBracket;
const Char* subjectPtrAtStartOfInstruction; // Several instrutions stash away a subjectPtr here for later compare
const UChar* subjectPtrAtStartOfInstruction; // Several instrutions stash away a subjectPtr here for later compare
const unsigned char* instructionPtrAtStartOfOnce;
int repeatOthercase;
......@@ -112,22 +110,21 @@ struct MatchFrame {
int saveOffset2;
int saveOffset3;
BracketChainNode<Char> bracketChainNode;
BracketChainNode bracketChainNode;
} locals;
};
/* Structure for passing "static" information around between the functions
doing traditional NFA matching, so that they are thread-safe. */
template <typename Char>
struct MatchData {
int* offsetVector; /* Offset vector */
int offsetEnd; /* One past the end */
int offsetMax; /* The maximum usable for return data */
bool offsetOverflow; /* Set if too many extractions */
const Char* startSubject; /* Start of the subject string */
const Char* endSubject; /* End of the subject string */
const Char* endMatchPtr; /* Subject position at end match */
const UChar* startSubject; /* Start of the subject string */
const UChar* endSubject; /* End of the subject string */
const UChar* endMatchPtr; /* Subject position at end match */
int endOffsetTop; /* Highwater mark at end of match */
bool multiline;
bool ignoreCase;
......@@ -158,8 +155,7 @@ Arguments:
md pointer to matching data block, if isSubject is true
*/
template <typename Char>
static void pchars(const Char* p, int length, bool isSubject, const MatchData& md)
static void pchars(const UChar* p, int length, bool isSubject, const MatchData& md)
{
if (isSubject && length > md.endSubject - p)
length = md.endSubject - p;
......@@ -191,10 +187,9 @@ Arguments:
Returns: true if matched
*/
template <typename Char>
static bool matchRef(int offset, const Char* subjectPtr, int length, const MatchData<Char>& md)
static bool matchRef(int offset, const UChar* subjectPtr, int length, const MatchData& md)
{
const Char* p = md.startSubject + md.offsetVector[offset];
const UChar* p = md.startSubject + md.offsetVector[offset];
#ifdef DEBUG
if (subjectPtr >= md.endSubject)
......@@ -217,9 +212,9 @@ static bool matchRef(int offset, const Char* subjectPtr, int length, const Match
if (md.ignoreCase) {
while (length-- > 0) {
Char c = *p++;
UChar c = *p++;
int othercase = kjs_pcre_ucp_othercase(c);
Char d = *subjectPtr++;
UChar d = *subjectPtr++;
if (c != d && othercase != d)
return false;
}
......@@ -301,7 +296,6 @@ Returns: 1 if matched ) these values are >= 0
static const unsigned FRAMES_ON_STACK = 16;
template <typename Char>
struct MatchStack {
MatchStack()
: framesEnd(frames + FRAMES_ON_STACK)
......@@ -311,9 +305,9 @@ struct MatchStack {
ASSERT((sizeof(frames) / sizeof(frames[0])) == FRAMES_ON_STACK);
}
MatchFrame<Char> frames[FRAMES_ON_STACK];
MatchFrame<Char>* framesEnd;
MatchFrame<Char>* currentFrame;
MatchFrame frames[FRAMES_ON_STACK];
MatchFrame* framesEnd;
MatchFrame* currentFrame;
unsigned size;
inline bool canUseStackBufferForNextFrame()
......@@ -321,16 +315,16 @@ struct MatchStack {
return size < FRAMES_ON_STACK;
}
inline MatchFrame<Char>* allocateNextFrame()
inline MatchFrame* allocateNextFrame()
{
if (canUseStackBufferForNextFrame())
return currentFrame + 1;
return new MatchFrame<Char>;
return new MatchFrame;
}
inline void pushNewFrame(const unsigned char* instructionPtr, BracketChainNode<Char>* bracketChain, ReturnLocation returnLocation)
inline void pushNewFrame(const unsigned char* instructionPtr, BracketChainNode* bracketChain, ReturnLocation returnLocation)
{
MatchFrame<Char>* newframe = allocateNextFrame();
MatchFrame* newframe = allocateNextFrame();
newframe->previousFrame = currentFrame;
newframe->args.subjectPtr = currentFrame->args.subjectPtr;
......@@ -345,7 +339,7 @@ struct MatchStack {
inline void popCurrentFrame()
{
MatchFrame<Char>* oldFrame = currentFrame;
MatchFrame* oldFrame = currentFrame;
currentFrame = currentFrame->previousFrame;
if (size > FRAMES_ON_STACK)
delete oldFrame;
......@@ -359,8 +353,7 @@ struct MatchStack {
}
};
template <typename Char>
static int matchError(int errorCode, MatchStack<Char>& stack)
static int matchError(int errorCode, MatchStack& stack)
{
stack.popAllFrames();
return errorCode;
......@@ -384,8 +377,7 @@ static inline void getUTF8CharAndIncrementLength(int& c, const unsigned char* su
}
}
template <typename Char>
static inline void startNewGroup(MatchFrame<Char>* currentFrame)
static inline void startNewGroup(MatchFrame* currentFrame)
{
/* At the start of a bracketed group, add the current subject pointer to the
stack of such pointers, to be re-instated at the end of the group when we hit
......@@ -412,15 +404,14 @@ static inline void repeatInformationFromInstructionOffset(short instructionOffse
maximumRepeats = maximumRepeatsFromInstructionOffset[instructionOffset];
}
template <typename Char>
static int match(const Char* subjectPtr, const unsigned char* instructionPtr, int offsetTop, MatchData<Char>& md)
static int match(const UChar* subjectPtr, const unsigned char* instructionPtr, int offsetTop, MatchData& md)
{
bool isMatch = false;
int min;
bool minimize = false; /* Initialization not really needed, but some compilers think so. */
unsigned matchCount = 0;
MatchStack<Char> stack;
MatchStack stack;
/* The opcode jump table. */
#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
......@@ -1837,13 +1828,12 @@ Returns: > 0 => success; value is the number of elements filled in
< -1 => some kind of unexpected problem
*/
template <typename Char>
static void tryFirstByteOptimization(const Char*& subjectPtr, const Char* endSubject, int first_byte, bool first_byte_caseless, bool useMultiLineFirstCharOptimization, const Char* originalSubjectStart)
static void tryFirstByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int first_byte, bool first_byte_caseless, bool useMultiLineFirstCharOptimization, const UChar* originalSubjectStart)
{
// If first_byte is set, try scanning to the first instance of that byte
// no need to try and match against any earlier part of the subject string.
if (first_byte >= 0) {
Char first_char = first_byte;
UChar first_char = first_byte;
if (first_byte_caseless)
while (subjectPtr < endSubject) {
int c = *subjectPtr;
......@@ -1867,8 +1857,7 @@ static void tryFirstByteOptimization(const Char*& subjectPtr, const Char* endSub
}
}
template <typename Char>
static bool tryRequiredByteOptimization(const Char*& subjectPtr, const Char* endSubject, int req_byte, int req_byte2, bool req_byte_caseless, bool hasFirstByte, const Char*& reqBytePtr)
static bool tryRequiredByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int req_byte, int req_byte2, bool req_byte_caseless, bool hasFirstByte, const UChar*& reqBytePtr)
{
/* If req_byte is set, we know that that character must appear in the subject
for the match to succeed. If the first character is set, req_byte must be
......@@ -1885,7 +1874,7 @@ static bool tryRequiredByteOptimization(const Char*& subjectPtr, const Char* end
*/
if (req_byte >= 0 && endSubject - subjectPtr < REQ_BYTE_MAX) {
const Char* p = subjectPtr + (hasFirstByte ? 1 : 0);
const UChar* p = subjectPtr + (hasFirstByte ? 1 : 0);
/* We don't need to repeat the search if we haven't yet reached the
place we found it at last time. */
......@@ -1923,9 +1912,8 @@ static bool tryRequiredByteOptimization(const Char*& subjectPtr, const Char* end
return false;
}
template <typename Char>
int jsRegExpExecute(const JSRegExp* re,
const Char* subject, int length, int start_offset, int* offsets,
const UChar* subject, int length, int start_offset, int* offsets,
int offsetcount)
{
ASSERT(re);
......@@ -1933,10 +1921,10 @@ int jsRegExpExecute(const JSRegExp* re,
ASSERT(offsetcount >= 0);
ASSERT(offsets || offsetcount == 0);
MatchData<Char> matchBlock;
MatchData matchBlock;
matchBlock.startSubject = subject;
matchBlock.endSubject = matchBlock.startSubject + length;
const Char* endSubject = matchBlock.endSubject;
const UChar* endSubject = matchBlock.endSubject;
matchBlock.multiline = (re->options & MatchAcrossMultipleLinesOption);
matchBlock.ignoreCase = (re->options & IgnoreCaseOption);
......@@ -2013,8 +2001,8 @@ int jsRegExpExecute(const JSRegExp* re,
/* Loop for handling unanchored repeated matching attempts; for anchored regexs
the loop runs just once. */
const Char* startMatch = subject + start_offset;
const Char* reqBytePtr = startMatch - 1;
const UChar* startMatch = subject + start_offset;
const UChar* reqBytePtr = startMatch - 1;
bool useMultiLineFirstCharOptimization = re->options & UseMultiLineFirstByteOptimizationOption;
do {
......@@ -2040,7 +2028,7 @@ int jsRegExpExecute(const JSRegExp* re,
/* The code starts after the JSRegExp block and the capture name table. */
const unsigned char* start_code = (const unsigned char*)(re + 1);
int returnCode = match<Char>(startMatch, start_code, 2, matchBlock);
int returnCode = match(startMatch, start_code, 2, matchBlock);
/* When the result is no match, advance the pointer to the next character
and continue. */
......@@ -2091,15 +2079,3 @@ int jsRegExpExecute(const JSRegExp* re,
DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n"));
return JSRegExpErrorNoMatch;
}
template
int jsRegExpExecute<unsigned short>(const JSRegExp* re,
const unsigned short* subject,
int length, int start_offset,
int* offsets, int offsetcount);
template
int jsRegExpExecute<char>(const JSRegExp* re,
const char* subject,
int length, int start_offset,
int* offsets, int offsetcount);
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