From dbdcded866ce6a3d84f57865379eaddc3dbc8302 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 4 Jul 2016 11:08:27 +0200 Subject: [PATCH] deps: upgrade to V8 5.0.71.54 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/7531 Reviewed-By: Michaƫl Zasso --- deps/v8/include/v8-version.h | 2 +- deps/v8/src/bootstrapper.cc | 4 + deps/v8/src/builtins.cc | 68 ++++ deps/v8/src/builtins.h | 2 + deps/v8/src/compiler/access-info.cc | 8 +- deps/v8/src/crankshaft/hydrogen.cc | 10 +- deps/v8/src/ic/ic-compiler.cc | 7 +- deps/v8/src/ic/ic.cc | 11 +- deps/v8/src/js/string.js | 13 - deps/v8/src/objects-inl.h | 20 ++ deps/v8/src/objects.cc | 154 ++++++--- deps/v8/src/objects.h | 53 ++- .../test/cctest/test-field-type-tracking.cc | 320 +++++++++++++++++- deps/v8/test/cctest/test-strings.cc | 22 ++ .../mjsunit/regress/regress-crbug-617524.js | 18 + .../regress/regress-seqstrsetchar-ex2.js | 34 -- .../test/mjsunit/regress/regress-v8-5009.js | 61 ++++ deps/v8/test/mjsunit/string-fromcharcode.js | 5 - 18 files changed, 657 insertions(+), 155 deletions(-) create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-617524.js delete mode 100644 deps/v8/test/mjsunit/regress/regress-seqstrsetchar-ex2.js create mode 100644 deps/v8/test/mjsunit/regress/regress-v8-5009.js diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index c24f07202b0847..39a537df5720aa 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 5 #define V8_MINOR_VERSION 0 #define V8_BUILD_NUMBER 71 -#define V8_PATCH_LEVEL 52 +#define V8_PATCH_LEVEL 54 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 252c51cae4deb7..73951f5e39fc2d 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -1292,6 +1292,10 @@ void Genesis::InitializeGlobal(Handle global_object, attribs); string_map->AppendDescriptor(&d); } + + // Install the String.fromCharCode function. + SimpleInstallFunction(string_fun, "fromCharCode", + Builtins::kStringFromCharCode, 1, false); } { diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index 23c41f706eb1c7..e057d6dff7f3b8 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -3732,6 +3732,74 @@ BUILTIN(ObjectProtoToString) { return *result; } +// ----------------------------------------------------------------------------- +// ES6 section 21.1 String Objects + +namespace { + +bool ToUint16(Handle value, uint16_t* result) { + if (value->IsNumber() || Object::ToNumber(value).ToHandle(&value)) { + *result = DoubleToUint32(value->Number()); + return true; + } + return false; +} + +} // namespace + +// ES6 21.1.2.1 String.fromCharCode ( ...codeUnits ) +BUILTIN(StringFromCharCode) { + HandleScope scope(isolate); + // Check resulting string length. + int index = 0; + Handle result; + int const length = args.length() - 1; + if (length == 0) return isolate->heap()->empty_string(); + DCHECK_LT(0, length); + // Load the first character code. + uint16_t code; + if (!ToUint16(args.at(1), &code)) return isolate->heap()->exception(); + // Assume that the resulting String contains only one byte characters. + if (code <= String::kMaxOneByteCharCodeU) { + // Check for single one-byte character fast case. + if (length == 1) { + return *isolate->factory()->LookupSingleCharacterStringFromCode(code); + } + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, isolate->factory()->NewRawOneByteString(length)); + do { + Handle::cast(result)->Set(index, code); + if (++index == length) break; + if (!ToUint16(args.at(1 + index), &code)) { + return isolate->heap()->exception(); + } + } while (code <= String::kMaxOneByteCharCodeU); + } + // Check if all characters fit into the one byte range. + if (index < length) { + // Fallback to two byte string. + Handle new_result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, new_result, isolate->factory()->NewRawTwoByteString(length)); + for (int new_index = 0; new_index < index; ++new_index) { + uint16_t new_code = + Handle::cast(result)->Get(new_index); + Handle::cast(new_result)->Set(new_index, new_code); + } + while (true) { + Handle::cast(new_result)->Set(index, code); + if (++index == length) break; + if (!ToUint16(args.at(1 + index), &code)) { + return isolate->heap()->exception(); + } + } + result = new_result; + } + return *result; +} + +// ----------------------------------------------------------------------------- +// ES6 section 21.1 ArrayBuffer Objects // ES6 section 24.1.2.1 ArrayBuffer ( length ) for the [[Call]] case. BUILTIN(ArrayBufferConstructor) { diff --git a/deps/v8/src/builtins.h b/deps/v8/src/builtins.h index 93e6e3d7f2e804..81161e93629bd3 100644 --- a/deps/v8/src/builtins.h +++ b/deps/v8/src/builtins.h @@ -149,6 +149,8 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) { V(ReflectSet, kNone) \ V(ReflectSetPrototypeOf, kNone) \ \ + V(StringFromCharCode, kNone) \ + \ V(SymbolConstructor, kNone) \ V(SymbolConstructor_ConstructStub, kTarget) \ \ diff --git a/deps/v8/src/compiler/access-info.cc b/deps/v8/src/compiler/access-info.cc index 4a2a857029a3d8..e38f629c5b5b7e 100644 --- a/deps/v8/src/compiler/access-info.cc +++ b/deps/v8/src/compiler/access-info.cc @@ -192,12 +192,12 @@ bool AccessInfoFactory::ComputeElementAccessInfos( MapTransitionList transitions(maps.length()); for (Handle map : maps) { if (Map::TryUpdate(map).ToHandle(&map)) { - Handle transition_target = - Map::FindTransitionedMap(map, &possible_transition_targets); - if (transition_target.is_null()) { + Map* transition_target = + map->FindElementsKindTransitionedMap(&possible_transition_targets); + if (transition_target == nullptr) { receiver_maps.Add(map); } else { - transitions.push_back(std::make_pair(map, transition_target)); + transitions.push_back(std::make_pair(map, handle(transition_target))); } } } diff --git a/deps/v8/src/crankshaft/hydrogen.cc b/deps/v8/src/crankshaft/hydrogen.cc index b6fdd3a3155302..4e34d177254076 100644 --- a/deps/v8/src/crankshaft/hydrogen.cc +++ b/deps/v8/src/crankshaft/hydrogen.cc @@ -7600,9 +7600,13 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( // Get transition target for each map (NULL == no transition). for (int i = 0; i < maps->length(); ++i) { Handle map = maps->at(i); - Handle transitioned_map = - Map::FindTransitionedMap(map, &possible_transitioned_maps); - transition_target.Add(transitioned_map); + Map* transitioned_map = + map->FindElementsKindTransitionedMap(&possible_transitioned_maps); + if (transitioned_map != nullptr) { + transition_target.Add(handle(transitioned_map)); + } else { + transition_target.Add(Handle()); + } } MapHandleList untransitionable_maps(maps->length()); diff --git a/deps/v8/src/ic/ic-compiler.cc b/deps/v8/src/ic/ic-compiler.cc index f74c69e50d431a..bc8a49332f24bd 100644 --- a/deps/v8/src/ic/ic-compiler.cc +++ b/deps/v8/src/ic/ic-compiler.cc @@ -235,8 +235,11 @@ void PropertyICCompiler::CompileKeyedStorePolymorphicHandlers( for (int i = 0; i < receiver_maps->length(); ++i) { Handle receiver_map(receiver_maps->at(i)); Handle cached_stub; - Handle transitioned_map = - Map::FindTransitionedMap(receiver_map, receiver_maps); + Handle transitioned_map; + { + Map* tmap = receiver_map->FindElementsKindTransitionedMap(receiver_maps); + if (tmap != nullptr) transitioned_map = handle(tmap); + } // TODO(mvstanton): The code below is doing pessimistic elements // transitions. I would like to stop doing that and rely on Allocation Site diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc index c0b3e49338a499..62669ca60bbd1f 100644 --- a/deps/v8/src/ic/ic.cc +++ b/deps/v8/src/ic/ic.cc @@ -836,11 +836,12 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) { ElementsKind target_elements_kind = target_map->elements_kind(); bool more_general_transition = IsMoreGeneralElementsKindTransition( source_map->elements_kind(), target_elements_kind); - Map* transitioned_map = - more_general_transition - ? source_map->LookupElementsTransitionMap(target_elements_kind) - : NULL; - + Map* transitioned_map = nullptr; + if (more_general_transition) { + MapHandleList map_list; + map_list.Add(handle(target_map)); + transitioned_map = source_map->FindElementsKindTransitionedMap(&map_list); + } return transitioned_map == target_map; } diff --git a/deps/v8/src/js/string.js b/deps/v8/src/js/string.js index a4019784e8ec12..cb74a67cfc22cd 100644 --- a/deps/v8/src/js/string.js +++ b/deps/v8/src/js/string.js @@ -558,18 +558,6 @@ function StringTrimRight() { } -// ECMA-262, section 15.5.3.2 -function StringFromCharCode(_) { // length == 1 - "use strict"; - var s = ""; - var n = arguments.length; - for (var i = 0; i < n; ++i) { - s += %_StringCharFromCode(arguments[i] & 0xffff); - } - return s; -} - - // ES6 draft, revision 26 (2014-07-18), section B.2.3.2.1 function HtmlEscape(str) { return %_Call(StringReplace, TO_STRING(str), /"/g, """); @@ -860,7 +848,6 @@ function StringRaw(callSite) { // Set up the non-enumerable functions on the String object. utils.InstallFunctions(GlobalString, DONT_ENUM, [ - "fromCharCode", StringFromCharCode, "fromCodePoint", StringFromCodePoint, "raw", StringRaw ]); diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index e00478a6afaf01..3b139f8eee7c29 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -18,6 +18,7 @@ #include "src/conversions-inl.h" #include "src/factory.h" #include "src/field-index-inl.h" +#include "src/field-type.h" #include "src/handles-inl.h" #include "src/heap/heap-inl.h" #include "src/heap/heap.h" @@ -2724,6 +2725,25 @@ FixedArrayBase* Map::GetInitialElements() { return NULL; } +// static +Handle Map::ReconfigureProperty(Handle map, int modify_index, + PropertyKind new_kind, + PropertyAttributes new_attributes, + Representation new_representation, + Handle new_field_type, + StoreMode store_mode) { + return Reconfigure(map, map->elements_kind(), modify_index, new_kind, + new_attributes, new_representation, new_field_type, + store_mode); +} + +// static +Handle Map::ReconfigureElementsKind(Handle map, + ElementsKind new_elements_kind) { + return Reconfigure(map, new_elements_kind, -1, kData, NONE, + Representation::None(), FieldType::None(map->GetIsolate()), + ALLOW_IN_DESCRIPTOR); +} Object** DescriptorArray::GetKeySlot(int descriptor_number) { DCHECK(descriptor_number < number_of_descriptors()); diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index cc0712a324804a..bb15b9aa14f597 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -2681,6 +2681,16 @@ const char* Representation::Mnemonic() const { } } +bool Map::InstancesNeedRewriting(Map* target) { + int target_number_of_fields = target->NumberOfFields(); + int target_inobject = target->GetInObjectProperties(); + int target_unused = target->unused_property_fields(); + int old_number_of_fields; + + return InstancesNeedRewriting(target, target_number_of_fields, + target_inobject, target_unused, + &old_number_of_fields); +} bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields, int target_inobject, int target_unused, @@ -3141,10 +3151,10 @@ int Map::NumberOfFields() { return result; } - Handle Map::CopyGeneralizeAllRepresentations( - Handle map, int modify_index, StoreMode store_mode, PropertyKind kind, - PropertyAttributes attributes, const char* reason) { + Handle map, ElementsKind elements_kind, int modify_index, + StoreMode store_mode, PropertyKind kind, PropertyAttributes attributes, + const char* reason) { Isolate* isolate = map->GetIsolate(); Handle old_descriptors(map->instance_descriptors(), isolate); int number_of_own_descriptors = map->NumberOfOwnDescriptors(); @@ -3200,6 +3210,7 @@ Handle Map::CopyGeneralizeAllRepresentations( MaybeHandle()); } } + new_map->set_elements_kind(elements_kind); return new_map; } @@ -3437,9 +3448,9 @@ static inline Handle GetFieldType( } } - -// Reconfigures property at |modify_index| with |new_kind|, |new_attributes|, -// |store_mode| and/or |new_representation|/|new_field_type|. +// Reconfigures elements kind to |new_elements_kind| and/or property at +// |modify_index| with |new_kind|, |new_attributes|, |store_mode| and/or +// |new_representation|/|new_field_type|. // If |modify_index| is negative then no properties are reconfigured but the // map is migrated to the up-to-date non-deprecated state. // @@ -3449,6 +3460,7 @@ static inline Handle GetFieldType( // any potential new (partial) version of the type in the transition tree. // To do this, on each rewrite: // - Search the root of the transition tree using FindRootMap. +// - Find/create a |root_map| with requested |new_elements_kind|. // - Find |target_map|, the newest matching version of this map using the // virtually "enhanced" |old_map|'s descriptor array (i.e. whose entry at // |modify_index| is considered to be of |new_kind| and having @@ -3464,12 +3476,13 @@ static inline Handle GetFieldType( // Return it. // - Otherwise, invalidate the outdated transition target from |target_map|, and // replace its transition tree with a new branch for the updated descriptors. -Handle Map::ReconfigureProperty(Handle old_map, int modify_index, - PropertyKind new_kind, - PropertyAttributes new_attributes, - Representation new_representation, - Handle new_field_type, - StoreMode store_mode) { +Handle Map::Reconfigure(Handle old_map, + ElementsKind new_elements_kind, int modify_index, + PropertyKind new_kind, + PropertyAttributes new_attributes, + Representation new_representation, + Handle new_field_type, + StoreMode store_mode) { DCHECK_NE(kAccessor, new_kind); // TODO(ishell): not supported yet. DCHECK(store_mode != FORCE_FIELD || modify_index >= 0); Isolate* isolate = old_map->GetIsolate(); @@ -3484,7 +3497,8 @@ Handle Map::ReconfigureProperty(Handle old_map, int modify_index, // uninitialized value for representation None can be overwritten by both // smi and tagged values. Doubles, however, would require a box allocation. if (modify_index >= 0 && !new_representation.IsNone() && - !new_representation.IsDouble()) { + !new_representation.IsDouble() && + old_map->elements_kind() == new_elements_kind) { PropertyDetails old_details = old_descriptors->GetDetails(modify_index); Representation old_representation = old_details.representation(); @@ -3517,38 +3531,39 @@ Handle Map::ReconfigureProperty(Handle old_map, int modify_index, // Check the state of the root map. Handle root_map(old_map->FindRootMap(), isolate); if (!old_map->EquivalentToForTransition(*root_map)) { - return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode, - new_kind, new_attributes, - "GenAll_NotEquivalent"); + return CopyGeneralizeAllRepresentations( + old_map, new_elements_kind, modify_index, store_mode, new_kind, + new_attributes, "GenAll_NotEquivalent"); } ElementsKind from_kind = root_map->elements_kind(); - ElementsKind to_kind = old_map->elements_kind(); + ElementsKind to_kind = new_elements_kind; // TODO(ishell): Add a test for SLOW_SLOPPY_ARGUMENTS_ELEMENTS. if (from_kind != to_kind && to_kind != DICTIONARY_ELEMENTS && + to_kind != SLOW_STRING_WRAPPER_ELEMENTS && to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS && !(IsTransitionableFastElementsKind(from_kind) && IsMoreGeneralElementsKindTransition(from_kind, to_kind))) { - return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode, - new_kind, new_attributes, - "GenAll_InvalidElementsTransition"); + return CopyGeneralizeAllRepresentations( + old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, + "GenAll_InvalidElementsTransition"); } int root_nof = root_map->NumberOfOwnDescriptors(); if (modify_index >= 0 && modify_index < root_nof) { PropertyDetails old_details = old_descriptors->GetDetails(modify_index); if (old_details.kind() != new_kind || old_details.attributes() != new_attributes) { - return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode, - new_kind, new_attributes, - "GenAll_RootModification1"); + return CopyGeneralizeAllRepresentations( + old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, + "GenAll_RootModification1"); } if ((old_details.type() != DATA && store_mode == FORCE_FIELD) || (old_details.type() == DATA && (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) || !new_representation.fits_into(old_details.representation())))) { - return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode, - new_kind, new_attributes, - "GenAll_RootModification2"); + return CopyGeneralizeAllRepresentations( + old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, + "GenAll_RootModification2"); } } @@ -3602,9 +3617,9 @@ Handle Map::ReconfigureProperty(Handle old_map, int modify_index, if (next_kind == kAccessor && !EqualImmutableValues(old_descriptors->GetValue(i), tmp_descriptors->GetValue(i))) { - return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode, - new_kind, new_attributes, - "GenAll_Incompatible"); + return CopyGeneralizeAllRepresentations( + old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, + "GenAll_Incompatible"); } if (next_location == kField && tmp_details.location() == kDescriptor) break; @@ -3697,9 +3712,9 @@ Handle Map::ReconfigureProperty(Handle old_map, int modify_index, if (next_kind == kAccessor && !EqualImmutableValues(old_descriptors->GetValue(i), tmp_descriptors->GetValue(i))) { - return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode, - new_kind, new_attributes, - "GenAll_Incompatible"); + return CopyGeneralizeAllRepresentations( + old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, + "GenAll_Incompatible"); } DCHECK(!tmp_map->is_deprecated()); target_map = tmp_map; @@ -3930,9 +3945,9 @@ Handle Map::ReconfigureProperty(Handle old_map, int modify_index, // could be inserted regardless of whether transitions array is full or not. if (maybe_transition == NULL && !TransitionArray::CanHaveMoreTransitions(split_map)) { - return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode, - new_kind, new_attributes, - "GenAll_CantHaveMoreTransitions"); + return CopyGeneralizeAllRepresentations( + old_map, to_kind, modify_index, store_mode, new_kind, new_attributes, + "GenAll_CantHaveMoreTransitions"); } old_map->NotifyLeafMapLayoutChange(); @@ -4013,18 +4028,27 @@ MaybeHandle Map::TryUpdate(Handle old_map) { if (root_map == NULL) return MaybeHandle(); // From here on, use the map with correct elements kind as root map. } - int root_nof = root_map->NumberOfOwnDescriptors(); + Map* new_map = root_map->TryReplayPropertyTransitions(*old_map); + if (new_map == nullptr) return MaybeHandle(); + return handle(new_map); +} + +Map* Map::TryReplayPropertyTransitions(Map* old_map) { + DisallowHeapAllocation no_allocation; + DisallowDeoptimization no_deoptimization(GetIsolate()); + + int root_nof = NumberOfOwnDescriptors(); int old_nof = old_map->NumberOfOwnDescriptors(); DescriptorArray* old_descriptors = old_map->instance_descriptors(); - Map* new_map = root_map; + Map* new_map = this; for (int i = root_nof; i < old_nof; ++i) { PropertyDetails old_details = old_descriptors->GetDetails(i); Map* transition = TransitionArray::SearchTransition( new_map, old_details.kind(), old_descriptors->GetKey(i), old_details.attributes()); - if (transition == NULL) return MaybeHandle(); + if (transition == NULL) return nullptr; new_map = transition; DescriptorArray* new_descriptors = new_map->instance_descriptors(); @@ -4032,7 +4056,7 @@ MaybeHandle Map::TryUpdate(Handle old_map) { DCHECK_EQ(old_details.kind(), new_details.kind()); DCHECK_EQ(old_details.attributes(), new_details.attributes()); if (!old_details.representation().fits_into(new_details.representation())) { - return MaybeHandle(); + return nullptr; } switch (new_details.type()) { case DATA: { @@ -4040,20 +4064,20 @@ MaybeHandle Map::TryUpdate(Handle old_map) { // Cleared field types need special treatment. They represent lost // knowledge, so we must first generalize the new_type to "Any". if (FieldTypeIsCleared(new_details.representation(), new_type)) { - return MaybeHandle(); + return nullptr; } PropertyType old_property_type = old_details.type(); if (old_property_type == DATA) { FieldType* old_type = old_descriptors->GetFieldType(i); if (FieldTypeIsCleared(old_details.representation(), old_type) || !old_type->NowIs(new_type)) { - return MaybeHandle(); + return nullptr; } } else { DCHECK(old_property_type == DATA_CONSTANT); Object* old_value = old_descriptors->GetValue(i); if (!new_type->NowContains(old_value)) { - return MaybeHandle(); + return nullptr; } } break; @@ -4071,14 +4095,14 @@ MaybeHandle Map::TryUpdate(Handle old_map) { Object* old_value = old_descriptors->GetValue(i); Object* new_value = new_descriptors->GetValue(i); if (old_details.location() == kField || old_value != new_value) { - return MaybeHandle(); + return nullptr; } break; } } } - if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle(); - return handle(new_map); + if (new_map->NumberOfOwnDescriptors() != old_nof) return nullptr; + return new_map; } @@ -4736,17 +4760,30 @@ static bool ContainsMap(MapHandleList* maps, Map* map) { return false; } +Map* Map::FindElementsKindTransitionedMap(MapHandleList* candidates) { + DisallowHeapAllocation no_allocation; + DisallowDeoptimization no_deoptimization(GetIsolate()); -Handle Map::FindTransitionedMap(Handle map, - MapHandleList* candidates) { - ElementsKind kind = map->elements_kind(); + ElementsKind kind = elements_kind(); bool packed = IsFastPackedElementsKind(kind); Map* transition = nullptr; if (IsTransitionableFastElementsKind(kind)) { - for (Map* current = map->ElementsTransitionMap(); - current != nullptr && current->has_fast_elements(); - current = current->ElementsTransitionMap()) { + // Check the state of the root map. + Map* root_map = FindRootMap(); + if (!EquivalentToForTransition(root_map)) return nullptr; + root_map = root_map->LookupElementsTransitionMap(kind); + DCHECK_NOT_NULL(root_map); + // Starting from the next existing elements kind transition try to + // replay the property transitions that does not involve instance rewriting + // (ElementsTransitionAndStoreStub does not support that). + for (root_map = root_map->ElementsTransitionMap(); + root_map != nullptr && root_map->has_fast_elements(); + root_map = root_map->ElementsTransitionMap()) { + Map* current = root_map->TryReplayPropertyTransitions(this); + if (current == nullptr) continue; + if (InstancesNeedRewriting(current)) continue; + if (ContainsMap(candidates, current) && (packed || !IsFastPackedElementsKind(current->elements_kind()))) { transition = current; @@ -4754,11 +4791,14 @@ Handle Map::FindTransitionedMap(Handle map, } } } - return transition == nullptr ? Handle() : handle(transition); + return transition; } static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) { + // Ensure we are requested to search elements kind transition "near the root". + DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(), + map->NumberOfOwnDescriptors()); Map* current_map = map; ElementsKind kind = map->elements_kind(); @@ -4889,7 +4929,7 @@ Handle Map::TransitionElementsTo(Handle map, return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION); } - return Map::AsElementsKind(map, to_kind); + return Map::ReconfigureElementsKind(map, to_kind); } @@ -5215,7 +5255,7 @@ void JSObject::AllocateStorageForMap(Handle object, Handle map) { } else { TransitionElementsKind(object, to_kind); } - map = Map::AsElementsKind(map, to_kind); + map = Map::ReconfigureElementsKind(map, to_kind); } JSObject::MigrateToMap(object, map); } @@ -9563,6 +9603,10 @@ Handle Map::CopyAsElementsKind(Handle map, ElementsKind kind, TransitionFlag flag) { Map* maybe_elements_transition_map = NULL; if (flag == INSERT_TRANSITION) { + // Ensure we are requested to add elements kind transition "near the root". + DCHECK_EQ(map->FindRootMap()->NumberOfOwnDescriptors(), + map->NumberOfOwnDescriptors()); + maybe_elements_transition_map = map->ElementsTransitionMap(); DCHECK(maybe_elements_transition_map == NULL || (maybe_elements_transition_map->elements_kind() == @@ -9890,7 +9934,7 @@ Handle Map::ReconfigureExistingProperty(Handle map, int descriptor, // There is no benefit from reconstructing transition tree for maps without // back pointers. return CopyGeneralizeAllRepresentations( - map, descriptor, FORCE_FIELD, kind, attributes, + map, map->elements_kind(), descriptor, FORCE_FIELD, kind, attributes, "GenAll_AttributesMismatchProtoMap"); } diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index f5e35c359674b0..4a8a55764f9a89 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -5773,6 +5773,7 @@ class Map: public HeapObject { int NumberOfFields(); // TODO(ishell): candidate with JSObject::MigrateToMap(). + bool InstancesNeedRewriting(Map* target); bool InstancesNeedRewriting(Map* target, int target_number_of_fields, int target_inobject, int target_unused, int* old_number_of_fields); @@ -5784,15 +5785,14 @@ class Map: public HeapObject { static void GeneralizeFieldType(Handle map, int modify_index, Representation new_representation, Handle new_field_type); - static Handle ReconfigureProperty(Handle map, int modify_index, - PropertyKind new_kind, - PropertyAttributes new_attributes, - Representation new_representation, - Handle new_field_type, - StoreMode store_mode); - static Handle CopyGeneralizeAllRepresentations( - Handle map, int modify_index, StoreMode store_mode, - PropertyKind kind, PropertyAttributes attributes, const char* reason); + + static inline Handle ReconfigureProperty( + Handle map, int modify_index, PropertyKind new_kind, + PropertyAttributes new_attributes, Representation new_representation, + Handle new_field_type, StoreMode store_mode); + + static inline Handle ReconfigureElementsKind( + Handle map, ElementsKind new_elements_kind); static Handle PrepareForDataProperty(Handle old_map, int descriptor_number, @@ -6022,17 +6022,10 @@ class Map: public HeapObject { // Computes a hash value for this map, to be used in HashTables and such. int Hash(); - // Returns the map that this map transitions to if its elements_kind - // is changed to |elements_kind|, or NULL if no such map is cached yet. - // |safe_to_add_transitions| is set to false if adding transitions is not - // allowed. - Map* LookupElementsTransitionMap(ElementsKind elements_kind); - // Returns the transitioned map for this map with the most generic - // elements_kind that's found in |candidates|, or null handle if no match is + // elements_kind that's found in |candidates|, or |nullptr| if no match is // found at all. - static Handle FindTransitionedMap(Handle map, - MapHandleList* candidates); + Map* FindElementsKindTransitionedMap(MapHandleList* candidates); inline bool CanTransition(); @@ -6191,6 +6184,17 @@ class Map: public HeapObject { Handle full_layout_descriptor); private: + // Returns the map that this (root) map transitions to if its elements_kind + // is changed to |elements_kind|, or |nullptr| if no such map is cached yet. + Map* LookupElementsTransitionMap(ElementsKind elements_kind); + + // Tries to replay property transitions starting from this (root) map using + // the descriptor array of the |map|. The |root_map| is expected to have + // proper elements kind and therefore elements kinds transitions are not + // taken by this function. Returns |nullptr| if matching transition map is + // not found. + Map* TryReplayPropertyTransitions(Map* map); + static void ConnectTransition(Handle parent, Handle child, Handle name, SimpleTransitionFlag flag); @@ -6227,6 +6231,19 @@ class Map: public HeapObject { static Handle CopyNormalized(Handle map, PropertyNormalizationMode mode); + static Handle Reconfigure(Handle map, + ElementsKind new_elements_kind, + int modify_index, PropertyKind new_kind, + PropertyAttributes new_attributes, + Representation new_representation, + Handle new_field_type, + StoreMode store_mode); + + static Handle CopyGeneralizeAllRepresentations( + Handle map, ElementsKind elements_kind, int modify_index, + StoreMode store_mode, PropertyKind kind, PropertyAttributes attributes, + const char* reason); + // Fires when the layout of an object with a leaf map changes. // This includes adding transitions to the leaf map or changing // the descriptor array. diff --git a/deps/v8/test/cctest/test-field-type-tracking.cc b/deps/v8/test/cctest/test-field-type-tracking.cc index cee3600314fe52..f05e0951a3fee9 100644 --- a/deps/v8/test/cctest/test-field-type-tracking.cc +++ b/deps/v8/test/cctest/test-field-type-tracking.cc @@ -86,6 +86,7 @@ static bool EqualDetails(DescriptorArray* descriptors, int descriptor, class Expectations { static const int MAX_PROPERTIES = 10; Isolate* isolate_; + ElementsKind elements_kind_; PropertyType types_[MAX_PROPERTIES]; PropertyAttributes attributes_[MAX_PROPERTIES]; Representation representations_[MAX_PROPERTIES]; @@ -97,8 +98,15 @@ class Expectations { int number_of_properties_; public: + explicit Expectations(Isolate* isolate, ElementsKind elements_kind) + : isolate_(isolate), + elements_kind_(elements_kind), + number_of_properties_(0) {} + explicit Expectations(Isolate* isolate) - : isolate_(isolate), number_of_properties_(0) {} + : Expectations( + isolate, + isolate->object_function()->initial_map()->elements_kind()) {} void Init(int index, PropertyType type, PropertyAttributes attributes, Representation representation, Handle value) { @@ -143,6 +151,10 @@ class Expectations { os << "\n"; } + void SetElementsKind(ElementsKind elements_kind) { + elements_kind_ = elements_kind; + } + Handle GetFieldType(int index) { CHECK(index < MAX_PROPERTIES); CHECK(types_[index] == DATA || types_[index] == ACCESSOR); @@ -252,6 +264,7 @@ class Expectations { } bool Check(Map* map, int expected_nof) const { + CHECK_EQ(elements_kind_, map->elements_kind()); CHECK(number_of_properties_ <= MAX_PROPERTIES); CHECK_EQ(expected_nof, map->NumberOfOwnDescriptors()); CHECK(!map->is_dictionary_map()); @@ -279,6 +292,13 @@ class Expectations { // given |map|. // + Handle AsElementsKind(Handle map, ElementsKind elements_kind) { + elements_kind_ = elements_kind; + map = Map::AsElementsKind(map, elements_kind); + CHECK_EQ(elements_kind_, map->elements_kind()); + return map; + } + Handle AddDataField(Handle map, PropertyAttributes attributes, Representation representation, Handle heap_type) { @@ -1524,6 +1544,271 @@ TEST(ReconfigureDataFieldAttribute_AccConstantToDataFieldAfterTargetMap) { } +//////////////////////////////////////////////////////////////////////////////// +// A set of tests for elements kind reconfiguration case. +// + +// This test ensures that representation/field type generalization is correctly +// propagated from one branch of transition tree (|map2) to another (|map|). +// +// + - p0 - p1 - p2A - p3 - p4: |map| +// | +// ek +// | +// {} - p0 - p1 - p2B - p3 - p4: |map2| +// +// where "p2A" and "p2B" differ only in the representation/field type. +// +static void TestReconfigureElementsKind_GeneralizeRepresentation( + Representation from_representation, Handle from_type, + Representation to_representation, Handle to_type, + Representation expected_representation, Handle expected_type) { + Isolate* isolate = CcTest::i_isolate(); + + Expectations expectations(isolate, FAST_SMI_ELEMENTS); + + // Create a map, add required properties to it and initialize expectations. + Handle initial_map = Map::Create(isolate, 0); + initial_map->set_elements_kind(FAST_SMI_ELEMENTS); + + Handle map = initial_map; + map = expectations.AsElementsKind(map, FAST_ELEMENTS); + for (int i = 0; i < kPropCount; i++) { + map = expectations.AddDataField(map, NONE, from_representation, from_type); + } + CHECK(!map->is_deprecated()); + CHECK(map->is_stable()); + CHECK(expectations.Check(*map)); + + // Create another branch in transition tree (property at index |kDiffProp| + // has different representatio/field type), initialize expectations. + const int kDiffProp = kPropCount / 2; + Expectations expectations2(isolate, FAST_SMI_ELEMENTS); + + Handle map2 = initial_map; + for (int i = 0; i < kPropCount; i++) { + if (i == kDiffProp) { + map2 = expectations2.AddDataField(map2, NONE, to_representation, to_type); + } else { + map2 = expectations2.AddDataField(map2, NONE, from_representation, + from_type); + } + } + CHECK(!map2->is_deprecated()); + CHECK(map2->is_stable()); + CHECK(expectations2.Check(*map2)); + + Zone zone; + Handle field_owner(map->FindFieldOwner(kDiffProp), isolate); + CompilationInfo info("testing", isolate, &zone); + CHECK(!info.dependencies()->HasAborted()); + info.dependencies()->AssumeFieldType(field_owner); + + // Reconfigure elements kinds of |map2|, which should generalize + // representations in |map|. + Handle new_map = Map::ReconfigureElementsKind(map2, FAST_ELEMENTS); + + // |map2| should be left unchanged but marked unstable. + CHECK(!map2->is_stable()); + CHECK(!map2->is_deprecated()); + CHECK_NE(*map2, *new_map); + CHECK(expectations2.Check(*map2)); + + // |map| should be deprecated and |new_map| should match new expectations. + expectations.SetDataField(kDiffProp, expected_representation, expected_type); + + CHECK(map->is_deprecated()); + CHECK(!info.dependencies()->HasAborted()); + info.dependencies()->Rollback(); // Properly cleanup compilation info. + CHECK_NE(*map, *new_map); + + CHECK(!new_map->is_deprecated()); + CHECK(expectations.Check(*new_map)); + + // Update deprecated |map|, it should become |new_map|. + Handle updated_map = Map::Update(map); + CHECK_EQ(*new_map, *updated_map); + + // Ensure Map::FindElementsKindTransitionedMap() is able to find the + // transitioned map. + { + MapHandleList map_list; + map_list.Add(updated_map); + Map* transitioned_map = map2->FindElementsKindTransitionedMap(&map_list); + CHECK_EQ(*updated_map, transitioned_map); + } +} + +// This test ensures that trivial representation/field type generalization +// (from HeapObject to HeapObject) is correctly propagated from one branch of +// transition tree (|map2|) to another (|map|). +// +// + - p0 - p1 - p2A - p3 - p4: |map| +// | +// ek +// | +// {} - p0 - p1 - p2B - p3 - p4: |map2| +// +// where "p2A" and "p2B" differ only in the representation/field type. +// +static void TestReconfigureElementsKind_GeneralizeRepresentationTrivial( + Representation from_representation, Handle from_type, + Representation to_representation, Handle to_type, + Representation expected_representation, Handle expected_type, + bool expected_field_type_dependency = true) { + Isolate* isolate = CcTest::i_isolate(); + + Expectations expectations(isolate, FAST_SMI_ELEMENTS); + + // Create a map, add required properties to it and initialize expectations. + Handle initial_map = Map::Create(isolate, 0); + initial_map->set_elements_kind(FAST_SMI_ELEMENTS); + + Handle map = initial_map; + map = expectations.AsElementsKind(map, FAST_ELEMENTS); + for (int i = 0; i < kPropCount; i++) { + map = expectations.AddDataField(map, NONE, from_representation, from_type); + } + CHECK(!map->is_deprecated()); + CHECK(map->is_stable()); + CHECK(expectations.Check(*map)); + + // Create another branch in transition tree (property at index |kDiffProp| + // has different attributes), initialize expectations. + const int kDiffProp = kPropCount / 2; + Expectations expectations2(isolate, FAST_SMI_ELEMENTS); + + Handle map2 = initial_map; + for (int i = 0; i < kPropCount; i++) { + if (i == kDiffProp) { + map2 = expectations2.AddDataField(map2, NONE, to_representation, to_type); + } else { + map2 = expectations2.AddDataField(map2, NONE, from_representation, + from_type); + } + } + CHECK(!map2->is_deprecated()); + CHECK(map2->is_stable()); + CHECK(expectations2.Check(*map2)); + + Zone zone; + Handle field_owner(map->FindFieldOwner(kDiffProp), isolate); + CompilationInfo info("testing", isolate, &zone); + CHECK(!info.dependencies()->HasAborted()); + info.dependencies()->AssumeFieldType(field_owner); + + // Reconfigure elements kinds of |map2|, which should generalize + // representations in |map|. + Handle new_map = Map::ReconfigureElementsKind(map2, FAST_ELEMENTS); + + // |map2| should be left unchanged but marked unstable. + CHECK(!map2->is_stable()); + CHECK(!map2->is_deprecated()); + CHECK_NE(*map2, *new_map); + CHECK(expectations2.Check(*map2)); + + // In trivial case |map| should be returned as a result of the elements + // kind reconfiguration, respective field types should be generalized and + // respective code dependencies should be invalidated. |map| should be NOT + // deprecated and it should match new expectations. + expectations.SetDataField(kDiffProp, expected_representation, expected_type); + CHECK(!map->is_deprecated()); + CHECK_EQ(*map, *new_map); + CHECK_EQ(expected_field_type_dependency, info.dependencies()->HasAborted()); + info.dependencies()->Rollback(); // Properly cleanup compilation info. + + CHECK(!new_map->is_deprecated()); + CHECK(expectations.Check(*new_map)); + + Handle updated_map = Map::Update(map); + CHECK_EQ(*new_map, *updated_map); + + // Ensure Map::FindElementsKindTransitionedMap() is able to find the + // transitioned map. + { + MapHandleList map_list; + map_list.Add(updated_map); + Map* transitioned_map = map2->FindElementsKindTransitionedMap(&map_list); + CHECK_EQ(*updated_map, transitioned_map); + } +} + +TEST(ReconfigureElementsKind_GeneralizeRepresentationSmiToDouble) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Handle any_type = FieldType::Any(isolate); + + TestReconfigureElementsKind_GeneralizeRepresentation( + Representation::Smi(), any_type, Representation::Double(), any_type, + Representation::Double(), any_type); +} + +TEST(ReconfigureElementsKind_GeneralizeRepresentationSmiToTagged) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Handle any_type = FieldType::Any(isolate); + Handle value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); + + TestReconfigureElementsKind_GeneralizeRepresentation( + Representation::Smi(), any_type, Representation::HeapObject(), value_type, + Representation::Tagged(), any_type); +} + +TEST(ReconfigureElementsKind_GeneralizeRepresentationDoubleToTagged) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Handle any_type = FieldType::Any(isolate); + Handle value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); + + TestReconfigureElementsKind_GeneralizeRepresentation( + Representation::Double(), any_type, Representation::HeapObject(), + value_type, Representation::Tagged(), any_type); +} + +TEST(ReconfigureElementsKind_GeneralizeRepresentationHeapObjToHeapObj) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Handle any_type = FieldType::Any(isolate); + + Handle current_type = + FieldType::Class(Map::Create(isolate, 0), isolate); + + Handle new_type = + FieldType::Class(Map::Create(isolate, 0), isolate); + + Handle expected_type = any_type; + + TestReconfigureElementsKind_GeneralizeRepresentationTrivial( + Representation::HeapObject(), current_type, Representation::HeapObject(), + new_type, Representation::HeapObject(), expected_type); + current_type = expected_type; + + new_type = FieldType::Class(Map::Create(isolate, 0), isolate); + + TestReconfigureElementsKind_GeneralizeRepresentationTrivial( + Representation::HeapObject(), any_type, Representation::HeapObject(), + new_type, Representation::HeapObject(), any_type, false); +} + +TEST(ReconfigureElementsKind_GeneralizeRepresentationHeapObjectToTagged) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Handle any_type = FieldType::Any(isolate); + Handle value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); + + TestReconfigureElementsKind_GeneralizeRepresentation( + Representation::HeapObject(), value_type, Representation::Smi(), any_type, + Representation::Tagged(), any_type); +} + //////////////////////////////////////////////////////////////////////////////// // A set of tests checking split map deprecation. // @@ -1640,15 +1925,16 @@ static void TestGeneralizeRepresentationWithSpecialTransition( CHECK(map->is_stable()); CHECK(expectations.Check(*map)); + Expectations expectations2 = expectations; + // Apply some special transition to |map|. CHECK(map->owns_descriptors()); - Handle map2 = config.Transition(map); + Handle map2 = config.Transition(map, expectations2); // |map| should still match expectations. CHECK(!map->is_deprecated()); CHECK(expectations.Check(*map)); - Expectations expectations2 = expectations; if (config.generalizes_representations()) { for (int i = 0; i < kPropCount; i++) { expectations2.GeneralizeRepresentation(i); @@ -1720,13 +2006,15 @@ TEST(ElementsKindTransitionFromMapOwningDescriptor) { FieldType::Class(Map::Create(isolate, 0), isolate); struct TestConfig { - Handle Transition(Handle map) { - return Map::CopyAsElementsKind(map, DICTIONARY_ELEMENTS, - INSERT_TRANSITION); + Handle Transition(Handle map, Expectations& expectations) { + Handle frozen_symbol(map->GetHeap()->frozen_symbol()); + expectations.SetElementsKind(DICTIONARY_ELEMENTS); + return Map::CopyForPreventExtensions(map, NONE, frozen_symbol, + "CopyForPreventExtensions"); } // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed. bool generalizes_representations() const { return false; } - bool is_non_equevalent_transition() const { return false; } + bool is_non_equevalent_transition() const { return true; } }; TestConfig config; TestGeneralizeRepresentationWithSpecialTransition( @@ -1744,7 +2032,7 @@ TEST(ElementsKindTransitionFromMapNotOwningDescriptor) { FieldType::Class(Map::Create(isolate, 0), isolate); struct TestConfig { - Handle Transition(Handle map) { + Handle Transition(Handle map, Expectations& expectations) { Isolate* isolate = CcTest::i_isolate(); Handle any_type = FieldType::Any(isolate); @@ -1756,12 +2044,14 @@ TEST(ElementsKindTransitionFromMapNotOwningDescriptor) { .ToHandleChecked(); CHECK(!map->owns_descriptors()); - return Map::CopyAsElementsKind(map, DICTIONARY_ELEMENTS, - INSERT_TRANSITION); + Handle frozen_symbol(map->GetHeap()->frozen_symbol()); + expectations.SetElementsKind(DICTIONARY_ELEMENTS); + return Map::CopyForPreventExtensions(map, NONE, frozen_symbol, + "CopyForPreventExtensions"); } // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed. bool generalizes_representations() const { return false; } - bool is_non_equevalent_transition() const { return false; } + bool is_non_equevalent_transition() const { return true; } }; TestConfig config; TestGeneralizeRepresentationWithSpecialTransition( @@ -1779,7 +2069,7 @@ TEST(ForObservedTransitionFromMapOwningDescriptor) { FieldType::Class(Map::Create(isolate, 0), isolate); struct TestConfig { - Handle Transition(Handle map) { + Handle Transition(Handle map, Expectations& expectations) { return Map::CopyForObserved(map); } // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed. @@ -1802,7 +2092,7 @@ TEST(ForObservedTransitionFromMapNotOwningDescriptor) { FieldType::Class(Map::Create(isolate, 0), isolate); struct TestConfig { - Handle Transition(Handle map) { + Handle Transition(Handle map, Expectations& expectations) { Isolate* isolate = CcTest::i_isolate(); Handle any_type = FieldType::Any(isolate); @@ -1845,7 +2135,7 @@ TEST(PrototypeTransitionFromMapOwningDescriptor) { prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0)); } - Handle Transition(Handle map) { + Handle Transition(Handle map, Expectations& expectations) { return Map::TransitionToPrototype(map, prototype_, REGULAR_PROTOTYPE); } // TODO(ishell): remove once IS_PROTO_TRANS_ISSUE_FIXED is removed. @@ -1879,7 +2169,7 @@ TEST(PrototypeTransitionFromMapNotOwningDescriptor) { prototype_ = factory->NewJSObjectFromMap(Map::Create(isolate, 0)); } - Handle Transition(Handle map) { + Handle Transition(Handle map, Expectations& expectations) { Isolate* isolate = CcTest::i_isolate(); Handle any_type = FieldType::Any(isolate); diff --git a/deps/v8/test/cctest/test-strings.cc b/deps/v8/test/cctest/test-strings.cc index e992f33c8bc8aa..770042d8148510 100644 --- a/deps/v8/test/cctest/test-strings.cc +++ b/deps/v8/test/cctest/test-strings.cc @@ -1508,3 +1508,25 @@ TEST(FormatMessage) { "'arg0' returned for property 'arg1' of object 'arg2' is not a function"); CHECK(String::Equals(result, expected)); } + +TEST(Regress609831) { + CcTest::InitializeVM(); + LocalContext context; + Isolate* isolate = CcTest::i_isolate(); + { + HandleScope scope(isolate); + v8::Local result = CompileRun( + "String.fromCharCode(32, 32, 32, 32, 32, " + "32, 32, 32, 32, 32, 32, 32, 32, 32, 32, " + "32, 32, 32, 32, 32, 32, 32, 32, 32, 32)"); + CHECK(v8::Utils::OpenHandle(*result)->IsSeqOneByteString()); + } + { + HandleScope scope(isolate); + v8::Local result = CompileRun( + "String.fromCharCode(432, 432, 432, 432, 432, " + "432, 432, 432, 432, 432, 432, 432, 432, 432, " + "432, 432, 432, 432, 432, 432, 432, 432, 432)"); + CHECK(v8::Utils::OpenHandle(*result)->IsSeqTwoByteString()); + } +} diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-617524.js b/deps/v8/test/mjsunit/regress/regress-crbug-617524.js new file mode 100644 index 00000000000000..b32eeef5f4d324 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-617524.js @@ -0,0 +1,18 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-gc --always-opt + +function f(a,b,c) { + a.a = b; + a[1] = c; + return a; +} + +f(new Array(5),.5,0); +var o1 = f(new Array(5),0,.5); +gc(); +var o2 = f(new Array(5),0,0); +var o3 = f(new Array(5),0); +assertEquals(0, o3.a); diff --git a/deps/v8/test/mjsunit/regress/regress-seqstrsetchar-ex2.js b/deps/v8/test/mjsunit/regress/regress-seqstrsetchar-ex2.js deleted file mode 100644 index 6a5ba9195ce983..00000000000000 --- a/deps/v8/test/mjsunit/regress/regress-seqstrsetchar-ex2.js +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2013 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Flags: --allow-natives-syntax - -String.fromCharCode(0xFFF, 0xFFF); -String.fromCharCode(0x7C, 0x7C); -%OptimizeFunctionOnNextCall(String.fromCharCode); -String.fromCharCode(0x7C, 0x7C); -String.fromCharCode(0xFFF, 0xFFF); diff --git a/deps/v8/test/mjsunit/regress/regress-v8-5009.js b/deps/v8/test/mjsunit/regress/regress-v8-5009.js new file mode 100644 index 00000000000000..f4995488b335a7 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-v8-5009.js @@ -0,0 +1,61 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function fn1() { +} + +function fn2() { +} + +function fn3() { +} + +function create(id) { + // Just some `FunctionTemplate` to hang on + var o = new version(); + + o.id = id; + o[0] = null; + + return o; +} + +function setM1(o) { + o.m1 = fn1; +} + +function setM2(o) { + o.m2 = fn2; +} + +function setAltM2(o) { + // Failing StoreIC happens here + o.m2 = fn3; +} + +function setAltM1(o) { + o.m1 = null; +} + +function test(o) { + o.m2(); + o.m1(); +} + +var p0 = create(0); +var p1 = create(1); +var p2 = create(2); + +setM1(p0); +setM1(p1); +setM1(p2); + +setM2(p0); +setAltM2(p0); +setAltM1(p0); + +setAltM2(p1); + +setAltM2(p2); +test(p2); diff --git a/deps/v8/test/mjsunit/string-fromcharcode.js b/deps/v8/test/mjsunit/string-fromcharcode.js index ad3f7a96fb1403..ac51682b72cfc7 100644 --- a/deps/v8/test/mjsunit/string-fromcharcode.js +++ b/deps/v8/test/mjsunit/string-fromcharcode.js @@ -103,11 +103,6 @@ for (var i = 0; i < 10; i++) { test(i); } -assertEquals("AAAA", String.fromCharCode(65, 65, 65, 65)); -assertEquals("AAAA", String.fromCharCode(65, 65, 65, 65)); -%OptimizeFunctionOnNextCall(String.fromCharCode); -assertEquals("AAAA", String.fromCharCode(65, 65, 65, 65)); - // Test the custom IC works correctly when the map changes. for (var i = 0; i < 10; i++) { var expected = (i < 5) ? " " : 42;