diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 28f15a4e745f52..1213993dad447a 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 4 #define V8_MINOR_VERSION 9 #define V8_BUILD_NUMBER 385 -#define V8_PATCH_LEVEL 27 +#define V8_PATCH_LEVEL 35 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index d9ad17cc54712b..86d65c33db738a 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -2678,10 +2678,10 @@ class V8_EXPORT Object : public Value { V8_DEPRECATED("Use CreateDataProperty / DefineOwnProperty", bool ForceSet(Local key, Local value, PropertyAttribute attribs = None)); - V8_DEPRECATED("Use CreateDataProperty / DefineOwnProperty", - Maybe ForceSet(Local context, Local key, - Local value, - PropertyAttribute attribs = None)); + V8_DEPRECATE_SOON("Use CreateDataProperty / DefineOwnProperty", + Maybe ForceSet(Local context, + Local key, Local value, + PropertyAttribute attribs = None)); V8_DEPRECATE_SOON("Use maybe version", Local Get(Local key)); V8_WARN_UNUSED_RESULT MaybeLocal Get(Local context, diff --git a/deps/v8/src/arm/deoptimizer-arm.cc b/deps/v8/src/arm/deoptimizer-arm.cc index 38635ea3cf9380..e4fc2138fc1949 100644 --- a/deps/v8/src/arm/deoptimizer-arm.cc +++ b/deps/v8/src/arm/deoptimizer-arm.cc @@ -288,14 +288,11 @@ void Deoptimizer::TableEntryGenerator::Generate() { __ CheckFor32DRegs(ip); __ ldr(r1, MemOperand(r0, Deoptimizer::input_offset())); - int src_offset = FrameDescription::double_registers_offset(); - for (int i = 0; i < DwVfpRegister::kMaxNumRegisters; ++i) { - if (i == kDoubleRegZero.code()) continue; - if (i == kScratchDoubleReg.code()) continue; - - const DwVfpRegister reg = DwVfpRegister::from_code(i); - __ vldr(reg, r1, src_offset, i < 16 ? al : ne); - src_offset += kDoubleSize; + for (int i = 0; i < config->num_allocatable_double_registers(); ++i) { + int code = config->GetAllocatableDoubleCode(i); + DwVfpRegister reg = DwVfpRegister::from_code(code); + int src_offset = code * kDoubleSize + double_regs_offset; + __ vldr(reg, r1, src_offset); } // Push state, pc, and continuation from the last output frame. diff --git a/deps/v8/src/arm64/deoptimizer-arm64.cc b/deps/v8/src/arm64/deoptimizer-arm64.cc index 118c5dfa8dcd74..081405037adf00 100644 --- a/deps/v8/src/arm64/deoptimizer-arm64.cc +++ b/deps/v8/src/arm64/deoptimizer-arm64.cc @@ -191,11 +191,13 @@ void Deoptimizer::TableEntryGenerator::Generate() { } // Copy FP registers to the input frame. + CPURegList copy_fp_to_input = saved_fp_registers; for (int i = 0; i < saved_fp_registers.Count(); i++) { - int dst_offset = FrameDescription::double_registers_offset() + - (i * kDoubleSize); int src_offset = kFPRegistersOffset + (i * kDoubleSize); __ Peek(x2, src_offset); + CPURegister reg = copy_fp_to_input.PopLowestIndex(); + int dst_offset = FrameDescription::double_registers_offset() + + (reg.code() * kDoubleSize); __ Str(x2, MemOperand(x1, dst_offset)); } @@ -264,11 +266,11 @@ void Deoptimizer::TableEntryGenerator::Generate() { DCHECK(!saved_fp_registers.IncludesAliasOf(crankshaft_fp_scratch) && !saved_fp_registers.IncludesAliasOf(fp_zero) && !saved_fp_registers.IncludesAliasOf(fp_scratch)); - int src_offset = FrameDescription::double_registers_offset(); while (!saved_fp_registers.IsEmpty()) { const CPURegister reg = saved_fp_registers.PopLowestIndex(); + int src_offset = FrameDescription::double_registers_offset() + + (reg.code() * kDoubleSize); __ Ldr(reg, MemOperand(x1, src_offset)); - src_offset += kDoubleSize; } // Push state from the last output frame. diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index 34b370fe664fe4..2df9503302fef6 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -208,6 +208,7 @@ inline bool PrototypeHasNoElements(PrototypeIterator* iter) { JSObject* current = iter->GetCurrent(); if (current->IsAccessCheckNeeded()) return false; if (current->HasIndexedInterceptor()) return false; + if (current->IsJSValue()) return false; if (current->elements()->length() != 0) return false; } return true; @@ -232,6 +233,41 @@ inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, } +inline bool HasSimpleElements(JSObject* current) { + if (current->IsAccessCheckNeeded()) return false; + if (current->HasIndexedInterceptor()) return false; + if (current->IsJSValue()) return false; + if (current->GetElementsAccessor()->HasAccessors(current)) return false; + return true; +} + + +inline bool HasOnlySimpleReceiverElements(Isolate* isolate, + JSReceiver* receiver) { + // Check that we have no accessors on the receiver's elements. + JSObject* object = JSObject::cast(receiver); + if (!HasSimpleElements(object)) return false; + // Check that ther are not elements on the prototype. + DisallowHeapAllocation no_gc; + PrototypeIterator iter(isolate, receiver); + return PrototypeHasNoElements(&iter); +} + + +inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) { + // Check that ther are not elements on the prototype. + DisallowHeapAllocation no_gc; + PrototypeIterator iter(isolate, receiver, + PrototypeIterator::START_AT_RECEIVER); + for (; !iter.IsAtEnd(); iter.Advance()) { + if (iter.GetCurrent()->IsJSProxy()) return false; + JSObject* current = iter.GetCurrent(); + if (!HasSimpleElements(current)) return false; + } + return true; +} + + // Returns empty handle if not applicable. MUST_USE_RESULT inline MaybeHandle EnsureJSArrayWithWritableFastElements( @@ -1013,9 +1049,10 @@ bool IterateElements(Isolate* isolate, Handle receiver, if (!val->ToUint32(&length)) { length = 0; } + return IterateElementsSlow(isolate, receiver, length, visitor); } - if (!(receiver->IsJSArray() || receiver->IsJSTypedArray())) { + if (!HasOnlySimpleElements(isolate, *receiver)) { // For classes which are not known to be safe to access via elements alone, // use the slow case. return IterateElementsSlow(isolate, receiver, length, visitor); @@ -1031,7 +1068,7 @@ bool IterateElements(Isolate* isolate, Handle receiver, // to check the prototype for missing elements. Handle elements(FixedArray::cast(array->elements())); int fast_length = static_cast(length); - DCHECK(fast_length <= elements->length()); + DCHECK_LE(fast_length, elements->length()); for (int j = 0; j < fast_length; j++) { HandleScope loop_scope(isolate); Handle element_value(elements->get(j), isolate); @@ -1090,14 +1127,6 @@ bool IterateElements(Isolate* isolate, Handle receiver, break; } case DICTIONARY_ELEMENTS: { - // CollectElementIndices() can't be called when there's a JSProxy - // on the prototype chain. - for (PrototypeIterator iter(isolate, array); !iter.IsAtEnd(); - iter.Advance()) { - if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { - return IterateElementsSlow(isolate, array, length, visitor); - } - } Handle dict(array->element_dictionary()); List indices(dict->Capacity() / 2); // Collect all indices in the object and the prototypes less @@ -1187,7 +1216,6 @@ bool IterateElements(Isolate* isolate, Handle receiver, bool HasConcatSpreadableModifier(Isolate* isolate, Handle obj) { - DCHECK(isolate->IsFastArrayConstructorPrototypeChainIntact()); if (!FLAG_harmony_concat_spreadable) return false; Handle key(isolate->factory()->is_concat_spreadable_symbol()); Maybe maybe = JSReceiver::HasProperty(obj, key); @@ -1232,17 +1260,14 @@ Object* Slow_ArrayConcat(Arguments* args, Isolate* isolate) { length_estimate = static_cast(array->length()->Number()); if (length_estimate != 0) { ElementsKind array_kind = - GetPackedElementsKind(array->map()->elements_kind()); + GetPackedElementsKind(array->GetElementsKind()); kind = GetMoreGeneralElementsKind(kind, array_kind); } element_estimate = EstimateElementCount(array); } else { if (obj->IsHeapObject()) { - if (obj->IsNumber()) { - kind = GetMoreGeneralElementsKind(kind, FAST_DOUBLE_ELEMENTS); - } else { - kind = GetMoreGeneralElementsKind(kind, FAST_ELEMENTS); - } + kind = GetMoreGeneralElementsKind( + kind, obj->IsNumber() ? FAST_DOUBLE_ELEMENTS : FAST_ELEMENTS); } length_estimate = 1; element_estimate = 1; @@ -1284,7 +1309,7 @@ Object* Slow_ArrayConcat(Arguments* args, Isolate* isolate) { } else { JSArray* array = JSArray::cast(*obj); uint32_t length = static_cast(array->length()->Number()); - switch (array->map()->elements_kind()) { + switch (array->GetElementsKind()) { case FAST_HOLEY_DOUBLE_ELEMENTS: case FAST_DOUBLE_ELEMENTS: { // Empty array is FixedArray but not FixedDoubleArray. @@ -1335,14 +1360,7 @@ Object* Slow_ArrayConcat(Arguments* args, Isolate* isolate) { } } if (!failure) { - Handle array = isolate->factory()->NewJSArray(0); - Smi* length = Smi::FromInt(j); - Handle map; - map = JSObject::GetElementsTransitionMap(array, kind); - array->set_map(*map); - array->set_length(length); - array->set_elements(*storage); - return *array; + return *isolate->factory()->NewJSArrayWithElements(storage, kind, j); } // In case of failure, fall through. } @@ -1387,23 +1405,23 @@ Object* Slow_ArrayConcat(Arguments* args, Isolate* isolate) { MaybeHandle Fast_ArrayConcat(Isolate* isolate, Arguments* args) { - if (!isolate->IsFastArrayConstructorPrototypeChainIntact()) { - return MaybeHandle(); - } int n_arguments = args->length(); int result_len = 0; { DisallowHeapAllocation no_gc; - Object* array_proto = isolate->array_function()->prototype(); // Iterate through all the arguments performing checks // and calculating total length. for (int i = 0; i < n_arguments; i++) { Object* arg = (*args)[i]; if (!arg->IsJSArray()) return MaybeHandle(); + if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) { + return MaybeHandle(); + } + // TODO(cbruni): support fast concatenation of DICTIONARY_ELEMENTS. + if (!JSObject::cast(arg)->HasFastElements()) { + return MaybeHandle(); + } Handle array(JSArray::cast(arg), isolate); - if (!array->HasFastElements()) return MaybeHandle(); - PrototypeIterator iter(isolate, arg); - if (iter.GetCurrent() != array_proto) return MaybeHandle(); if (HasConcatSpreadableModifier(isolate, array)) { return MaybeHandle(); } @@ -2207,7 +2225,11 @@ BUILTIN(DateConstructor) { char buffer[128]; Vector str(buffer, arraysize(buffer)); ToDateString(time_val, str, isolate->date_cache()); - return *isolate->factory()->NewStringFromAsciiChecked(str.start()); + Handle result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + isolate->factory()->NewStringFromUtf8(CStrVector(buffer))); + return *result; } @@ -2787,7 +2809,11 @@ BUILTIN(DatePrototypeToDateString) { char buffer[128]; Vector str(buffer, arraysize(buffer)); ToDateString(date->value()->Number(), str, isolate->date_cache(), kDateOnly); - return *isolate->factory()->NewStringFromAsciiChecked(str.start()); + Handle result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + isolate->factory()->NewStringFromUtf8(CStrVector(buffer))); + return *result; } @@ -2827,7 +2853,11 @@ BUILTIN(DatePrototypeToString) { char buffer[128]; Vector str(buffer, arraysize(buffer)); ToDateString(date->value()->Number(), str, isolate->date_cache()); - return *isolate->factory()->NewStringFromAsciiChecked(str.start()); + Handle result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + isolate->factory()->NewStringFromUtf8(CStrVector(buffer))); + return *result; } @@ -2838,7 +2868,11 @@ BUILTIN(DatePrototypeToTimeString) { char buffer[128]; Vector str(buffer, arraysize(buffer)); ToDateString(date->value()->Number(), str, isolate->date_cache(), kTimeOnly); - return *isolate->factory()->NewStringFromAsciiChecked(str.start()); + Handle result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + isolate->factory()->NewStringFromUtf8(CStrVector(buffer))); + return *result; } diff --git a/deps/v8/src/compiler/pipeline.cc b/deps/v8/src/compiler/pipeline.cc index 4d6aacd78a882e..2204424706a4e2 100644 --- a/deps/v8/src/compiler/pipeline.cc +++ b/deps/v8/src/compiler/pipeline.cc @@ -677,6 +677,13 @@ struct SimplifiedLoweringPhase { SimplifiedLowering lowering(data->jsgraph(), temp_zone, data->source_positions()); lowering.LowerAllNodes(); + + // TODO(bmeurer): See comment on SimplifiedLowering::abort_compilation_. + if (lowering.abort_compilation_) { + data->set_compilation_failed(); + return; + } + JSGraphReducer graph_reducer(data->jsgraph(), temp_zone); DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(), data->common()); @@ -1204,6 +1211,9 @@ Handle Pipeline::GenerateCode() { // Kill the Typer and thereby uninstall the decorator (if any). typer.Reset(nullptr); + // TODO(bmeurer): See comment on SimplifiedLowering::abort_compilation_. + if (data.compilation_failed()) return Handle::null(); + return ScheduleAndGenerateCode( Linkage::ComputeIncoming(data.instruction_zone(), info())); } diff --git a/deps/v8/src/compiler/simplified-lowering.cc b/deps/v8/src/compiler/simplified-lowering.cc index 653fea80eac4f4..8af8bdfaa1775b 100644 --- a/deps/v8/src/compiler/simplified-lowering.cc +++ b/deps/v8/src/compiler/simplified-lowering.cc @@ -1189,10 +1189,18 @@ class RepresentationSelector { NodeOutputInfo(access.machine_type().representation(), NodeProperties::GetType(node)); } else { + if (access.machine_type().representation() != + MachineRepresentation::kFloat64) { + // TODO(bmeurer): See comment on abort_compilation_. + if (lower()) lowering->abort_compilation_ = true; + } output_info = NodeOutputInfo::Float64(); } } } else { + // TODO(bmeurer): See comment on abort_compilation_. + if (lower()) lowering->abort_compilation_ = true; + // If undefined is not truncated away, we need to have the tagged // representation. output_info = NodeOutputInfo::AnyTagged(); diff --git a/deps/v8/src/compiler/simplified-lowering.h b/deps/v8/src/compiler/simplified-lowering.h index f9410f8b41eef5..056837ab87f5cf 100644 --- a/deps/v8/src/compiler/simplified-lowering.h +++ b/deps/v8/src/compiler/simplified-lowering.h @@ -43,6 +43,11 @@ class SimplifiedLowering final { void DoStringLessThan(Node* node); void DoStringLessThanOrEqual(Node* node); + // TODO(bmeurer): This is a gigantic hack to support the gigantic LoadBuffer + // typing hack to support the gigantic "asm.js should be fast without proper + // verifier"-hack, ... Kill this! Soon! Really soon! I'm serious! + bool abort_compilation_ = false; + private: JSGraph* const jsgraph_; Zone* const zone_; diff --git a/deps/v8/src/elements.cc b/deps/v8/src/elements.cc index d4d80dbdecfdbb..277749763a2bc2 100644 --- a/deps/v8/src/elements.cc +++ b/deps/v8/src/elements.cc @@ -545,6 +545,16 @@ class ElementsAccessorBase : public ElementsAccessor { *holder, *backing_store, index, filter) != kMaxUInt32; } + bool HasAccessors(JSObject* holder) final { + return ElementsAccessorSubclass::HasAccessorsImpl(holder, + holder->elements()); + } + + static bool HasAccessorsImpl(JSObject* holder, + FixedArrayBase* backing_store) { + return false; + } + Handle Get(Handle backing_store, uint32_t entry) final { return ElementsAccessorSubclass::GetImpl(backing_store, entry); @@ -1048,6 +1058,21 @@ class DictionaryElementsAccessor obj->set_elements(*new_elements); } + static bool HasAccessorsImpl(JSObject* holder, + FixedArrayBase* backing_store) { + SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store); + if (!dict->requires_slow_elements()) return false; + int capacity = dict->Capacity(); + for (int i = 0; i < capacity; i++) { + Object* key = dict->KeyAt(i); + if (!dict->IsKey(key)) continue; + DCHECK(!dict->IsDeleted(i)); + PropertyDetails details = dict->DetailsAt(i); + if (details.type() == ACCESSOR_CONSTANT) return true; + } + return false; + } + static Object* GetRaw(FixedArrayBase* store, uint32_t entry) { SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store); return backing_store->ValueAt(entry); @@ -1813,6 +1838,11 @@ class TypedElementsAccessor BackingStore::cast(backing_store)->SetValue(entry, value); } + static bool HasAccessorsImpl(JSObject* holder, + FixedArrayBase* backing_store) { + return false; + } + static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry, Object* value, WriteBarrierMode mode) { BackingStore::cast(backing_store)->SetValue(entry, value); @@ -1970,6 +2000,13 @@ class SloppyArgumentsElementsAccessor return ArgumentsAccessor::HasEntryImpl(arguments, entry - length); } + static bool HasAccessorsImpl(JSObject* holder, + FixedArrayBase* backing_store) { + FixedArray* parameter_map = FixedArray::cast(backing_store); + FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); + return ArgumentsAccessor::HasAccessorsImpl(holder, arguments); + } + static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters, uint32_t entry) { FixedArray* parameter_map = FixedArray::cast(parameters); diff --git a/deps/v8/src/elements.h b/deps/v8/src/elements.h index 71e70a1c0097b9..86ada229e33752 100644 --- a/deps/v8/src/elements.h +++ b/deps/v8/src/elements.h @@ -54,6 +54,8 @@ class ElementsAccessor { return HasElement(holder, index, handle(holder->elements()), filter); } + virtual bool HasAccessors(JSObject* holder) = 0; + // Returns true if the backing store is compact in the given range virtual bool IsPacked(Handle holder, Handle backing_store, uint32_t start, diff --git a/deps/v8/src/heap/incremental-marking.cc b/deps/v8/src/heap/incremental-marking.cc index 52d0ca4e51b6e2..579df28b087803 100644 --- a/deps/v8/src/heap/incremental-marking.cc +++ b/deps/v8/src/heap/incremental-marking.cc @@ -847,16 +847,21 @@ void IncrementalMarking::MarkObject(Heap* heap, HeapObject* obj) { intptr_t IncrementalMarking::ProcessMarkingDeque(intptr_t bytes_to_process) { intptr_t bytes_processed = 0; - Map* filler_map = heap_->one_pointer_filler_map(); + Map* one_pointer_filler_map = heap_->one_pointer_filler_map(); + Map* two_pointer_filler_map = heap_->two_pointer_filler_map(); MarkingDeque* marking_deque = heap_->mark_compact_collector()->marking_deque(); while (!marking_deque->IsEmpty() && bytes_processed < bytes_to_process) { HeapObject* obj = marking_deque->Pop(); - // Explicitly skip one word fillers. Incremental markbit patterns are - // correct only for objects that occupy at least two words. + // Explicitly skip one and two word fillers. Incremental markbit patterns + // are correct only for objects that occupy at least two words. + // Moreover, slots filtering for left-trimmed arrays works only when + // the distance between the old array start and the new array start + // is greater than two if both starts are marked. Map* map = obj->map(); - if (map == filler_map) continue; + if (map == one_pointer_filler_map || map == two_pointer_filler_map) + continue; int size = obj->SizeFromMap(map); unscanned_bytes_of_large_object_ = 0; diff --git a/deps/v8/src/heap/memory-reducer.cc b/deps/v8/src/heap/memory-reducer.cc index 33e624978ffc21..ee1009134bc75e 100644 --- a/deps/v8/src/heap/memory-reducer.cc +++ b/deps/v8/src/heap/memory-reducer.cc @@ -73,14 +73,7 @@ void MemoryReducer::NotifyTimer(const Event& event) { PrintIsolate(heap()->isolate(), "Memory reducer: started GC #%d\n", state_.started_gcs); } - if (heap()->ShouldOptimizeForMemoryUsage()) { - // TODO(ulan): Remove this once crbug.com/552305 is fixed. - // Do full GC if memory usage has higher priority than latency. - heap()->CollectAllGarbage(Heap::kReduceMemoryFootprintMask, - "memory reducer"); - } else { - heap()->StartIdleIncrementalMarking(); - } + heap()->StartIdleIncrementalMarking(); } else if (state_.action == kWait) { if (!heap()->incremental_marking()->IsStopped() && heap()->ShouldOptimizeForMemoryUsage()) { diff --git a/deps/v8/src/runtime/runtime-array.cc b/deps/v8/src/runtime/runtime-array.cc index 28e92cbd2baa0b..f2a217d7f7c0c1 100644 --- a/deps/v8/src/runtime/runtime-array.cc +++ b/deps/v8/src/runtime/runtime-array.cc @@ -120,9 +120,11 @@ RUNTIME_FUNCTION(Runtime_PushIfAbsent) { RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) { HandleScope scope(isolate); DCHECK(args.length() == 2); - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); + CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); - return *JSObject::PrepareElementsForSort(object, limit); + if (object->IsJSProxy()) return Smi::FromInt(-1); + return *JSObject::PrepareElementsForSort(Handle::cast(object), + limit); } diff --git a/deps/v8/test/cctest/cctest.gyp b/deps/v8/test/cctest/cctest.gyp index 9ef2d9bfb2830c..708b767a10e42a 100644 --- a/deps/v8/test/cctest/cctest.gyp +++ b/deps/v8/test/cctest/cctest.gyp @@ -81,7 +81,6 @@ 'compiler/test-run-jsops.cc', 'compiler/test-run-machops.cc', 'compiler/test-run-native-calls.cc', - 'compiler/test-run-properties.cc', 'compiler/test-run-stackcheck.cc', 'compiler/test-run-stubs.cc', 'compiler/test-run-variables.cc', diff --git a/deps/v8/test/cctest/compiler/test-run-properties.cc b/deps/v8/test/cctest/compiler/test-run-properties.cc deleted file mode 100644 index 3c421025292151..00000000000000 --- a/deps/v8/test/cctest/compiler/test-run-properties.cc +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2014 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. - -#include "test/cctest/compiler/function-tester.h" - -namespace v8 { -namespace internal { -namespace compiler { - -template -static void TypedArrayLoadHelper(const char* array_type) { - static const uint32_t kValues[] = { - 0x00000000, 0x00000001, 0x00000023, 0x00000042, 0x12345678, 0x87654321, - 0x0000003f, 0x0000007f, 0x00003fff, 0x00007fff, 0x3fffffff, 0x7fffffff, - 0x000000ff, 0x00000080, 0x0000ffff, 0x00008000, 0xffffffff, 0x80000000}; - EmbeddedVector values_buffer; - StringBuilder values_builder(values_buffer.start(), values_buffer.length()); - for (size_t i = 0; i < arraysize(kValues); ++i) { - values_builder.AddFormatted("a[%d] = 0x%08x;", i, kValues[i]); - } - - // Note that below source creates two different typed arrays with the same - // elements kind to get coverage for both (on heap / with external backing - // store) access patterns. - const char* source = - "(function(a) {" - " var x = (a = new %sArray(%d)); %s;" - " var y = (a = new %sArray(%d)); %s; %%TypedArrayGetBuffer(y);" - " if (!%%HasFixed%sElements(x)) %%AbortJS('x');" - " if (!%%HasFixed%sElements(y)) %%AbortJS('y');" - " function f(a,b) {" - " a = a | 0; b = b | 0;" - " return x[a] + y[b];" - " }" - " return f;" - "})()"; - EmbeddedVector source_buffer; - SNPrintF(source_buffer, source, array_type, arraysize(kValues), - values_buffer.start(), array_type, arraysize(kValues), - values_buffer.start(), array_type, array_type); - - FunctionTester T(source_buffer.start(), - CompilationInfo::kFunctionContextSpecializing | - CompilationInfo::kTypingEnabled); - for (size_t i = 0; i < arraysize(kValues); ++i) { - for (size_t j = 0; j < arraysize(kValues); ++j) { - volatile U value_a = static_cast(kValues[i]); - volatile U value_b = static_cast(kValues[j]); - double expected = - static_cast(value_a) + static_cast(value_b); - T.CheckCall(T.Val(expected), T.Val(static_cast(i)), - T.Val(static_cast(j))); - } - } -} - - -TEST(TypedArrayLoad) { - FLAG_typed_array_max_size_in_heap = 256; - TypedArrayLoadHelper("Int8"); - TypedArrayLoadHelper("Uint8"); - TypedArrayLoadHelper("Int16"); - TypedArrayLoadHelper("Uint16"); - TypedArrayLoadHelper("Int32"); - TypedArrayLoadHelper("Uint32"); - TypedArrayLoadHelper("Float32"); - TypedArrayLoadHelper("Float64"); - // TODO(mstarzinger): Add tests for ClampedUint8. -} - - -template -static void TypedArrayStoreHelper(const char* array_type) { - static const uint32_t kValues[] = { - 0x00000000, 0x00000001, 0x00000023, 0x00000042, 0x12345678, 0x87654321, - 0x0000003f, 0x0000007f, 0x00003fff, 0x00007fff, 0x3fffffff, 0x7fffffff, - 0x000000ff, 0x00000080, 0x0000ffff, 0x00008000, 0xffffffff, 0x80000000}; - EmbeddedVector values_buffer; - StringBuilder values_builder(values_buffer.start(), values_buffer.length()); - for (size_t i = 0; i < arraysize(kValues); ++i) { - values_builder.AddFormatted("a[%d] = 0x%08x;", i, kValues[i]); - } - - // Note that below source creates two different typed arrays with the same - // elements kind to get coverage for both (on heap/with external backing - // store) access patterns. - const char* source = - "(function(a) {" - " var x = (a = new %sArray(%d)); %s;" - " var y = (a = new %sArray(%d)); %s; %%TypedArrayGetBuffer(y);" - " if (!%%HasFixed%sElements(x)) %%AbortJS('x');" - " if (!%%HasFixed%sElements(y)) %%AbortJS('y');" - " function f(a,b) {" - " a = a | 0; b = b | 0;" - " var t = x[a];" - " x[a] = y[b];" - " y[b] = t;" - " t = y[b];" - " y[b] = x[a];" - " x[a] = t;" - " return x[a] + y[b];" - " }" - " return f;" - "})()"; - EmbeddedVector source_buffer; - SNPrintF(source_buffer, source, array_type, arraysize(kValues), - values_buffer.start(), array_type, arraysize(kValues), - values_buffer.start(), array_type, array_type); - - FunctionTester T(source_buffer.start(), - CompilationInfo::kFunctionContextSpecializing | - CompilationInfo::kTypingEnabled); - for (size_t i = 0; i < arraysize(kValues); ++i) { - for (size_t j = 0; j < arraysize(kValues); ++j) { - volatile U value_a = static_cast(kValues[i]); - volatile U value_b = static_cast(kValues[j]); - double expected = - static_cast(value_a) + static_cast(value_b); - T.CheckCall(T.Val(expected), T.Val(static_cast(i)), - T.Val(static_cast(j))); - } - } -} - - -TEST(TypedArrayStore) { - FLAG_typed_array_max_size_in_heap = 256; - TypedArrayStoreHelper("Int8"); - TypedArrayStoreHelper("Uint8"); - TypedArrayStoreHelper("Int16"); - TypedArrayStoreHelper("Uint16"); - TypedArrayStoreHelper("Int32"); - TypedArrayStoreHelper("Uint32"); - TypedArrayStoreHelper("Float32"); - TypedArrayStoreHelper("Float64"); - // TODO(mstarzinger): Add tests for ClampedUint8. -} - -} // namespace compiler -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/mjsunit/array-concat.js b/deps/v8/test/mjsunit/array-concat.js index 97bd85aca2e646..6e25b5c5cd320c 100644 --- a/deps/v8/test/mjsunit/array-concat.js +++ b/deps/v8/test/mjsunit/array-concat.js @@ -29,6 +29,19 @@ * @fileoverview Test concat on small and large arrays */ + +(function testStringWrapperConcat() { + var concat = Array.prototype.concat; + var str = new String('abcd'); + assertEquals([1,2,3,new String('abcd')], [1, 2, 3].concat(str)); + assertEquals([new String("abcd")], concat.call(str)); + + var array = [1, 2, 3]; + array.__proto__ = str; + array.length = 4; + assertEquals([1,2,3,'d'], concat.call(array)); +})() + var poses; poses = [140, 4000000000]; diff --git a/deps/v8/test/mjsunit/array-sort.js b/deps/v8/test/mjsunit/array-sort.js index 36608f5e142e45..beb8b95b014bb4 100644 --- a/deps/v8/test/mjsunit/array-sort.js +++ b/deps/v8/test/mjsunit/array-sort.js @@ -464,3 +464,9 @@ function TestSortToObject() { assertEquals(0, Number(Array.prototype.sort.call(0))); } TestSortToObject(); + +function TestSortOnProxy() { + var p = new Proxy([2,1,3], {}); + assertEquals([1,2,3], p.sort()); +} +TestSortOnProxy(); diff --git a/deps/v8/test/mjsunit/regress/regress-4800.js b/deps/v8/test/mjsunit/regress/regress-4800.js new file mode 100644 index 00000000000000..af7cbc0b8f42d9 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-4800.js @@ -0,0 +1,76 @@ +// 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: --allow-natives-syntax + +function f(x, len) { + var distraction = []; + var result = new Array(25); + + // Create a bunch of double values with long live ranges. + var d0 = x + 0.5; + var d1 = x + 1.5; + var d2 = x + 2.5; + var d3 = x + 3.5; + var d4 = x + 4.5; + var d5 = x + 5.5; + var d6 = x + 6.5; + var d7 = x + 7.5; + var d8 = x + 8.5; + var d9 = x + 9.5; + var d10 = x + 10.5; + var d11 = x + 11.5; + var d12 = x + 12.5; + var d13 = x + 13.5; + var d14 = x + 14.5; + var d15 = x + 15.5; + var d16 = x + 16.5; + var d17 = x + 17.5; + var d18 = x + 18.5; + var d19 = x + 19.5; + var d20 = x + 20.5; + var d21 = x + 21.5; + var d22 = x + 22.5; + var d23 = x + 23.5; + var d24 = x + 24.5; + + // Trigger a stub failure when the array grows too big. + distraction[len] = 0; + + // Write the long-lived doubles to memory and verify them. + result[0] = d0; + result[1] = d1; + result[2] = d2; + result[3] = d3; + result[4] = d4; + result[5] = d5; + result[6] = d6; + result[7] = d7; + result[8] = d8; + result[9] = d9; + result[10] = d10; + result[11] = d11; + result[12] = d12; + result[13] = d13; + result[14] = d14; + result[15] = d15; + result[16] = d16; + result[17] = d17; + result[18] = d18; + result[19] = d19; + result[20] = d20; + result[21] = d21; + result[22] = d22; + result[23] = d23; + result[24] = d24; + + for (var i = 0; i < result.length; i++) { + assertEquals(x + i + 0.5, result[i]); + } +} + +f(0, 10); +f(0, 10); +%OptimizeFunctionOnNextCall(f); +f(0, 80000); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-589792.js b/deps/v8/test/mjsunit/regress/regress-crbug-589792.js new file mode 100644 index 00000000000000..f735afceaefbf7 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-589792.js @@ -0,0 +1,20 @@ +// 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: --allow-natives-syntax + +var boom = (function(stdlib, foreign, heap) { + "use asm"; + var MEM8 = new stdlib.Uint8Array(heap); + var MEM32 = new stdlib.Int32Array(heap); + function foo(i, j) { + j = MEM8[256]; + // This following value '10' determines the value of 'rax' + MEM32[j >> 10] = 0xabcdefaa; + return MEM32[j >> 2] + j + } + return foo +})(this, 0, new ArrayBuffer(256)); +%OptimizeFunctionOnNextCall(boom); +boom(0, 0x1000); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-594574-concat-leak-1.js b/deps/v8/test/mjsunit/regress/regress-crbug-594574-concat-leak-1.js new file mode 100644 index 00000000000000..d5f51a49cacb01 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-594574-concat-leak-1.js @@ -0,0 +1,36 @@ +// 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 + +array = new Array(10); +array[0] = 0.1; +// array[1] = THE_HOLE, reading through the prototype chain +array[2] = 2.1; +array[3] = 3.1; + +var copy = array.slice(0, array.length); + +// Change the array's prototype. +var proto = {}; +array.__proto__ = proto; + +// Define [1] on the prototype to alter the array during concatenation. +Object.defineProperty( + proto, 1, { + get() { + // Alter the array. + array.length = 1; + // Force gc to move the array. + gc(); + return "value from proto"; + }, + set(new_value) { } +}); + +var concatted_array = Array.prototype.concat.call(array); +assertEquals(concatted_array[0], 0.1); +assertEquals(concatted_array[1], "value from proto"); +assertEquals(concatted_array[2], undefined); +assertEquals(concatted_array[3], undefined); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-594574-concat-leak-2.js b/deps/v8/test/mjsunit/regress/regress-crbug-594574-concat-leak-2.js new file mode 100644 index 00000000000000..f359cfd80b5e7b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-594574-concat-leak-2.js @@ -0,0 +1,35 @@ +// 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 + +array = new Array(10); +array[0] = 0.1; +// array[1] = THE_HOLE, reading through the prototype chain +array[2] = 2.1; +array[3] = 3.1; + +var copy = array.slice(0, array.length); + +// Use the defaul array prototype. +var proto = array.__proto__; + +// Define [1] on the prototype to alter the array during concatenation. +Object.defineProperty( + proto, 1, { + get() { + // Alter the array. + array.length = 1; + // Force gc to move the array. + gc(); + return "value from proto"; + }, + set(new_value) { } +}); + +var concatted_array = Array.prototype.concat.call(array); +assertEquals(concatted_array[0], 0.1); +assertEquals(concatted_array[1], "value from proto"); +assertEquals(concatted_array[2], undefined); +assertEquals(concatted_array[3], undefined);