From 40ea061c30a9f6be21a35239341a259847f8cac5 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 29 Mar 2010 01:04:53 -0700 Subject: [PATCH] Upgrade V8 to 2.2.0 --- deps/v8/ChangeLog | 7 +++ deps/v8/src/SConscript | 1 + deps/v8/src/bootstrapper.cc | 62 ++++++++++++++++++- deps/v8/src/builtins.cc | 4 +- deps/v8/src/frame-element.h | 2 +- deps/v8/src/heap.cc | 24 ++++++- deps/v8/src/heap.h | 5 ++ deps/v8/src/objects-inl.h | 10 +++ deps/v8/src/objects.cc | 29 ++++++++- deps/v8/src/objects.h | 14 +++++ deps/v8/src/regexp.js | 26 +------- deps/v8/src/register-allocator.h | 2 +- deps/v8/src/runtime.cc | 56 +++++++++++++++++ deps/v8/src/runtime.h | 1 + deps/v8/src/{type-info-inl.h => type-info.cc} | 6 +- deps/v8/src/type-info.h | 2 +- deps/v8/src/v8-counters.h | 1 + deps/v8/src/version.cc | 4 +- deps/v8/test/mjsunit/mirror-regexp.js | 4 +- deps/v8/test/mjsunit/regexp.js | 48 ++++++++++++++ deps/v8/tools/gyp/v8.gyp | 2 +- deps/v8/tools/visual_studio/v8_base.vcproj | 2 +- .../v8/tools/visual_studio/v8_base_arm.vcproj | 2 +- .../v8/tools/visual_studio/v8_base_x64.vcproj | 2 +- 24 files changed, 270 insertions(+), 46 deletions(-) rename deps/v8/src/{type-info-inl.h => type-info.cc} (95%) diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 0de330847b..a15cce80d0 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,10 @@ +2010-03-29: Version 2.2.0 + + Fixed a few minor bugs. + + Performance improvements for string operations. + + 2010-03-26: Version 2.1.10 Fixed scons build issues. diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript index a1d4796b7f..1f1c1c1833 100755 --- a/deps/v8/src/SConscript +++ b/deps/v8/src/SConscript @@ -102,6 +102,7 @@ SOURCES = { stub-cache.cc token.cc top.cc + type-info.cc unicode.cc utils.cc v8-counters.cc diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 8a9fa4bf69..82a63f0ae6 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -723,8 +723,68 @@ void Genesis::InitializeGlobal(Handle inner_global, InstallFunction(global, "RegExp", JS_REGEXP_TYPE, JSRegExp::kSize, Top::initial_object_prototype(), Builtins::Illegal, true); - global_context()->set_regexp_function(*regexp_fun); + + ASSERT(regexp_fun->has_initial_map()); + Handle initial_map(regexp_fun->initial_map()); + + ASSERT_EQ(0, initial_map->inobject_properties()); + + Handle descriptors = Factory::NewDescriptorArray(5); + PropertyAttributes final = + static_cast(DONT_ENUM | DONT_DELETE | READ_ONLY); + int enum_index = 0; + { + // ECMA-262, section 15.10.7.1. + FieldDescriptor field(Heap::source_symbol(), + JSRegExp::kSourceFieldIndex, + final, + enum_index++); + descriptors->Set(0, &field); + } + { + // ECMA-262, section 15.10.7.2. + FieldDescriptor field(Heap::global_symbol(), + JSRegExp::kGlobalFieldIndex, + final, + enum_index++); + descriptors->Set(1, &field); + } + { + // ECMA-262, section 15.10.7.3. + FieldDescriptor field(Heap::ignore_case_symbol(), + JSRegExp::kIgnoreCaseFieldIndex, + final, + enum_index++); + descriptors->Set(2, &field); + } + { + // ECMA-262, section 15.10.7.4. + FieldDescriptor field(Heap::multiline_symbol(), + JSRegExp::kMultilineFieldIndex, + final, + enum_index++); + descriptors->Set(3, &field); + } + { + // ECMA-262, section 15.10.7.5. + PropertyAttributes writable = + static_cast(DONT_ENUM | DONT_DELETE); + FieldDescriptor field(Heap::last_index_symbol(), + JSRegExp::kLastIndexFieldIndex, + writable, + enum_index++); + descriptors->Set(4, &field); + } + descriptors->SetNextEnumerationIndex(enum_index); + descriptors->Sort(); + + initial_map->set_inobject_properties(5); + initial_map->set_pre_allocated_property_fields(5); + initial_map->set_unused_property_fields(0); + initial_map->set_instance_size( + initial_map->instance_size() + 5 * kPointerSize); + initial_map->set_instance_descriptors(*descriptors); } { // -- J S O N diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index 122fbba2c4..feb912f414 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -495,7 +495,9 @@ BUILTIN(ArrayShift) { } if (Heap::new_space()->Contains(elms)) { - array->set_elements(LeftTrimFixedArray(elms)); + // As elms still in the same space they used to be (new space), + // there is no need to update remembered set. + array->set_elements(LeftTrimFixedArray(elms), SKIP_WRITE_BARRIER); } else { // Shift the elements. AssertNoAllocation no_gc; diff --git a/deps/v8/src/frame-element.h b/deps/v8/src/frame-element.h index 83db5c3342..48bb354aa8 100644 --- a/deps/v8/src/frame-element.h +++ b/deps/v8/src/frame-element.h @@ -28,7 +28,7 @@ #ifndef V8_FRAME_ELEMENT_H_ #define V8_FRAME_ELEMENT_H_ -#include "type-info-inl.h" +#include "type-info.h" #include "macro-assembler.h" #include "zone.h" diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index 1f1599a79b..5421dcc195 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -1961,8 +1961,9 @@ Object* Heap::AllocateConsString(String* first, String* second) { return MakeOrFindTwoCharacterString(c1, c2); } - bool is_ascii = first->IsAsciiRepresentation() - && second->IsAsciiRepresentation(); + bool first_is_ascii = first->IsAsciiRepresentation(); + bool second_is_ascii = second->IsAsciiRepresentation(); + bool is_ascii = first_is_ascii && second_is_ascii; // Make sure that an out of memory exception is thrown if the length // of the new cons string is too large. @@ -1997,6 +1998,25 @@ Object* Heap::AllocateConsString(String* first, String* second) { for (int i = 0; i < second_length; i++) *dest++ = src[i]; return result; } else { + // For short external two-byte strings we check whether they can + // be represented using ascii. + if (!first_is_ascii) { + first_is_ascii = first->IsExternalTwoByteStringWithAsciiChars(); + } + if (first_is_ascii && !second_is_ascii) { + second_is_ascii = second->IsExternalTwoByteStringWithAsciiChars(); + } + if (first_is_ascii && second_is_ascii) { + Object* result = AllocateRawAsciiString(length); + if (result->IsFailure()) return result; + // Copy the characters into the new object. + char* dest = SeqAsciiString::cast(result)->GetChars(); + String::WriteToFlat(first, dest, 0, first_length); + String::WriteToFlat(second, dest + first_length, 0, second_length); + Counters::string_add_runtime_ext_to_ascii.Increment(); + return result; + } + Object* result = AllocateRawTwoByteString(length); if (result->IsFailure()) return result; // Copy the characters into the new object. diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h index 2a0de236ee..494c99b1f4 100644 --- a/deps/v8/src/heap.h +++ b/deps/v8/src/heap.h @@ -149,6 +149,11 @@ class ZoneScopeInfo; V(number_symbol, "number") \ V(Number_symbol, "Number") \ V(RegExp_symbol, "RegExp") \ + V(source_symbol, "source") \ + V(global_symbol, "global") \ + V(ignore_case_symbol, "ignoreCase") \ + V(multiline_symbol, "multiline") \ + V(last_index_symbol, "lastIndex") \ V(object_symbol, "object") \ V(prototype_symbol, "prototype") \ V(string_symbol, "string") \ diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index a26da7dd62..6d7bad7512 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -255,6 +255,16 @@ bool String::IsTwoByteRepresentation() { } +bool String::IsExternalTwoByteStringWithAsciiChars() { + if (!IsExternalTwoByteString()) return false; + const uc16* data = ExternalTwoByteString::cast(this)->resource()->data(); + for (int i = 0, len = length(); i < len; i++) { + if (data[i] > kMaxAsciiCharCode) return false; + } + return true; +} + + bool StringShape::IsCons() { return (type_ & kStringRepresentationMask) == kConsStringTag; } diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index a1fbc99277..02ea5b0455 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -4660,13 +4660,38 @@ bool String::IsEqualTo(Vector str) { } +template +static inline uint32_t HashSequentialString(const schar* chars, int length) { + StringHasher hasher(length); + if (!hasher.has_trivial_hash()) { + int i; + for (i = 0; hasher.is_array_index() && (i < length); i++) { + hasher.AddCharacter(chars[i]); + } + for (; i < length; i++) { + hasher.AddCharacterNoIndex(chars[i]); + } + } + return hasher.GetHashField(); +} + + uint32_t String::ComputeAndSetHash() { // Should only be called if hash code has not yet been computed. ASSERT(!(hash_field() & kHashComputedMask)); + const int len = length(); + // Compute the hash code. - StringInputBuffer buffer(this); - uint32_t field = ComputeHashField(&buffer, length()); + uint32_t field = 0; + if (StringShape(this).IsSequentialAscii()) { + field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len); + } else if (StringShape(this).IsSequentialTwoByte()) { + field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len); + } else { + StringInputBuffer buffer(this); + field = ComputeHashField(&buffer, len); + } // Store the hash code in the object. set_hash_field(field); diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 01977f0929..9197466e85 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -3667,6 +3667,13 @@ class JSRegExp: public JSObject { FixedArray::kHeaderSize + kIrregexpUC16CodeIndex * kPointerSize; static const int kIrregexpCaptureCountOffset = FixedArray::kHeaderSize + kIrregexpCaptureCountIndex * kPointerSize; + + // In-object fields. + static const int kSourceFieldIndex = 0; + static const int kGlobalFieldIndex = 1; + static const int kIgnoreCaseFieldIndex = 2; + static const int kMultilineFieldIndex = 3; + static const int kLastIndexFieldIndex = 4; }; @@ -3919,6 +3926,13 @@ class String: public HeapObject { inline bool IsAsciiRepresentation(); inline bool IsTwoByteRepresentation(); + // Check whether this string is an external two-byte string that in + // fact contains only ascii characters. + // + // Such strings may appear when the embedder prefers two-byte + // representations even for ascii data. + inline bool IsExternalTwoByteStringWithAsciiChars(); + // Get and set individual two byte chars in the string. inline void Set(int index, uint16_t value); // Get individual two byte char in the string. Repeated calls diff --git a/deps/v8/src/regexp.js b/deps/v8/src/regexp.js index dc1b0429f7..cc9723c816 100644 --- a/deps/v8/src/regexp.js +++ b/deps/v8/src/regexp.js @@ -71,32 +71,10 @@ function DoConstructRegExp(object, pattern, flags, isConstructorCall) { } } - if (isConstructorCall) { - // ECMA-262, section 15.10.7.1. - %SetProperty(object, 'source', pattern, - DONT_DELETE | READ_ONLY | DONT_ENUM); - - // ECMA-262, section 15.10.7.2. - %SetProperty(object, 'global', global, DONT_DELETE | READ_ONLY | DONT_ENUM); - - // ECMA-262, section 15.10.7.3. - %SetProperty(object, 'ignoreCase', ignoreCase, - DONT_DELETE | READ_ONLY | DONT_ENUM); - - // ECMA-262, section 15.10.7.4. - %SetProperty(object, 'multiline', multiline, - DONT_DELETE | READ_ONLY | DONT_ENUM); - - // ECMA-262, section 15.10.7.5. - %SetProperty(object, 'lastIndex', 0, DONT_DELETE | DONT_ENUM); - } else { // RegExp is being recompiled via RegExp.prototype.compile. - %IgnoreAttributesAndSetProperty(object, 'source', pattern); - %IgnoreAttributesAndSetProperty(object, 'global', global); - %IgnoreAttributesAndSetProperty(object, 'ignoreCase', ignoreCase); - %IgnoreAttributesAndSetProperty(object, 'multiline', multiline); - %IgnoreAttributesAndSetProperty(object, 'lastIndex', 0); + if (!isConstructorCall) { regExpCache.type = 'none'; } + %RegExpInitializeObject(object, pattern, global, ignoreCase, multiline); // Call internal function to compile the pattern. %RegExpCompile(object, pattern, flags); diff --git a/deps/v8/src/register-allocator.h b/deps/v8/src/register-allocator.h index 0fbc83b821..4564533911 100644 --- a/deps/v8/src/register-allocator.h +++ b/deps/v8/src/register-allocator.h @@ -29,7 +29,7 @@ #define V8_REGISTER_ALLOCATOR_H_ #include "macro-assembler.h" -#include "type-info-inl.h" +#include "type-info.h" #if V8_TARGET_ARCH_IA32 #include "ia32/register-allocator-ia32.h" diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index c77d518371..7d104fa3b4 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -1228,6 +1228,62 @@ static Object* Runtime_RegExpExec(Arguments args) { } +static Object* Runtime_RegExpInitializeObject(Arguments args) { + AssertNoAllocation no_alloc; + ASSERT(args.length() == 5); + CONVERT_CHECKED(JSRegExp, regexp, args[0]); + CONVERT_CHECKED(String, source, args[1]); + + Object* global = args[2]; + if (!global->IsTrue()) global = Heap::false_value(); + + Object* ignoreCase = args[3]; + if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value(); + + Object* multiline = args[4]; + if (!multiline->IsTrue()) multiline = Heap::false_value(); + + Map* map = regexp->map(); + Object* constructor = map->constructor(); + if (constructor->IsJSFunction() && + JSFunction::cast(constructor)->initial_map() == map) { + // If we still have the original map, set in-object properties directly. + regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source); + // TODO(lrn): Consider skipping write barrier on booleans as well. + // Both true and false should be in oldspace at all times. + regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global); + regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase); + regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline); + regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, + Smi::FromInt(0), + SKIP_WRITE_BARRIER); + return regexp; + } + + // Map has changed, so use generic, but slower, method. + PropertyAttributes final = + static_cast(READ_ONLY | DONT_ENUM | DONT_DELETE); + PropertyAttributes writable = + static_cast(DONT_ENUM | DONT_DELETE); + regexp->IgnoreAttributesAndSetLocalProperty(Heap::source_symbol(), + source, + final); + regexp->IgnoreAttributesAndSetLocalProperty(Heap::global_symbol(), + global, + final); + regexp->IgnoreAttributesAndSetLocalProperty(Heap::ignore_case_symbol(), + ignoreCase, + final); + regexp->IgnoreAttributesAndSetLocalProperty(Heap::multiline_symbol(), + multiline, + final); + regexp->IgnoreAttributesAndSetLocalProperty(Heap::last_index_symbol(), + Smi::FromInt(0), + writable); + return regexp; +} + + static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) { HandleScope scope; ASSERT(args.length() == 1); diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h index 42af3df88a..a55a27135b 100644 --- a/deps/v8/src/runtime.h +++ b/deps/v8/src/runtime.h @@ -154,6 +154,7 @@ namespace internal { F(RegExpCompile, 3, 1) \ F(RegExpExec, 4, 1) \ F(RegExpExecMultiple, 4, 1) \ + F(RegExpInitializeObject, 5, 1) \ \ /* Strings */ \ F(StringCharCodeAt, 2, 1) \ diff --git a/deps/v8/src/type-info-inl.h b/deps/v8/src/type-info.cc similarity index 95% rename from deps/v8/src/type-info-inl.h rename to deps/v8/src/type-info.cc index 90d3f55f9b..b1bde599f4 100644 --- a/deps/v8/src/type-info-inl.h +++ b/deps/v8/src/type-info.cc @@ -25,9 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_TYPE_INFO_INL_H_ -#define V8_TYPE_INFO_INL_H_ - +#include "v8.h" #include "type-info.h" #include "objects-inl.h" @@ -51,5 +49,3 @@ TypeInfo TypeInfo::TypeFromValue(Handle value) { } } // namespace v8::internal - -#endif // V8_TYPE_INFO_INL_H_ diff --git a/deps/v8/src/type-info.h b/deps/v8/src/type-info.h index 15bc128023..1d82634092 100644 --- a/deps/v8/src/type-info.h +++ b/deps/v8/src/type-info.h @@ -130,7 +130,7 @@ class TypeInfo { return false; } - static inline TypeInfo TypeFromValue(Handle value); + static TypeInfo TypeFromValue(Handle value); inline bool IsUnknown() { return type_ == kUnknownType; diff --git a/deps/v8/src/v8-counters.h b/deps/v8/src/v8-counters.h index a5f3594ca7..bd671a13fe 100644 --- a/deps/v8/src/v8-counters.h +++ b/deps/v8/src/v8-counters.h @@ -166,6 +166,7 @@ namespace internal { SC(generic_binary_stub_calls_regs, V8.GenericBinaryStubCallsRegs) \ SC(string_add_runtime, V8.StringAddRuntime) \ SC(string_add_native, V8.StringAddNative) \ + SC(string_add_runtime_ext_to_ascii, V8.StringAddRuntimeExtToAscii) \ SC(sub_string_runtime, V8.SubStringRuntime) \ SC(sub_string_native, V8.SubStringNative) \ SC(string_compare_native, V8.StringCompareNative) \ diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index e3d0887552..66e79013d6 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -33,8 +33,8 @@ // NOTE these macros are used by the SCons build script so their names // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 2 -#define MINOR_VERSION 1 -#define BUILD_NUMBER 10 +#define MINOR_VERSION 2 +#define BUILD_NUMBER 0 #define PATCH_LEVEL 0 #define CANDIDATE_VERSION false diff --git a/deps/v8/test/mjsunit/mirror-regexp.js b/deps/v8/test/mjsunit/mirror-regexp.js index 8c834bf38b..d6a9d71024 100644 --- a/deps/v8/test/mjsunit/mirror-regexp.js +++ b/deps/v8/test/mjsunit/mirror-regexp.js @@ -70,8 +70,8 @@ function testRegExpMirror(r) { assertEquals('regexp', mirror.type()); assertFalse(mirror.isPrimitive()); for (var p in expected_attributes) { - assertEquals(mirror.property(p).attributes(), - expected_attributes[p], + assertEquals(expected_attributes[p], + mirror.property(p).attributes(), p + ' attributes'); } diff --git a/deps/v8/test/mjsunit/regexp.js b/deps/v8/test/mjsunit/regexp.js index 0a23d00acc..c8dcc6fe89 100644 --- a/deps/v8/test/mjsunit/regexp.js +++ b/deps/v8/test/mjsunit/regexp.js @@ -388,3 +388,51 @@ try { assertTrue(String(e).indexOf("Stack overflow") >= 0, "overflow"); } + +// Test that compile works on modified objects +var re = /re+/; +assertEquals("re+", re.source); +assertFalse(re.global); +assertFalse(re.ignoreCase); +assertFalse(re.multiline); +assertEquals(0, re.lastIndex); + +re.compile("ro+", "gim"); +assertEquals("ro+", re.source); +assertTrue(re.global); +assertTrue(re.ignoreCase); +assertTrue(re.multiline); +assertEquals(0, re.lastIndex); + +re.lastIndex = 42; +re.someOtherProperty = 42; +re.someDeletableProperty = 42; +re[37] = 37; +re[42] = 42; + +re.compile("ra+", "i"); +assertEquals("ra+", re.source); +assertFalse(re.global); +assertTrue(re.ignoreCase); +assertFalse(re.multiline); +assertEquals(0, re.lastIndex); + +assertEquals(42, re.someOtherProperty); +assertEquals(42, re.someDeletableProperty); +assertEquals(37, re[37]); +assertEquals(42, re[42]); + +re.lastIndex = -1; +re.someOtherProperty = 37; +re[42] = 37; +assertTrue(delete re[37]); +assertTrue(delete re.someDeletableProperty); +re.compile("ri+", "gm"); + +assertEquals("ri+", re.source); +assertTrue(re.global); +assertFalse(re.ignoreCase); +assertTrue(re.multiline); +assertEquals(0, re.lastIndex); +assertEquals(37, re.someOtherProperty); +assertEquals(37, re[42]); diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp index d5bb0cb764..7d0e699528 100644 --- a/deps/v8/tools/gyp/v8.gyp +++ b/deps/v8/tools/gyp/v8.gyp @@ -388,7 +388,7 @@ '../../src/token.h', '../../src/top.cc', '../../src/top.h', - '../../src/type-info-inl.h', + '../../src/type-info.cc', '../../src/type-info.h', '../../src/unicode-inl.h', '../../src/unicode.cc', diff --git a/deps/v8/tools/visual_studio/v8_base.vcproj b/deps/v8/tools/visual_studio/v8_base.vcproj index 58bf92f8ff..5fa08f7038 100644 --- a/deps/v8/tools/visual_studio/v8_base.vcproj +++ b/deps/v8/tools/visual_studio/v8_base.vcproj @@ -945,7 +945,7 @@ >