Commit cc75535d authored by Peter Marshall's avatar Peter Marshall Committed by Commit Bot

[runtime] Fix spec bug in TypedArrayConstruct with mutating iterables.

The spec requires that we use IterableToList, which we skipped for
some arrays as an optimization. We can't skip this for arrays with
objects though, because the objects may mutate the array during
the copying step via valueOf side effects.

Also clean up the implementation to use a runtime function rather
than a builtin as the helper. Also reverses the result of the helper
because I think it is a bit more intuitive that way.

Bug: v8:6224
Change-Id: I9199491abede4479785df6d9068331bc2d6e9c5e
Reviewed-on: https://chromium-review.googlesource.com/471986Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44507}
parent f764f432
...@@ -1524,11 +1524,6 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -1524,11 +1524,6 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
array_function, isolate->factory()->InternalizeUtf8String("isArray"), array_function, isolate->factory()->InternalizeUtf8String("isArray"),
Builtins::kArrayIsArray, 1, true); Builtins::kArrayIsArray, 1, true);
native_context()->set_is_arraylike(*is_arraylike); native_context()->set_is_arraylike(*is_arraylike);
Handle<JSFunction> has_side_effects = SimpleCreateFunction(
isolate, factory->NewStringFromAsciiChecked("hasIterationSideEffects"),
Builtins::kHasIterationSideEffects, 1, false);
native_context()->set_has_iteration_side_effects(*has_side_effects);
} }
{ // --- A r r a y I t e r a t o r --- { // --- A r r a y I t e r a t o r ---
......
...@@ -1239,14 +1239,5 @@ BUILTIN(ArrayConcat) { ...@@ -1239,14 +1239,5 @@ BUILTIN(ArrayConcat) {
return Slow_ArrayConcat(&args, species, isolate); return Slow_ArrayConcat(&args, species, isolate);
} }
BUILTIN(HasIterationSideEffects) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
bool observable = args[1]->IterationHasObservableEffects();
return isolate->heap()->ToBoolean(observable);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -243,7 +243,6 @@ namespace internal { ...@@ -243,7 +243,6 @@ namespace internal {
/* Array */ \ /* Array */ \
ASM(ArrayCode) \ ASM(ArrayCode) \
ASM(InternalArrayCode) \ ASM(InternalArrayCode) \
CPP(HasIterationSideEffects) \
CPP(ArrayConcat) \ CPP(ArrayConcat) \
/* ES6 #sec-array.isarray */ \ /* ES6 #sec-array.isarray */ \
TFJ(ArrayIsArray, 1, kArg) \ TFJ(ArrayIsArray, 1, kArg) \
......
...@@ -47,7 +47,6 @@ enum ContextLookupFlags { ...@@ -47,7 +47,6 @@ enum ContextLookupFlags {
V(IS_ARRAYLIKE, JSFunction, is_arraylike) \ V(IS_ARRAYLIKE, JSFunction, is_arraylike) \
V(GENERATOR_NEXT_INTERNAL, JSFunction, generator_next_internal) \ V(GENERATOR_NEXT_INTERNAL, JSFunction, generator_next_internal) \
V(GET_TEMPLATE_CALL_SITE_INDEX, JSFunction, get_template_call_site) \ V(GET_TEMPLATE_CALL_SITE_INDEX, JSFunction, get_template_call_site) \
V(HAS_ITERATION_SIDE_EFFECTS_INDEX, JSFunction, has_iteration_side_effects) \
V(MAKE_ERROR_INDEX, JSFunction, make_error) \ V(MAKE_ERROR_INDEX, JSFunction, make_error) \
V(MAKE_RANGE_ERROR_INDEX, JSFunction, make_range_error) \ V(MAKE_RANGE_ERROR_INDEX, JSFunction, make_range_error) \
V(MAKE_SYNTAX_ERROR_INDEX, JSFunction, make_syntax_error) \ V(MAKE_SYNTAX_ERROR_INDEX, JSFunction, make_syntax_error) \
......
...@@ -150,6 +150,10 @@ inline bool IsFastSmiElementsKind(ElementsKind kind) { ...@@ -150,6 +150,10 @@ inline bool IsFastSmiElementsKind(ElementsKind kind) {
kind == FAST_HOLEY_SMI_ELEMENTS; kind == FAST_HOLEY_SMI_ELEMENTS;
} }
inline bool IsFastNumberElementsKind(ElementsKind kind) {
return IsFastSmiElementsKind(kind) || IsFastDoubleElementsKind(kind);
}
inline bool IsFastObjectElementsKind(ElementsKind kind) { inline bool IsFastObjectElementsKind(ElementsKind kind) {
return kind == FAST_ELEMENTS || return kind == FAST_ELEMENTS ||
......
...@@ -113,7 +113,12 @@ function TypedArraySpeciesCreate(exemplar, arg0, arg1, arg2, conservative) { ...@@ -113,7 +113,12 @@ function TypedArraySpeciesCreate(exemplar, arg0, arg1, arg2, conservative) {
macro TYPED_ARRAY_CONSTRUCTOR(NAME, ELEMENT_SIZE) macro TYPED_ARRAY_CONSTRUCTOR(NAME, ELEMENT_SIZE)
function NAMEConstructByIterable(obj, iterable, iteratorFn) { function NAMEConstructByIterable(obj, iterable, iteratorFn) {
if (%has_iteration_side_effects(iterable)) { if (%IterableToListCanBeElided(iterable)) {
// This .length access is unobservable, because it being observable would
// mean that iteration has side effects, and we wouldn't reach this path.
%typed_array_construct_by_array_like(
obj, iterable, iterable.length, ELEMENT_SIZE);
} else {
var list = new InternalArray(); var list = new InternalArray();
// Reading the Symbol.iterator property of iterable twice would be // Reading the Symbol.iterator property of iterable twice would be
// observable with getters, so instead, we call the function which // observable with getters, so instead, we call the function which
...@@ -131,11 +136,6 @@ function NAMEConstructByIterable(obj, iterable, iteratorFn) { ...@@ -131,11 +136,6 @@ function NAMEConstructByIterable(obj, iterable, iteratorFn) {
list.push(value); list.push(value);
} }
%typed_array_construct_by_array_like(obj, list, list.length, ELEMENT_SIZE); %typed_array_construct_by_array_like(obj, list, list.length, ELEMENT_SIZE);
} else {
// This .length access is unobservable, because it being observable would
// mean that iteration has side effects, and we wouldn't reach this path.
%typed_array_construct_by_array_like(
obj, iterable, iterable.length, ELEMENT_SIZE);
} }
} }
......
...@@ -1028,6 +1028,22 @@ RUNTIME_FUNCTION(Runtime_CreateDataProperty) { ...@@ -1028,6 +1028,22 @@ RUNTIME_FUNCTION(Runtime_CreateDataProperty) {
return *value; return *value;
} }
// Checks that 22.2.2.1.1 Runtime Semantics: IterableToList produces exactly the
// same result as doing nothing.
RUNTIME_FUNCTION(Runtime_IterableToListCanBeElided) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
if (!obj->IsJSObject()) return isolate->heap()->ToBoolean(false);
// While iteration alone may not have observable side-effects, calling
// toNumber on an object will. Make sure the arg is not an array of objects.
ElementsKind kind = JSObject::cast(*obj)->GetElementsKind();
if (!IsFastNumberElementsKind(kind)) return isolate->heap()->ToBoolean(false);
return isolate->heap()->ToBoolean(!obj->IterationHasObservableEffects());
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -422,7 +422,8 @@ namespace internal { ...@@ -422,7 +422,8 @@ namespace internal {
F(CreateIterResultObject, 2, 1) \ F(CreateIterResultObject, 2, 1) \
F(CreateKeyValueArray, 2, 1) \ F(CreateKeyValueArray, 2, 1) \
F(IsAccessCheckNeeded, 1, 1) \ F(IsAccessCheckNeeded, 1, 1) \
F(CreateDataProperty, 3, 1) F(CreateDataProperty, 3, 1) \
F(IterableToListCanBeElided, 1, 1)
#define FOR_EACH_INTRINSIC_OPERATORS(F) \ #define FOR_EACH_INTRINSIC_OPERATORS(F) \
F(Multiply, 2, 1) \ F(Multiply, 2, 1) \
......
...@@ -30,6 +30,27 @@ function TestConstructLargeObject(constr) { ...@@ -30,6 +30,27 @@ function TestConstructLargeObject(constr) {
} }
} }
function TestConstructFromArrayWithSideEffects(constr) {
var arr = [{ valueOf() { arr[1] = 20; return 1; }}, 2];
var ta = new constr(arr);
assertEquals(1, ta[0]);
assertEquals(2, ta[1]);
}
function TestConstructFromArrayWithSideEffectsHoley(constr) {
var arr = [{ valueOf() { arr[1] = 20; return 1; }}, 2, , 4];
var ta = new constr(arr);
assertEquals(1, ta[0]);
assertEquals(2, ta[1]);
// ta[2] will be the default value, but we aren't testing that here.
assertEquals(4, ta[3]);
}
function TestConstructFromArray(constr) { function TestConstructFromArray(constr) {
var n = 64; var n = 64;
var jsArray = []; var jsArray = [];
...@@ -97,6 +118,8 @@ function TestOffsetIsUsed(constr, n) { ...@@ -97,6 +118,8 @@ function TestOffsetIsUsed(constr, n) {
Test(TestConstructSmallObject); Test(TestConstructSmallObject);
Test(TestConstructLargeObject); Test(TestConstructLargeObject);
Test(TestConstructFromArrayWithSideEffects);
Test(TestConstructFromArrayWithSideEffectsHoley);
Test(TestConstructFromArray); Test(TestConstructFromArray);
Test(TestConstructFromTypedArray); Test(TestConstructFromTypedArray);
Test(TestLengthIsMaxSmi); Test(TestLengthIsMaxSmi);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment