Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_BYTE_LENGTH_UL,
ecma_builtin_arraybuffer_prototype_bytelength_getter,
ECMA_PROPERTY_FIXED)

#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
/* ECMA-262 v6, 24.1.4.4 */
STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG,
LIT_MAGIC_STRING_ARRAY_BUFFER_UL,
ECMA_PROPERTY_FLAG_CONFIGURABLE)
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */

/* Routine properties:
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
ROUTINE (LIT_MAGIC_STRING_SLICE, ecma_builtin_arraybuffer_prototype_object_slice, 2, 2)
Expand Down
85 changes: 84 additions & 1 deletion jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
#include "ecma-conversion.h"
#include "ecma-function-object.h"
#include "ecma-exceptions.h"
#include "ecma-gc.h"
#include "ecma-helpers.h"
#include "jmem.h"
#include "ecma-objects.h"
#include "ecma-try-catch-macro.h"
#include "lit-magic-strings.h"
Expand All @@ -33,6 +35,69 @@
* @{
*/

#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
/**
* Helper function for Object.prototype.toString routine when
* the @@toStringTag property is present
*
* See also:
* ECMA-262 v6, 19.1.3.6
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_helper_object_to_string_tag_helper (ecma_value_t tag_value) /**< string tag */
{
JERRY_ASSERT (ecma_is_value_string (tag_value));

ecma_string_t *tag_str_p = ecma_get_string_from_value (tag_value);
ecma_string_t *ret_string_p;

/* Building string "[object #@@toStringTag#]"
The string size will be size("[object ") + size(#@@toStringTag#) + size ("]"). */
const lit_utf8_size_t buffer_size = 9 + ecma_string_get_size (tag_str_p);
JMEM_DEFINE_LOCAL_ARRAY (str_buffer, buffer_size, lit_utf8_byte_t);

lit_utf8_byte_t *buffer_ptr = str_buffer;

const lit_magic_string_id_t magic_string_ids[] =
{
LIT_MAGIC_STRING_LEFT_SQUARE_CHAR,
LIT_MAGIC_STRING_OBJECT,
LIT_MAGIC_STRING_SPACE_CHAR,
};

/* Copy to buffer the "[object " string */
for (uint32_t i = 0; i < sizeof (magic_string_ids) / sizeof (lit_magic_string_id_t); ++i)
{
buffer_ptr = lit_copy_magic_string_to_buffer (magic_string_ids[i], buffer_ptr,
(lit_utf8_size_t) ((str_buffer + buffer_size) - buffer_ptr));

JERRY_ASSERT (buffer_ptr <= str_buffer + buffer_size);
}

/* Copy to buffer the #@@toStringTag# string */
buffer_ptr += ecma_string_copy_to_utf8_buffer (tag_str_p, buffer_ptr,
(lit_utf8_size_t) ((str_buffer + buffer_size) - buffer_ptr));

JERRY_ASSERT (buffer_ptr <= str_buffer + buffer_size);

/* Copy to buffer the "]" string */
buffer_ptr = lit_copy_magic_string_to_buffer (LIT_MAGIC_STRING_RIGHT_SQUARE_CHAR, buffer_ptr,
(lit_utf8_size_t) ((str_buffer + buffer_size) - buffer_ptr));

JERRY_ASSERT (buffer_ptr <= str_buffer + buffer_size);

ret_string_p = ecma_new_ecma_string_from_utf8 (str_buffer, (lit_utf8_size_t) (buffer_ptr - str_buffer));

JMEM_FINALIZE_LOCAL_ARRAY (str_buffer);
ecma_deref_ecma_string (tag_str_p);

return ecma_make_string_value (ret_string_p);
} /* ecma_builtin_helper_object_to_string_tag_helper */
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */

/**
* Common implementation of the Object.prototype.toString routine
*
Expand Down Expand Up @@ -75,7 +140,25 @@ ecma_builtin_helper_object_to_string (const ecma_value_t this_arg) /**< this arg

type_string = ecma_object_get_class_name (obj_p);

ecma_free_value (obj_this);
#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
ecma_value_t tag_value = ecma_op_object_get_by_symbol_id (obj_p, LIT_MAGIC_STRING_TO_STRING_TAG);

if (ECMA_IS_VALUE_ERROR (tag_value))
{
ecma_deref_object (obj_p);
return tag_value;
}

if (ecma_is_value_string (tag_value))
{
ecma_deref_object (obj_p);
return ecma_builtin_helper_object_to_string_tag_helper (tag_value);
}

ecma_free_value (tag_value);
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */

ecma_deref_object (obj_p);
}

ecma_string_t *ret_string_p;
Expand Down
7 changes: 7 additions & 0 deletions jerry-core/ecma/builtin-objects/ecma-builtin-json.inc.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@

#ifndef CONFIG_DISABLE_JSON_BUILTIN

#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
/* ECMA-262 v6, 24.3.3 */
STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG,
LIT_MAGIC_STRING_JSON_U,
ECMA_PROPERTY_FLAG_CONFIGURABLE)
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */

