Skip to content

Commit e3861d7

Browse files
committed
Implement Object.freeze and Object.isFrozen function
JerryScript-DCO-1.0-Signed-off-by: Kristof Kosztyo [email protected]
1 parent 2ee469e commit e3861d7

File tree

3 files changed

+213
-7
lines changed

3 files changed

+213
-7
lines changed

jerry-core/ecma/builtin-objects/ecma-builtin-object.cpp

Lines changed: 132 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,82 @@ ecma_builtin_object_object_seal (ecma_value_t this_arg __attr_unused___, /**< 't
259259
* Returned value must be freed with ecma_free_completion_value.
260260
*/
261261
static ecma_completion_value_t
262-
ecma_builtin_object_object_freeze (ecma_value_t this_arg, /**< 'this' argument */
262+
ecma_builtin_object_object_freeze (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */
263263
ecma_value_t arg) /**< routine's argument */
264264
{
265-
ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg);
265+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
266+
267+
// 1.
268+
if (!ecma_is_value_object (arg))
269+
{
270+
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
271+
}
272+
else
273+
{
274+
// 2.
275+
ecma_object_t *obj_p = ecma_get_object_from_value (arg);
276+
277+
ecma_property_t *property_p;
278+
for (property_p = ecma_get_property_list (obj_p);
279+
property_p != NULL && ecma_is_completion_value_empty (ret_value);
280+
property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p))
281+
{
282+
ecma_string_t *property_name_p;
283+
284+
if (property_p->type == ECMA_PROPERTY_NAMEDDATA)
285+
{
286+
property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
287+
property_p->u.named_data_property.name_p);
288+
}
289+
else
290+
if (property_p->type == ECMA_PROPERTY_NAMEDACCESSOR)
291+
{
292+
property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
293+
property_p->u.named_accessor_property.name_p);
294+
}
295+
else
296+
{
297+
continue;
298+
}
299+
300+
// 2.a
301+
ecma_property_descriptor_t prop_desc = ecma_get_property_descriptor_from_property (property_p);
302+
303+
// 2.b
304+
if (property_p->type == ECMA_PROPERTY_NAMEDDATA && ecma_is_property_writable (property_p))
305+
{
306+
prop_desc.is_writable = false;
307+
}
308+
309+
// 2.c
310+
if (ecma_is_property_configurable (property_p))
311+
{
312+
prop_desc.is_configurable = false;
313+
}
314+
315+
// 2.d
316+
ECMA_TRY_CATCH (define_own_prop_ret,
317+
ecma_op_object_define_own_property (obj_p,
318+
property_name_p,
319+
&prop_desc,
320+
true),
321+
ret_value);
322+
ECMA_FINALIZE (define_own_prop_ret);
323+
324+
ecma_free_property_descriptor (&prop_desc);
325+
}
326+
327+
if (ecma_is_completion_value_empty (ret_value))
328+
{
329+
// 3.
330+
ecma_set_object_extensible (obj_p, false);
331+
332+
// 4.
333+
ret_value = ecma_make_normal_completion_value (ecma_copy_value (arg, true));
334+
}
335+
}
336+
337+
return ret_value;
266338
} /* ecma_builtin_object_object_freeze */
267339

