Update ecma_op_typedarray_from to use iterable objects (#3501)
Added steps 6-8 from ECMA-262 v6, 22.2.2.1.1 JerryScript-DCO-1.0-Signed-off-by: Adam Szilagyi aszilagy@inf.u-szeged.hu
This commit is contained in:
@@ -736,11 +736,11 @@ ecma_builtin_typedarray_prototype_filter (ecma_value_t this_arg, /**< this argum
|
||||
|
||||
ecma_value_t call_args[] = { get_value, current_index, this_arg };
|
||||
|
||||
ecma_value_t call_value = ecma_op_function_call (func_object_p, cb_this_arg, call_args, 3);
|
||||
|
||||
ecma_fast_free_value (current_index);
|
||||
ecma_fast_free_value (get_value);
|
||||
|
||||
ecma_value_t call_value = ecma_op_function_call (func_object_p, cb_this_arg, call_args, 3);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (call_value))
|
||||
{
|
||||
goto cleanup;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "ecma-iterator-object.h"
|
||||
#include "ecma-typedarray-object.h"
|
||||
#include "ecma-arraybuffer-object.h"
|
||||
#include "ecma-function-object.h"
|
||||
@@ -675,7 +676,64 @@ ecma_typedarray_create_object_with_typedarray (ecma_object_t *typedarray_p, /**<
|
||||
} /* ecma_typedarray_create_object_with_typedarray */
|
||||
|
||||
/**
|
||||
* Create a TypedArray object by transforming from an array-like object
|
||||
* Helper method for ecma_op_typedarray_from
|
||||
*
|
||||
* @return ECMA_VALUE_TRUE - if setting the given value to the new typedarray was successful
|
||||
* ECMA_VALUE_ERROR - otherwise
|
||||
*/
|
||||
static ecma_value_t
|
||||
ecma_op_typedarray_from_helper (ecma_value_t this_val, /**< this_arg for the above from function */
|
||||
ecma_value_t current_value, /**< given value to set */
|
||||
uint32_t index, /**< currrent index */
|
||||
ecma_object_t *func_object_p, /**< map function object */
|
||||
ecma_typedarray_info_t *info_p, /**< typedarray info */
|
||||
ecma_typedarray_setter_fn_t setter_cb) /**< setter callback function */
|
||||
{
|
||||
ecma_value_t mapped_value;
|
||||
if (func_object_p != NULL)
|
||||
{
|
||||
/* 17.d 17.f */
|
||||
ecma_value_t current_index = ecma_make_uint32_value (index);
|
||||
ecma_value_t call_args[] = { current_value, current_index };
|
||||
|
||||
ecma_value_t cb_value = ecma_op_function_call (func_object_p, this_val, call_args, 2);
|
||||
|
||||
ecma_free_value (current_index);
|
||||
ecma_free_value (current_value);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (cb_value))
|
||||
{
|
||||
return cb_value;
|
||||
}
|
||||
|
||||
mapped_value = cb_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
mapped_value = current_value;
|
||||
}
|
||||
|
||||
ecma_number_t num_var;
|
||||
ecma_value_t mapped_number = ecma_get_number (mapped_value, &num_var);
|
||||
ecma_free_value (mapped_value);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (mapped_number))
|
||||
{
|
||||
return mapped_number;
|
||||
}
|
||||
|
||||
if (index >= info_p->length)
|
||||
{
|
||||
return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type."));
|
||||
}
|
||||
|
||||
setter_cb (info_p->buffer_p + (index << info_p->shift), num_var);
|
||||
|
||||
return ECMA_VALUE_TRUE;
|
||||
} /* ecma_op_typedarray_from_helper */
|
||||
|
||||
/**
|
||||
* Create a TypedArray object by transforming from an array-like object or iterable object
|
||||
*
|
||||
* See also: ES2015 22.2.2.1
|
||||
*
|
||||
@@ -693,12 +751,130 @@ ecma_op_typedarray_from (ecma_value_t items_val, /**< the source array-like obje
|
||||
/* 3 */
|
||||
JERRY_ASSERT (ecma_op_is_callable (map_fn_val) || ecma_is_value_undefined (map_fn_val));
|
||||
|
||||
/* 4-5 */
|
||||
ecma_object_t *func_object_p = NULL;
|
||||
if (!ecma_is_value_undefined (map_fn_val))
|
||||
{
|
||||
func_object_p = ecma_get_object_from_value (map_fn_val);
|
||||
}
|
||||
|
||||
/* 6 */
|
||||
ecma_value_t using_iterator = ecma_op_get_method_by_symbol_id (items_val, LIT_GLOBAL_SYMBOL_ITERATOR);
|
||||
|
||||
/* 7 */
|
||||
if (ECMA_IS_VALUE_ERROR (using_iterator))
|
||||
{
|
||||
return using_iterator;
|
||||
}
|
||||
|
||||
/* 8 */
|
||||
if (!ecma_is_value_undefined (using_iterator))
|
||||
{
|
||||
/* 8.a */
|
||||
ecma_value_t iterator = ecma_op_get_iterator (items_val, using_iterator);
|
||||
ecma_free_value (using_iterator);
|
||||
|
||||
/* 8.b */
|
||||
if (ECMA_IS_VALUE_ERROR (iterator))
|
||||
{
|
||||
return iterator;
|
||||
}
|
||||
|
||||
/* 8.c */
|
||||
ecma_collection_t *values_p = ecma_new_collection ();
|
||||
ecma_value_t ret_value = ECMA_VALUE_EMPTY;
|
||||
|
||||
/* 8.e */
|
||||
while (true)
|
||||
{
|
||||
/* 8.e.i */
|
||||
ecma_value_t next = ecma_op_iterator_step (iterator);
|
||||
|
||||
/* 8.e.ii */
|
||||
if (ECMA_IS_VALUE_ERROR (next))
|
||||
{
|
||||
ret_value = next;
|
||||
break;
|
||||
}
|
||||
|
||||
if (next == ECMA_VALUE_FALSE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* 8.e.iii */
|
||||
ecma_value_t next_value = ecma_op_iterator_value (next);
|
||||
ecma_free_value (next);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (next_value))
|
||||
{
|
||||
ret_value = next_value;
|
||||
break;
|
||||
}
|
||||
|
||||
ecma_collection_push_back (values_p, next_value);
|
||||
}
|
||||
|
||||
ecma_free_value (iterator);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (ret_value))
|
||||
{
|
||||
ecma_collection_free (values_p);
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
/* 8.g */
|
||||
ecma_value_t new_typedarray = ecma_typedarray_create_object_with_length (values_p->item_count,
|
||||
NULL,
|
||||
proto_p,
|
||||
element_size_shift,
|
||||
typedarray_id);
|
||||
|
||||
/* 8.h */
|
||||
if (ECMA_IS_VALUE_ERROR (new_typedarray))
|
||||
{
|
||||
ecma_collection_free (values_p);
|
||||
return new_typedarray;
|
||||
}
|
||||
|
||||
ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray);
|
||||
ecma_typedarray_info_t info = ecma_typedarray_get_info (new_typedarray_p);
|
||||
ecma_typedarray_setter_fn_t setter_cb = ecma_get_typedarray_setter_fn (info.id);
|
||||
|
||||
ret_value = ecma_make_object_value (new_typedarray_p);
|
||||
|
||||
/* 8.j */
|
||||
for (uint32_t index = 0; index < values_p->item_count; index++)
|
||||
{
|
||||
ecma_value_t set_value = ecma_op_typedarray_from_helper (this_val,
|
||||
values_p->buffer_p[index],
|
||||
index,
|
||||
func_object_p,
|
||||
&info,
|
||||
setter_cb);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (set_value))
|
||||
{
|
||||
for (uint32_t j = index + 1; j < values_p->item_count; j++)
|
||||
{
|
||||
ecma_free_value (values_p->buffer_p[j]);
|
||||
}
|
||||
|
||||
ret_value = set_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ecma_collection_destroy (values_p);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (ret_value))
|
||||
{
|
||||
ecma_deref_object (new_typedarray_p);
|
||||
}
|
||||
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
/* 10 */
|
||||
ecma_value_t arraylike_object_val = ecma_op_to_object (items_val);
|
||||
|
||||
@@ -713,7 +889,6 @@ ecma_op_typedarray_from (ecma_value_t items_val, /**< the source array-like obje
|
||||
uint32_t len;
|
||||
ecma_value_t len_value = ecma_op_object_get_length (arraylike_object_p, &len);
|
||||
|
||||
ecma_value_t ret_value = ECMA_VALUE_ERROR;
|
||||
if (ECMA_IS_VALUE_ERROR (len_value))
|
||||
{
|
||||
ecma_deref_object (arraylike_object_p);
|
||||
@@ -736,71 +911,43 @@ ecma_op_typedarray_from (ecma_value_t items_val, /**< the source array-like obje
|
||||
ecma_object_t *new_typedarray_p = ecma_get_object_from_value (new_typedarray);
|
||||
ecma_typedarray_info_t info = ecma_typedarray_get_info (new_typedarray_p);
|
||||
ecma_typedarray_setter_fn_t setter_cb = ecma_get_typedarray_setter_fn (info.id);
|
||||
ecma_number_t num_var;
|
||||
ecma_value_t ret_value = ecma_make_object_value (new_typedarray_p);
|
||||
|
||||
/* 17 */
|
||||
for (uint32_t index = 0; index < len; index++)
|
||||
{
|
||||
/* 17.b */
|
||||
ecma_value_t current_value = ecma_op_object_find_by_uint32_index (arraylike_object_p, index);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (current_value))
|
||||
{
|
||||
goto cleanup;
|
||||
ret_value = current_value;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ecma_is_value_found (current_value))
|
||||
{
|
||||
ecma_value_t mapped_value;
|
||||
if (func_object_p != NULL)
|
||||
ecma_value_t set_value = ecma_op_typedarray_from_helper (this_val,
|
||||
current_value,
|
||||
index,
|
||||
func_object_p,
|
||||
&info,
|
||||
setter_cb);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (set_value))
|
||||
{
|
||||
/* 17.d 17.f */
|
||||
ecma_value_t current_index = ecma_make_uint32_value (index);
|
||||
ecma_value_t call_args[] = { current_value, current_index };
|
||||
|
||||
ecma_value_t cb_value = ecma_op_function_call (func_object_p, this_val, call_args, 2);
|
||||
|
||||
ecma_free_value (current_index);
|
||||
ecma_free_value (current_value);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (cb_value))
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
mapped_value = cb_value;
|
||||
ret_value = set_value;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
mapped_value = current_value;
|
||||
}
|
||||
|
||||
ecma_value_t mapped_number = ecma_get_number (mapped_value, &num_var);
|
||||
ecma_free_value (mapped_value);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (mapped_number))
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (index >= info.length)
|
||||
{
|
||||
ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type."));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ecma_length_t byte_pos = (index << info.shift);
|
||||
setter_cb (info.buffer_p + byte_pos, num_var);
|
||||
}
|
||||
}
|
||||
|
||||
ecma_ref_object (new_typedarray_p);
|
||||
ret_value = ecma_make_object_value (new_typedarray_p);
|
||||
|
||||
cleanup:
|
||||
ecma_deref_object (new_typedarray_p);
|
||||
ecma_deref_object (arraylike_object_p);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (ret_value))
|
||||
{
|
||||
ecma_deref_object (new_typedarray_p);
|
||||
}
|
||||
|
||||
return ret_value;
|
||||
} /* ecma_op_typedarray_from */
|
||||
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
// Copyright JS Foundation and other contributors, http://js.foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
var typedArrayConstructors = [
|
||||
Uint8Array,
|
||||
Int8Array,
|
||||
Uint16Array,
|
||||
Int16Array,
|
||||
Uint32Array,
|
||||
Int32Array,
|
||||
Uint8ClampedArray,
|
||||
Float32Array,
|
||||
Float64Array
|
||||
];
|
||||
|
||||
var set = new Set([1,2,3]);
|
||||
|
||||
var foo = {};
|
||||
var bar = {};
|
||||
var weak_set = new WeakSet();
|
||||
weak_set.add(foo);
|
||||
weak_set.add(bar);
|
||||
|
||||
var string = new String('123');
|
||||
|
||||
var map = new Map();
|
||||
map.set(0, 'zero');
|
||||
map.set(1, 'one');
|
||||
|
||||
var weak_map = new WeakMap();
|
||||
weak_map.set(foo, 'foo');
|
||||
weak_map.set(bar, 'bar');
|
||||
|
||||
var string = '123';
|
||||
|
||||
for (var constructor of typedArrayConstructors)
|
||||
{
|
||||
assert(constructor.from.length === 1);
|
||||
|
||||
try {
|
||||
function f() {constructor.from.call(Array, []);}
|
||||
} catch (e) {
|
||||
assert(e instanceof TypeError);
|
||||
}
|
||||
|
||||
assert(constructor.from(set).toString() === '1,2,3');
|
||||
assert(constructor.from(weak_set).toString() === '');
|
||||
|
||||
if (constructor == Float32Array || constructor == Float64Array)
|
||||
{
|
||||
assert(constructor.from(map).toString() === 'NaN,NaN');
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(constructor.from(map).toString() === '0,0');
|
||||
}
|
||||
|
||||
assert(constructor.from(weak_map).toString() === '');
|
||||
assert(constructor.from(string).toString() === '1,2,3');
|
||||
|
||||
try {
|
||||
function f() {constructor.from.call({}, []);}
|
||||
} catch (e) {
|
||||
assert(e instanceof TypeError);
|
||||
}
|
||||
|
||||
try {
|
||||
function f() {constructor.from.call([], []);}
|
||||
} catch (e) {
|
||||
assert(e instanceof TypeError);
|
||||
}
|
||||
|
||||
try {
|
||||
function f() {constructor.from.call(1, []);}
|
||||
} catch (e) {
|
||||
assert(e instanceof TypeError);
|
||||
}
|
||||
|
||||
try {
|
||||
function f() {constructor.from.call(undefined, []);}
|
||||
} catch (e) {
|
||||
assert(e instanceof TypeError);
|
||||
}
|
||||
|
||||
assert(constructor.from([1,2,3,4]).toString() === '1,2,3,4');
|
||||
assert(constructor.from([12,45]).toString() === '12,45');
|
||||
assert(constructor.from(NaN).toString() === '');
|
||||
assert(constructor.from(Infinity).toString() === '');
|
||||
|
||||
assert(constructor.from([4,5,6], x => x + 1).toString() === '5,6,7');
|
||||
assert(constructor.from([2,4,8], x => x * 2).toString() === '4,8,16');
|
||||
|
||||
try {
|
||||
constructor.from([1,2,3], x => {throw 5});
|
||||
assert(false);
|
||||
} catch (e) {
|
||||
assert(e === 5);
|
||||
}
|
||||
|
||||
try {
|
||||
constructor.from([Symbol.match]);
|
||||
assert(false);
|
||||
} catch (e) {
|
||||
assert(e instanceof TypeError);
|
||||
}
|
||||
|
||||
try {
|
||||
constructor.from([1,1,1], 'foo');
|
||||
assert(false);
|
||||
} catch (e) {
|
||||
assert (e instanceof TypeError);
|
||||
}
|
||||
|
||||
try {
|
||||
function f() {constructor.from(null)}
|
||||
} catch (e) {
|
||||
assert(e instanceof TypeError);
|
||||
}
|
||||
|
||||
try {
|
||||
function f() {constructor.from(undefined);}
|
||||
} catch (e) {
|
||||
assert(e instanceof TypeError);
|
||||
}
|
||||
|
||||
var called = 0;
|
||||
var arr = [1,2,3];
|
||||
var obj = {};
|
||||
|
||||
function testIterator() {
|
||||
called++;
|
||||
return arr[Symbol.iterator]();
|
||||
}
|
||||
|
||||
var getCalled = 0;
|
||||
Object.defineProperty(obj, Symbol.iterator, {
|
||||
get: function() {
|
||||
getCalled++;
|
||||
return testIterator;
|
||||
},
|
||||
});
|
||||
|
||||
assert(constructor.from(obj).toString() === '1,2,3');
|
||||
assert(called === 1);
|
||||
assert(getCalled === 1);
|
||||
}
|
||||
Reference in New Issue
Block a user