Skip to content

Commit 2ee469e

Browse files
committed
Implement Object.seal and Object.isSealed function
JerryScript-DCO-1.0-Signed-off-by: Kristof Kosztyo kkosztyo.u-szeged@partner.samsung.com
1 parent 4836d3b commit 2ee469e

File tree

3 files changed

+207
-7
lines changed

3 files changed

+207
-7
lines changed

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

Lines changed: 118 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,75 @@ ecma_builtin_object_object_get_own_property_names (ecma_value_t this_arg __attr_
178178
* Returned value must be freed with ecma_free_completion_value.
179179
*/
180180
static ecma_completion_value_t
181-
ecma_builtin_object_object_seal (ecma_value_t this_arg, /**< 'this' argument */
181+
ecma_builtin_object_object_seal (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */
182182
ecma_value_t arg) /**< routine's argument */
183183
{
184-
ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg);
184+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
185+
186+
// 1.
187+
if (!ecma_is_value_object (arg))
188+
{
189+
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
190+
}
191+
else
192+
{
193+
// 2.
194+
ecma_object_t *obj_p = ecma_get_object_from_value (arg);
195+
196+
ecma_property_t *property_p;
197+
for (property_p = ecma_get_property_list (obj_p);
198+
property_p != NULL && ecma_is_completion_value_empty (ret_value);
199+
property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p))
200+
{
201+
ecma_string_t *property_name_p;
202+
203+
if (property_p->type == ECMA_PROPERTY_NAMEDDATA)
204+
{
205+
property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
206+
property_p->u.named_data_property.name_p);
207+
}
208+
else if (property_p->type == ECMA_PROPERTY_NAMEDACCESSOR)
209+
{
210+
property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
211+
property_p->u.named_accessor_property.name_p);
212+
}
213+
else
214+
{
215+
continue;
216+
}
217+
218+
// 2.a
219+
ecma_property_descriptor_t prop_desc = ecma_get_property_descriptor_from_property (property_p);
220+
221+
// 2.b
222+
if (ecma_is_property_configurable (property_p))
223+
{
224+
prop_desc.is_configurable = false;
225+
}
226+
227+
// 2.c
228+
ECMA_TRY_CATCH (define_own_prop_ret,
229+
ecma_op_object_define_own_property (obj_p,
230+
property_name_p,
231+
&prop_desc,
232+
true),
233+
ret_value);
234+
ECMA_FINALIZE (define_own_prop_ret);
235+
236+
ecma_free_property_descriptor (&prop_desc);
237+
}
238+
239+
if (ecma_is_completion_value_empty (ret_value))
240+
{
241+
// 3.
242+
ecma_set_object_extensible (obj_p, false);
243+
244+
// 4.
245+
ret_value = ecma_make_normal_completion_value (ecma_copy_value (arg, true));
246+
}
247+
}
248+
249+
return ret_value;
185250
} /* ecma_builtin_object_object_seal */
186251

187252
/**
@@ -240,10 +305,59 @@ ecma_builtin_object_object_prevent_extensions (ecma_value_t this_arg __attr_unus
240305
* Returned value must be freed with ecma_free_completion_value.
241306
*/
242307
static ecma_completion_value_t
243-
ecma_builtin_object_object_is_sealed (ecma_value_t this_arg, /**< 'this' argument */
308+
ecma_builtin_object_object_is_sealed (ecma_value_t this_arg __attr_unused___, /**< 'this' argument */
244309
ecma_value_t arg) /**< routine's argument */
245310
{
246-
ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg);
311+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
312+
313+
// 1.
314+
if (!ecma_is_value_object (arg))
315+
{
316+
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
317+
}
318+
else
319+
{
320+
ecma_object_t *obj_p = ecma_get_object_from_value (arg);
321+
ecma_property_t *property_p;
322+
323+
// This will be the result if the other steps doesn't change it.
324+
bool sealed = false;
325+
326+
// 3.
327+
// The pseudo code contains multiple early return but this way we get the same
328+
// result.
329+
if (!ecma_get_object_extensible (obj_p))
330+
{
331+
sealed = true;
332+
}
333+
334+
// 2.
335+
for (property_p = ecma_get_property_list (obj_p);
336+
property_p != NULL && sealed;
337+
property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p))
338+
{
339+
if (property_p->type == ECMA_PROPERTY_INTERNAL)
340+
{
341+
continue;
342+
}
343+
344+
JERRY_ASSERT (property_p->type == ECMA_PROPERTY_NAMEDDATA || property_p->type == ECMA_PROPERTY_NAMEDACCESSOR);
345+
346+
// 2.b
347+
if (ecma_is_property_configurable (property_p))
348+
{
349+
sealed = false;
350+
break;
351+
}
352+
}
353+
354+
// 4.
355+
ret_value = ecma_make_simple_completion_value (sealed
356+
? ECMA_SIMPLE_VALUE_TRUE
357+
: ECMA_SIMPLE_VALUE_FALSE);
358+
}
359+
360+
return ret_value;
247361
} /* ecma_builtin_object_object_is_sealed */
248362