268340
/**
@@ -370,10 +442,66 @@ ecma_builtin_object_object_is_sealed (ecma_value_t this_arg __attr_unused___, /*
370442
* Returned value must be freed with ecma_free_completion_value.
371443
*/
372444
static ecma_completion_value_t
373-
ecma_builtin_object_object_is_frozen (ecma_value_t this_arg, /**< 'this' argument */
445+
ecma_builtin_object_object_is_frozen (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */
374446
ecma_value_t arg) /**< routine's argument */
375447
{
376-
ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg);
448+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
449+
450+
// 1.
451+
if (!ecma_is_value_object (arg))
452+
{
453+
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
454+
}
455+
else
456+
{
457+
ecma_object_t *obj_p = ecma_get_object_from_value (arg);
458+
ecma_property_t *property_p;
459+
460+
// This will be the result if the other steps doesn't change it.
461+
bool frozen = false;
462+
463+
// 3.
464+
// The pseudo code contains multiple early return but this way we get the same
465+
// result.
466+
if (!ecma_get_object_extensible (obj_p))
467+
{
468+
frozen = true;
469+
}
470+
471+
// 2.
472+
for (property_p = ecma_get_property_list (obj_p);
473+
property_p != NULL && frozen;
474+
property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p))
475+
{
476+
if (property_p->type == ECMA_PROPERTY_INTERNAL)
477+
{
478+
continue;
479+
}
480+
481+
JERRY_ASSERT (property_p->type == ECMA_PROPERTY_NAMEDDATA || property_p->type == ECMA_PROPERTY_NAMEDACCESSOR);
482+
483+
// 2.b
484+
if (property_p->type == ECMA_PROPERTY_NAMEDDATA && ecma_is_property_writable (property_p))
485+
{
486+
frozen = false;
487+
break;
488+
}
489+
490+
// 2.c
491+
if (ecma_is_property_configurable (property_p))
492+
{
493+
frozen = false;
494+
break;
495+
}
496+
}
497+
498+
// 4.
499+
ret_value = ecma_make_simple_completion_value (frozen
500+
? ECMA_SIMPLE_VALUE_TRUE
501+
: ECMA_SIMPLE_VALUE_FALSE);
502+
}
503+
504+
return ret_value;
377505
} /* ecma_builtin_object_object_is_frozen */
378506

379507
/**

tests/jerry/object-is-extensible.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ try
4242
var sealed = Object.seal({});
4343
assert (Object.isExtensible(sealed) === false);
4444

45-
// The functions below are unimplemented.
4645
// Frozen objects are also by definition non-extensible.
47-
// var frozen = Object.freeze({});
48-
// assert(Object.isExtensible(frozen) === false);
46+
var frozen = Object.freeze({});
47+
assert(Object.isExtensible(frozen) === false);

tests/jerry/object_freeze.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright 2015 Samsung Electronics Co., Ltd.
2+
// Copyright 2015 University of Szeged.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
var obj = {
17+
prop: function() {},
18+
foo: 'bar'
19+
};
20+
21+
// New properties may be added, existing properties may be changed or removed
22+
obj.foo = 'baz';
23+
obj.lumpy = 'woof';
24+
delete obj.prop;
25+
26+
var o = Object.freeze(obj);
27+
28+
assert(Object.isFrozen(obj) === true);
29+
30+
// Now any changes will fail
31+
obj.foo = 'quux'; // silently does nothing
32+
assert (obj.foo === 'baz');
33+
34+
obj.quaxxor = 'the friendly duck'; // silently doesn't add the property
35+
assert (obj.quaxxor === undefined);
36+
37+
// ...and in strict mode such attempts will throw TypeErrors
38+
function fail(){
39+
'use strict';
40+
41+
try {
42+
obj.foo = 'sparky'; // throws a TypeError
43+
assert (false);
44+
} catch (e) {
45+
assert (e instanceof TypeError);
46+
}
47+
48+
try {
49+
delete obj.foo; // throws a TypeError
50+
assert (false);
51+
} catch (e) {
52+
assert (e instanceof TypeError);
53+
}
54+
55+
try {
56+
obj.sparky = 'arf'; // throws a TypeError
57+
assert (false);
58+
} catch (e) {
59+
assert (e instanceof TypeError);
60+
}
61+
}
62+
63+
fail();
64+
65+
// Attempted changes through Object.defineProperty will also throw
66+
67+
try {
68+
Object.defineProperty(obj, 'ohai', { value: 17 }); // throws a TypeError
69+
assert (false);
70+
} catch (e) {
71+
assert (e instanceof TypeError);
72+
}
73+
74+
try {
75+
Object.defineProperty(obj, 'foo', { value: 'eit' }); // throws a TypeError
76+
assert (false);
77+
} catch (e) {
78+
assert (e instanceof TypeError);
79+
}

0 commit comments

Comments
 (0)