Rewrite Function.bind as a builtin
[WebKit.git] / Source / JavaScriptCore / runtime / ObjectConstructor.cpp
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2008 Apple Inc. All rights reserved.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20
21 #include "config.h"
22 #include "ObjectConstructor.h"
23
24 #include "ButterflyInlines.h"
25 #include "CopiedSpaceInlines.h"
26 #include "Error.h"
27 #include "ExceptionHelpers.h"
28 #include "JSFunction.h"
29 #include "JSArray.h"
30 #include "JSGlobalObject.h"
31 #include "Lookup.h"
32 #include "ObjectPrototype.h"
33 #include "JSCInlines.h"
34 #include "PropertyDescriptor.h"
35 #include "PropertyNameArray.h"
36 #include "StackVisitor.h"
37
38 namespace JSC {
39
40 static EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*);
41 static EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*);
42 static EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*);
43 static EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState*);
44 static EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*);
45 static EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*);
46 static EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState*);
47 static EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState*);
48 static EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState*);
49 static EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState*);
50 static EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState*);
51 static EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState*);
52 static EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState*);
53
54 }
55
56 #include "ObjectConstructor.lut.h"
57
58 namespace JSC {
59
60 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ObjectConstructor);
61
62 const ClassInfo ObjectConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::objectConstructorTable, CREATE_METHOD_TABLE(ObjectConstructor) };
63
64 /* Source for ObjectConstructor.lut.h
65 @begin objectConstructorTable
66   getPrototypeOf            objectConstructorGetPrototypeOf             DontEnum|Function 1
67   getOwnPropertyDescriptor  objectConstructorGetOwnPropertyDescriptor   DontEnum|Function 2
68   getOwnPropertyNames       objectConstructorGetOwnPropertyNames        DontEnum|Function 1
69   keys                      objectConstructorKeys                       DontEnum|Function 1
70   defineProperty            objectConstructorDefineProperty             DontEnum|Function 3
71   defineProperties          objectConstructorDefineProperties           DontEnum|Function 2
72   create                    objectConstructorCreate                     DontEnum|Function 2
73   seal                      objectConstructorSeal                       DontEnum|Function 1
74   freeze                    objectConstructorFreeze                     DontEnum|Function 1
75   preventExtensions         objectConstructorPreventExtensions          DontEnum|Function 1
76   isSealed                  objectConstructorIsSealed                   DontEnum|Function 1
77   isFrozen                  objectConstructorIsFrozen                   DontEnum|Function 1
78   isExtensible              objectConstructorIsExtensible               DontEnum|Function 1
79 @end
80 */
81
82 ObjectConstructor::ObjectConstructor(VM& vm, Structure* structure)
83     : InternalFunction(vm, structure)
84 {
85 }
86
87 void ObjectConstructor::finishCreation(VM& vm, ObjectPrototype* objectPrototype)
88 {
89     Base::finishCreation(vm, Identifier(&vm, "Object").string());
90     // ECMA 15.2.3.1
91     putDirectPrototypePropertyWithoutTransitions(vm, objectPrototype, DontEnum | DontDelete | ReadOnly);
92     // no. of arguments for constructor
93     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
94 }
95
96 bool ObjectConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
97 {
98     return getStaticFunctionSlot<JSObject>(exec, ExecState::objectConstructorTable(exec->vm()), jsCast<ObjectConstructor*>(object), propertyName, slot);
99 }
100
101 static ALWAYS_INLINE JSObject* constructObject(ExecState* exec)
102 {
103     JSGlobalObject* globalObject = exec->callee()->globalObject();
104     ArgList args(exec);
105     JSValue arg = args.at(0);
106     if (arg.isUndefinedOrNull())
107         return constructEmptyObject(exec, globalObject->objectPrototype());
108     return arg.toObject(exec, globalObject);
109 }
110
111 static EncodedJSValue JSC_HOST_CALL constructWithObjectConstructor(ExecState* exec)
112 {
113     return JSValue::encode(constructObject(exec));
114 }
115
116 ConstructType ObjectConstructor::getConstructData(JSCell*, ConstructData& constructData)
117 {
118     constructData.native.function = constructWithObjectConstructor;
119     return ConstructTypeHost;
120 }
121
122 static EncodedJSValue JSC_HOST_CALL callObjectConstructor(ExecState* exec)
123 {
124     return JSValue::encode(constructObject(exec));
125 }
126
127 CallType ObjectConstructor::getCallData(JSCell*, CallData& callData)
128 {
129     callData.native.function = callObjectConstructor;
130     return CallTypeHost;
131 }
132
133 class ObjectConstructorGetPrototypeOfFunctor {
134 public:
135     ObjectConstructorGetPrototypeOfFunctor(JSObject* object)
136         : m_hasSkippedFirstFrame(false)
137         , m_object(object)
138         , m_result(JSValue::encode(jsUndefined()))
139     {
140     }
141
142     EncodedJSValue result() const { return m_result; }
143
144     StackVisitor::Status operator()(StackVisitor& visitor)
145     {
146         if (!m_hasSkippedFirstFrame) {
147             m_hasSkippedFirstFrame = true;
148             return StackVisitor::Continue;
149         }
150
151     if (m_object->allowsAccessFrom(visitor->callFrame()))
152         m_result = JSValue::encode(m_object->prototype());
153     return StackVisitor::Done;
154 }
155
156 private:
157     bool m_hasSkippedFirstFrame;
158     JSObject* m_object;
159     EncodedJSValue m_result;
160 };
161
162 EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec)
163 {
164     if (!exec->argument(0).isObject())
165         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested prototype of a value that is not an object.")));
166     JSObject* object = asObject(exec->argument(0));
167     ObjectConstructorGetPrototypeOfFunctor functor(object);
168     exec->iterate(functor);
169     return functor.result();
170 }
171
172 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec)
173 {
174     if (!exec->argument(0).isObject())
175         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested property descriptor of a value that is not an object.")));
176     String propertyName = exec->argument(1).toString(exec)->value(exec);
177     if (exec->hadException())
178         return JSValue::encode(jsNull());
179     JSObject* object = asObject(exec->argument(0));
180     PropertyDescriptor descriptor;
181     if (!object->getOwnPropertyDescriptor(exec, Identifier(exec, propertyName), descriptor))
182         return JSValue::encode(jsUndefined());
183     if (exec->hadException())
184         return JSValue::encode(jsUndefined());
185
186     JSObject* description = constructEmptyObject(exec);
187     if (!descriptor.isAccessorDescriptor()) {
188         description->putDirect(exec->vm(), exec->propertyNames().value, descriptor.value() ? descriptor.value() : jsUndefined(), 0);
189         description->putDirect(exec->vm(), exec->propertyNames().writable, jsBoolean(descriptor.writable()), 0);
190     } else {
191         ASSERT(descriptor.getter());
192         ASSERT(descriptor.setter());
193         description->putDirect(exec->vm(), exec->propertyNames().get, descriptor.getter(), 0);
194         description->putDirect(exec->vm(), exec->propertyNames().set, descriptor.setter(), 0);
195     }
196     
197     description->putDirect(exec->vm(), exec->propertyNames().enumerable, jsBoolean(descriptor.enumerable()), 0);
198     description->putDirect(exec->vm(), exec->propertyNames().configurable, jsBoolean(descriptor.configurable()), 0);
199
200     return JSValue::encode(description);
201 }
202
203 // FIXME: Use the enumeration cache.
204 EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exec)
205 {
206     if (!exec->argument(0).isObject())
207         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested property names of a value that is not an object.")));
208     PropertyNameArray properties(exec);
209     asObject(exec->argument(0))->methodTable(exec->vm())->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, IncludeDontEnumProperties);
210     JSArray* names = constructEmptyArray(exec, 0);
211     size_t numProperties = properties.size();
212     for (size_t i = 0; i < numProperties; i++)
213         names->push(exec, jsOwnedString(exec, properties[i].string()));
214     return JSValue::encode(names);
215 }
216
217 // FIXME: Use the enumeration cache.
218 EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec)
219 {
220     if (!exec->argument(0).isObject())
221         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested keys of a value that is not an object.")));
222     PropertyNameArray properties(exec);
223     asObject(exec->argument(0))->methodTable(exec->vm())->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, ExcludeDontEnumProperties);
224     JSArray* keys = constructEmptyArray(exec, 0);
225     size_t numProperties = properties.size();
226     for (size_t i = 0; i < numProperties; i++)
227         keys->push(exec, jsOwnedString(exec, properties[i].string()));
228     return JSValue::encode(keys);
229 }
230
231 // ES5 8.10.5 ToPropertyDescriptor
232 static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor& desc)
233 {
234     if (!in.isObject()) {
235         exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Property description must be an object.")));
236         return false;
237     }
238     JSObject* description = asObject(in);
239
240     PropertySlot enumerableSlot(description);
241     if (description->getPropertySlot(exec, exec->propertyNames().enumerable, enumerableSlot)) {
242         desc.setEnumerable(enumerableSlot.getValue(exec, exec->propertyNames().enumerable).toBoolean(exec));
243         if (exec->hadException())
244             return false;
245     }
246
247     PropertySlot configurableSlot(description);
248     if (description->getPropertySlot(exec, exec->propertyNames().configurable, configurableSlot)) {
249         desc.setConfigurable(configurableSlot.getValue(exec, exec->propertyNames().configurable).toBoolean(exec));
250         if (exec->hadException())
251             return false;
252     }
253
254     JSValue value;
255     PropertySlot valueSlot(description);
256     if (description->getPropertySlot(exec, exec->propertyNames().value, valueSlot)) {
257         desc.setValue(valueSlot.getValue(exec, exec->propertyNames().value));
258         if (exec->hadException())
259             return false;
260     }
261
262     PropertySlot writableSlot(description);
263     if (description->getPropertySlot(exec, exec->propertyNames().writable, writableSlot)) {
264         desc.setWritable(writableSlot.getValue(exec, exec->propertyNames().writable).toBoolean(exec));
265         if (exec->hadException())
266             return false;
267     }
268
269     PropertySlot getSlot(description);
270     if (description->getPropertySlot(exec, exec->propertyNames().get, getSlot)) {
271         JSValue get = getSlot.getValue(exec, exec->propertyNames().get);
272         if (exec->hadException())
273             return false;
274         if (!get.isUndefined()) {
275             CallData callData;
276             if (getCallData(get, callData) == CallTypeNone) {
277                 exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Getter must be a function.")));
278                 return false;
279             }
280         }
281         desc.setGetter(get);
282     }
283
284     PropertySlot setSlot(description);
285     if (description->getPropertySlot(exec, exec->propertyNames().set, setSlot)) {
286         JSValue set = setSlot.getValue(exec, exec->propertyNames().set);
287         if (exec->hadException())
288             return false;
289         if (!set.isUndefined()) {
290             CallData callData;
291             if (getCallData(set, callData) == CallTypeNone) {
292                 exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Setter must be a function.")));
293                 return false;
294             }
295         }
296         desc.setSetter(set);
297     }
298
299     if (!desc.isAccessorDescriptor())
300         return true;
301
302     if (desc.value()) {
303         exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Invalid property.  'value' present on property with getter or setter.")));
304         return false;
305     }
306
307     if (desc.writablePresent()) {
308         exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Invalid property.  'writable' present on property with getter or setter.")));
309         return false;
310     }
311     return true;
312 }
313
314 EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState* exec)
315 {
316     if (!exec->argument(0).isObject())
317         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Properties can only be defined on Objects.")));
318     JSObject* O = asObject(exec->argument(0));
319     String propertyName = exec->argument(1).toString(exec)->value(exec);
320     if (exec->hadException())
321         return JSValue::encode(jsNull());
322     PropertyDescriptor descriptor;
323     if (!toPropertyDescriptor(exec, exec->argument(2), descriptor))
324         return JSValue::encode(jsNull());
325     ASSERT((descriptor.attributes() & Accessor) || (!descriptor.isAccessorDescriptor()));
326     ASSERT(!exec->hadException());
327     O->methodTable(exec->vm())->defineOwnProperty(O, exec, Identifier(exec, propertyName), descriptor, true);
328     return JSValue::encode(O);
329 }
330
331 static JSValue defineProperties(ExecState* exec, JSObject* object, JSObject* properties)
332 {
333     PropertyNameArray propertyNames(exec);
334     asObject(properties)->methodTable(exec->vm())->getOwnPropertyNames(asObject(properties), exec, propertyNames, ExcludeDontEnumProperties);
335     size_t numProperties = propertyNames.size();
336     Vector<PropertyDescriptor> descriptors;
337     MarkedArgumentBuffer markBuffer;
338     for (size_t i = 0; i < numProperties; i++) {
339         JSValue prop = properties->get(exec, propertyNames[i]);
340         if (exec->hadException())
341             return jsNull();
342         PropertyDescriptor descriptor;
343         if (!toPropertyDescriptor(exec, prop, descriptor))
344             return jsNull();
345         descriptors.append(descriptor);
346         // Ensure we mark all the values that we're accumulating
347         if (descriptor.isDataDescriptor() && descriptor.value())
348             markBuffer.append(descriptor.value());
349         if (descriptor.isAccessorDescriptor()) {
350             if (descriptor.getter())
351                 markBuffer.append(descriptor.getter());
352             if (descriptor.setter())
353                 markBuffer.append(descriptor.setter());
354         }
355     }
356     for (size_t i = 0; i < numProperties; i++) {
357         object->methodTable(exec->vm())->defineOwnProperty(object, exec, propertyNames[i], descriptors[i], true);
358         if (exec->hadException())
359             return jsNull();
360     }
361     return object;
362 }
363
364 EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState* exec)
365 {
366     if (!exec->argument(0).isObject())
367         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Properties can only be defined on Objects.")));
368     return JSValue::encode(defineProperties(exec, asObject(exec->argument(0)), exec->argument(1).toObject(exec)));
369 }
370
371 EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec)
372 {
373     JSValue proto = exec->argument(0);
374     if (!proto.isObject() && !proto.isNull())
375         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object prototype may only be an Object or null.")));
376     JSObject* newObject = proto.isObject()
377         ? constructEmptyObject(exec, asObject(proto))
378         : constructEmptyObject(exec, exec->lexicalGlobalObject()->nullPrototypeObjectStructure());
379     if (exec->argument(1).isUndefined())
380         return JSValue::encode(newObject);
381     if (!exec->argument(1).isObject())
382         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Property descriptor list must be an Object.")));
383     return JSValue::encode(defineProperties(exec, newObject, asObject(exec->argument(1))));
384 }
385
386 EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec)
387 {
388     // 1. If Type(O) is not Object throw a TypeError exception.
389     JSValue obj = exec->argument(0);
390     if (!obj.isObject())
391         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.seal can only be called on Objects.")));
392     JSObject* object = asObject(obj);
393
394     if (isJSFinalObject(object)) {
395         object->seal(exec->vm());
396         return JSValue::encode(obj);
397     }
398
399     // 2. For each named own property name P of O,
400     PropertyNameArray properties(exec);
401     object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties);
402     PropertyNameArray::const_iterator end = properties.end();
403     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
404         // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
405         PropertyDescriptor desc;
406         if (!object->getOwnPropertyDescriptor(exec, *iter, desc))
407             continue;
408         // b. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
409         desc.setConfigurable(false);
410         // c. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
411         object->methodTable(exec->vm())->defineOwnProperty(object, exec, *iter, desc, true);
412         if (exec->hadException())
413             return JSValue::encode(obj);
414     }
415
416     // 3. Set the [[Extensible]] internal property of O to false.
417     object->preventExtensions(exec->vm());
418
419     // 4. Return O.
420     return JSValue::encode(obj);
421 }
422
423 EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec)
424 {
425     // 1. If Type(O) is not Object throw a TypeError exception.
426     JSValue obj = exec->argument(0);
427     if (!obj.isObject())
428         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.freeze can only be called on Objects.")));
429     JSObject* object = asObject(obj);
430
431     if (isJSFinalObject(object) && !hasIndexedProperties(object->indexingType())) {
432         object->freeze(exec->vm());
433         return JSValue::encode(obj);
434     }
435
436     // 2. For each named own property name P of O,
437     PropertyNameArray properties(exec);
438     object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties);
439     PropertyNameArray::const_iterator end = properties.end();
440     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
441         // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
442         PropertyDescriptor desc;
443         if (!object->getOwnPropertyDescriptor(exec, *iter, desc))
444             continue;
445         // b. If IsDataDescriptor(desc) is true, then
446         // i. If desc.[[Writable]] is true, set desc.[[Writable]] to false.
447         if (desc.isDataDescriptor())
448             desc.setWritable(false);
449         // c. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
450         desc.setConfigurable(false);
451         // d. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
452         object->methodTable(exec->vm())->defineOwnProperty(object, exec, *iter, desc, true);
453         if (exec->hadException())
454             return JSValue::encode(obj);
455     }
456
457     // 3. Set the [[Extensible]] internal property of O to false.
458     object->preventExtensions(exec->vm());
459
460     // 4. Return O.
461     return JSValue::encode(obj);
462 }
463
464 EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState* exec)
465 {
466     JSValue obj = exec->argument(0);
467     if (!obj.isObject())
468         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.preventExtensions can only be called on Objects.")));
469     asObject(obj)->preventExtensions(exec->vm());
470     return JSValue::encode(obj);
471 }
472
473 EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec)
474 {
475     // 1. If Type(O) is not Object throw a TypeError exception.
476     JSValue obj = exec->argument(0);
477     if (!obj.isObject())
478         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.isSealed can only be called on Objects.")));
479     JSObject* object = asObject(obj);
480
481     if (isJSFinalObject(object))
482         return JSValue::encode(jsBoolean(object->isSealed(exec->vm())));
483
484     // 2. For each named own property name P of O,
485     PropertyNameArray properties(exec);
486     object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties);
487     PropertyNameArray::const_iterator end = properties.end();
488     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
489         // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
490         PropertyDescriptor desc;
491         if (!object->getOwnPropertyDescriptor(exec, *iter, desc))
492             continue;
493         // b. If desc.[[Configurable]] is true, then return false.
494         if (desc.configurable())
495             return JSValue::encode(jsBoolean(false));
496     }
497
498     // 3. If the [[Extensible]] internal property of O is false, then return true.
499     // 4. Otherwise, return false.
500     return JSValue::encode(jsBoolean(!object->isExtensible()));
501 }
502
503 EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState* exec)
504 {
505     // 1. If Type(O) is not Object throw a TypeError exception.
506     JSValue obj = exec->argument(0);
507     if (!obj.isObject())
508         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.isFrozen can only be called on Objects.")));
509     JSObject* object = asObject(obj);
510
511     if (isJSFinalObject(object))
512         return JSValue::encode(jsBoolean(object->isFrozen(exec->vm())));
513
514     // 2. For each named own property name P of O,
515     PropertyNameArray properties(exec);
516     object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties);
517     PropertyNameArray::const_iterator end = properties.end();
518     for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
519         // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
520         PropertyDescriptor desc;
521         if (!object->getOwnPropertyDescriptor(exec, *iter, desc))
522             continue;
523         // b. If IsDataDescriptor(desc) is true then
524         // i. If desc.[[Writable]] is true, return false. c. If desc.[[Configurable]] is true, then return false.
525         if ((desc.isDataDescriptor() && desc.writable()) || desc.configurable())
526             return JSValue::encode(jsBoolean(false));
527     }
528
529     // 3. If the [[Extensible]] internal property of O is false, then return true.
530     // 4. Otherwise, return false.
531     return JSValue::encode(jsBoolean(!object->isExtensible()));
532 }
533
534 EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState* exec)
535 {
536     JSValue obj = exec->argument(0);
537     if (!obj.isObject())
538         return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.isExtensible can only be called on Objects.")));
539     return JSValue::encode(jsBoolean(asObject(obj)->isExtensible()));
540 }
541
542 } // namespace JSC