249363
/**

tests/jerry/object-is-extensible.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ try
3838
assert (e instanceof TypeError);
3939
}
4040

41-
// The functions below are unimplemented.
4241
// Sealed objects are by definition non-extensible.
43-
// var sealed = Object.seal({});
44-
// assert(Object.isExtensible(sealed) === false);
42+
var sealed = Object.seal({});
43+
assert (Object.isExtensible(sealed) === false);
4544

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

tests/jerry/object_seal.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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+
// New properties may be added, existing properties may be changed or removed.
21+
obj.foo = 'baz';
22+
obj.lumpy = 'woof';
23+
delete obj.prop;
24+
25+
var o = Object.seal(obj);
26+
27+
assert (o === obj);
28+
assert (Object.isSealed (obj) === true);
29+
30+
// Changing property values on a sealed object still works.
31+
obj.foo = 'quux';
32+
assert (obj.foo === 'quux');
33+
// But you can't convert data properties to accessors, or vice versa.
34+
try {
35+
Object.defineProperty(obj, 'foo', { get: function() { return 42; } }); // throws a TypeError
36+
assert (false);
37+
} catch (e) {
38+
assert (e instanceof TypeError);
39+
}
40+
41+
// Now any changes, other than to property values, will fail.
42+
obj.quaxxor = 'the friendly duck'; // silently doesn't add the property
43+
delete obj.foo; // silently doesn't delete the property
44+
45+
assert (obj.quaxxor === undefined);
46+
assert (obj.foo === 'quux')
47+
48+
try {
49+
// Attempted additions through Object.defineProperty will also throw.
50+
Object.defineProperty (obj, 'ohai', { value: 17 }); // throws a TypeError
51+
assert (false);
52+
} catch (e) {
53+
assert (e instanceof TypeError);
54+
}
55+
56+
try {
57+
Object.defineProperties (obj, { 'ohai' : { value: 17 } });
58+
assert (false);
59+
} catch (e) {
60+
assert (e instanceof TypeError);
61+
}
62+
63+
Object.defineProperty (obj, 'foo', { value: 'eit' });
64+
assert (obj.foo === 'eit')
65+
66+
// Objects aren't sealed by default.
67+
var empty = {};
68+
assert (Object.isSealed (empty) === false);
69+
70+
// If you make an empty object non-extensible, it is vacuously sealed.
71+
Object.preventExtensions (empty);
72+
assert (Object.isSealed (empty) === true);
73+
74+
// The same is not true of a non-empty object, unless its properties are all non-configurable.
75+
var hasProp = { fee: 'fie foe fum' };
76+
Object.preventExtensions (hasProp);
77+
assert (Object.isSealed (hasProp) === false);
78+
79+
// But make them all non-configurable and the object becomes sealed.
80+
Object.defineProperty (hasProp, 'fee', { configurable: false });
81+
assert (Object.isSealed (hasProp) === true);
82+
83+
// The easiest way to seal an object, of course, is Object.seal.
84+
var sealed = {};
85+
Object.seal (sealed);
86+
assert (Object.isSealed (sealed) === true);

0 commit comments

Comments
 (0)