/* Routine properties:
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
ROUTINE (LIT_MAGIC_STRING_PARSE, ecma_builtin_json_parse, 2, 2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
ECMA_BUILTIN_ID_MAP,
ECMA_PROPERTY_CONFIGURABLE_WRITABLE)

#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
/* ECMA-262 v6, 23.1.3.13 */
STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG,
LIT_MAGIC_STRING_MAP_UL,
ECMA_PROPERTY_FLAG_CONFIGURABLE)
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */

/* Routine properties:
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
ROUTINE (LIT_MAGIC_STRING_CLEAR, ecma_builtin_map_prototype_object_clear, 0, 0)
Expand Down
7 changes: 7 additions & 0 deletions jerry-core/ecma/builtin-objects/ecma-builtin-math.inc.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ NUMBER_VALUE (LIT_MAGIC_STRING_SQRT2_U,
ECMA_BUILTIN_NUMBER_SQRT2,
ECMA_PROPERTY_FIXED)

#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
/* ECMA-262 v6, 20.2.1.9 */
STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG,
LIT_MAGIC_STRING_MATH_UL,
ECMA_PROPERTY_FLAG_CONFIGURABLE)
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */

/* Routine properties:
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
ROUTINE (LIT_MAGIC_STRING_ABS, ECMA_MATH_OBJECT_ABS, 1, 1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
1,
ECMA_PROPERTY_FLAG_WRITABLE)

#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
/* ECMA-262 v6, 25.4.5.4 */
STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG,
LIT_MAGIC_STRING_PROMISE_UL,
ECMA_PROPERTY_FLAG_CONFIGURABLE)
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */

ROUTINE (LIT_MAGIC_STRING_THEN, ecma_builtin_promise_prototype_then, 2, 2)
ROUTINE (LIT_MAGIC_STRING_CATCH, ecma_builtin_promise_prototype_catch, 1, 1)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,28 @@ ecma_builtin_typedarray_prototype_length_getter (ecma_value_t this_arg) /**< thi
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray."));
} /* ecma_builtin_typedarray_prototype_length_getter */

#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
/**
* The %TypedArray%.prototype[Symbol.toStringTag] accessor
*
* See also:
* ES2015, 22.2.3.31
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_typedarray_prototype_to_string_tag_getter (ecma_value_t this_arg) /**< this argument */
{
if (!ecma_is_typedarray (this_arg))
{
return ECMA_VALUE_UNDEFINED;
}

return ecma_make_magic_string_value (ecma_object_get_class_name (ecma_get_object_from_value (this_arg)));
} /* ecma_builtin_typedarray_prototype_to_string_tag_getter */
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */

/**
* Type of routine.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_LENGTH,
ecma_builtin_typedarray_prototype_length_getter,
ECMA_PROPERTY_FIXED)

#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
/* ECMA-262 v6, 23.1.3.13 */
ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_TO_STRING_TAG,
ecma_builtin_typedarray_prototype_to_string_tag_getter,
ECMA_PROPERTY_FLAG_CONFIGURABLE)
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */

/* Routine properties:
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
ROUTINE (LIT_MAGIC_STRING_TO_STRING_UL, ecma_builtin_typedarray_prototype_object_to_string, 0, 0)
Expand Down
24 changes: 24 additions & 0 deletions jerry-core/ecma/operations/ecma-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,30 @@ ecma_op_object_get_by_magic_id (ecma_object_t *object_p, /**< the object */
return ecma_op_object_get (object_p, ecma_get_magic_string (property_id));
} /* ecma_op_object_get_by_magic_id */

#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
/**
* [[Get]] operation of ecma object where the property is a well-known symbol
*
* @return ecma value
* Returned value must be freed with ecma_free_value
*/
ecma_value_t
ecma_op_object_get_by_symbol_id (ecma_object_t *object_p, /**< the object */
lit_magic_string_id_t property_id) /**< property symbol id */
{
ecma_value_t symbol_value = ecma_op_object_get_by_magic_id (ecma_builtin_get (ECMA_BUILTIN_ID_SYMBOL),
property_id);
JERRY_ASSERT (ecma_is_value_symbol (symbol_value));

ecma_string_t *symbol_p = ecma_get_symbol_from_value (symbol_value);
ecma_value_t ret_value = ecma_op_object_get (object_p, symbol_p);

ecma_deref_ecma_string (symbol_p);

return ret_value;
} /* ecma_op_object_get_by_symbol_id */
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */

/**
* [[Put]] ecma general object's operation
*
Expand Down
3 changes: 3 additions & 0 deletions jerry-core/ecma/operations/ecma-objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ ecma_value_t ecma_op_object_find (ecma_object_t *object_p, ecma_string_t *proper
ecma_value_t ecma_op_object_get_own_data_prop (ecma_object_t *object_p, ecma_string_t *property_name_p);
ecma_value_t ecma_op_object_get (ecma_object_t *object_p, ecma_string_t *property_name_p);
ecma_value_t ecma_op_object_get_by_magic_id (ecma_object_t *object_p, lit_magic_string_id_t property_id);
#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
ecma_value_t ecma_op_object_get_by_symbol_id (ecma_object_t *object_p, lit_magic_string_id_t property_id);
#endif /* CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */
ecma_value_t ecma_op_object_put (ecma_object_t *object_p, ecma_string_t *property_name_p, ecma_value_t value,
bool is_throw);
ecma_value_t ecma_op_object_delete (ecma_object_t *obj_p, ecma_string_t *property_name_p, bool is_throw);
Expand Down
102 changes: 102 additions & 0 deletions tests/jerry/es2015/object-prototype-tostring.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// 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.

/* Symbol prototype @@toStringTag */
assert (Symbol.prototype[Symbol.toStringTag] === "Symbol");
assert (Object.prototype.toString.call (Symbol ()) === "[object Symbol]");

assert (delete Symbol.prototype[Symbol.toStringTag]);
assert (Symbol.prototype[Symbol.toStringTag] === undefined);
Symbol.prototype[Symbol.toStringTag] = "myStringTag1";
assert (Object.prototype.toString.call (Symbol ()) === "[object myStringTag1]");
Symbol.prototype[Symbol.toStringTag] = {};
assert (Object.prototype.toString.call (Symbol ()) === "[object Symbol]");

/* Math @@toStringTag */
assert (Math[Symbol.toStringTag] === "Math");
assert (Object.prototype.toString.call (Math) === "[object Math]");

assert (delete Math[Symbol.toStringTag]);
assert (Math[Symbol.toStringTag] === undefined);
Math[Symbol.toStringTag] = "myStringTag2";
assert (Object.prototype.toString.call (Math) === "[object myStringTag2]");
Math[Symbol.toStringTag] = {};
assert (Object.prototype.toString.call (Math) === "[object Math]");

/* ArrayBuffer.prototype @@toStringTag */
assert (ArrayBuffer.prototype[Symbol.toStringTag] === "ArrayBuffer");
assert (Object.prototype.toString.call (new ArrayBuffer ()) === "[object ArrayBuffer]");

assert (delete ArrayBuffer.prototype[Symbol.toStringTag]);
assert (ArrayBuffer.prototype[Symbol.toStringTag] === undefined);
ArrayBuffer.prototype[Symbol.toStringTag] = "myStringTag3";
assert (Object.prototype.toString.call (new ArrayBuffer ()) === "[object myStringTag3]");
ArrayBuffer.prototype[Symbol.toStringTag] = {};
assert (ArrayBuffer.prototype.toString.call (new ArrayBuffer ()) === "[object ArrayBuffer]");

/* Promise.prototype @@toStringTag */
assert (Promise.prototype[Symbol.toStringTag] === "Promise");
assert (Object.prototype.toString.call (new Promise (function () {})) === "[object Promise]");

assert (delete Promise.prototype[Symbol.toStringTag]);
assert (Promise.prototype[Symbol.toStringTag] === undefined);
Promise.prototype[Symbol.toStringTag] = "myStringTag4";
assert (Object.prototype.toString.call (new Promise (function () {})) === "[object myStringTag4]");
Promise.prototype[Symbol.toStringTag] = {};
assert (Promise.prototype.toString.call (new Promise (function () {})) === "[object Promise]");

/* Map.prototype @@toStringTag */
assert (Map.prototype[Symbol.toStringTag] === "Map");
assert (Object.prototype.toString.call (new Map ()) === "[object Map]");
assert (Object.prototype.toString.call (Map) === "[object Function]");

assert (delete Map.prototype[Symbol.toStringTag]);
assert (Map.prototype[Symbol.toStringTag] === undefined);
Map.prototype[Symbol.toStringTag] = "myStringTag5";
assert (Map.prototype.toString.call (new Map ()) === "[object myStringTag5]");
assert (Object.prototype.toString.call (Map) === "[object Function]");
Map.prototype[Symbol.toStringTag] = {};
assert (Map.prototype.toString.call (new Map) === "[object Map]");

/* JSON @@toStringTag */
assert (JSON[Symbol.toStringTag] === "JSON");
assert (Object.prototype.toString.call (JSON) === "[object JSON]");

assert (delete JSON[Symbol.toStringTag]);
assert (JSON[Symbol.toStringTag] === undefined);
JSON[Symbol.toStringTag] = "myStringTag6";
assert (Map.prototype.toString.call (JSON) === "[object myStringTag6]");
JSON[Symbol.toStringTag] = {};
assert (Object.prototype.toString.call (JSON) === "[object JSON]");

var typedArrayTypes = ["Int8Array",
"Uint8Array",
"Uint8ClampedArray",
"Int16Array",
"Uint16Array",
"Int32Array",
"Uint32Array",
"Float32Array",
"Float64Array"];

for (var i = 0; i < typedArrayTypes.length; i++) {
var typedArray = this[typedArrayTypes[i]];
assert (typedArray.prototype[Symbol.toStringTag] === undefined);
assert (Object.prototype.toString.call (typedArray) === "[object Function]");
assert (Object.prototype.toString.call (typedArray.prototype) === "[object Object]");

var newArray = new typedArray ();
assert (newArray[Symbol.toStringTag] === typedArrayTypes[i]);
assert (Object.prototype.toString.call (newArray) === "[object " + typedArrayTypes[i] + "]");
}