1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 Crimson AS <info@crimson.no>
4 ** Copyright (C) 2016 The Qt Company Ltd.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtQml module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 
42 #include "qv4objectproto_p.h"
43 #include "qv4argumentsobject_p.h"
44 #include <private/qv4mm_p.h>
45 #include "qv4scopedvalue_p.h"
46 #include "qv4runtime_p.h"
47 #include "qv4objectiterator_p.h"
48 #include "qv4string_p.h"
49 #include "qv4jscall_p.h"
50 #include "qv4symbol_p.h"
51 #include "qv4propertykey_p.h"
52 
53 #include <QtCore/QDateTime>
54 #include <QtCore/QStringList>
55 
56 using namespace QV4;
57 
58 
59 DEFINE_OBJECT_VTABLE(ObjectCtor);
60 
init(QV4::ExecutionContext * scope)61 void Heap::ObjectCtor::init(QV4::ExecutionContext *scope)
62 {
63     Heap::FunctionObject::init(scope, QStringLiteral("Object"));
64 }
65 
virtualCallAsConstructor(const FunctionObject * f,const Value * argv,int argc,const Value * newTarget)66 ReturnedValue ObjectCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
67 {
68     ExecutionEngine *v4 = f->engine();
69     const ObjectCtor *nt = static_cast<const ObjectCtor *>(newTarget);
70     if (!argc || argv[0].isUndefined() || argv[0].isNull()) {
71         Scope scope(v4);
72         ScopedObject obj(scope, scope.engine->newObject());
73         ScopedObject proto(scope, nt->get(scope.engine->id_prototype()));
74         if (!!proto)
75             obj->setPrototypeOf(proto);
76         return obj.asReturnedValue();
77     } else {
78         return argv[0].toObject(v4)->asReturnedValue();
79     }
80 }
81 
virtualCall(const FunctionObject * m,const Value *,const Value * argv,int argc)82 ReturnedValue ObjectCtor::virtualCall(const FunctionObject *m, const Value *, const Value *argv, int argc)
83 {
84     ExecutionEngine *v4 = m->engine();
85     if (!argc || argv[0].isUndefined() || argv[0].isNull()) {
86         return v4->newObject()->asReturnedValue();
87     } else {
88         return argv[0].toObject(v4)->asReturnedValue();
89     }
90 }
91 
init(ExecutionEngine * v4,Object * ctor)92 void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
93 {
94     Scope scope(v4);
95     ScopedObject o(scope, this);
96 
97     ctor->defineReadonlyProperty(v4->id_prototype(), o);
98     ctor->defineReadonlyConfigurableProperty(v4->id_length(), Value::fromInt32(1));
99     ctor->defineDefaultProperty(QStringLiteral("getPrototypeOf"), method_getPrototypeOf, 1);
100     ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), method_getOwnPropertyDescriptor, 2);
101     ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptors"), method_getOwnPropertyDescriptors, 1);
102     ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyNames"), method_getOwnPropertyNames, 1);
103     ctor->defineDefaultProperty(QStringLiteral("getOwnPropertySymbols"), method_getOwnPropertySymbols, 1);
104     ctor->defineDefaultProperty(QStringLiteral("assign"), method_assign, 2);
105     ctor->defineDefaultProperty(QStringLiteral("create"), method_create, 2);
106     ctor->defineDefaultProperty(QStringLiteral("defineProperty"), method_defineProperty, 3);
107     ctor->defineDefaultProperty(QStringLiteral("defineProperties"), method_defineProperties, 2);
108     ctor->defineDefaultProperty(QStringLiteral("entries"), method_entries, 1);
109     ctor->defineDefaultProperty(QStringLiteral("seal"), method_seal, 1);
110     ctor->defineDefaultProperty(QStringLiteral("freeze"), method_freeze, 1);
111     ctor->defineDefaultProperty(QStringLiteral("preventExtensions"), method_preventExtensions, 1);
112     ctor->defineDefaultProperty(QStringLiteral("is"), method_is, 2);
113     ctor->defineDefaultProperty(QStringLiteral("isSealed"), method_isSealed, 1);
114     ctor->defineDefaultProperty(QStringLiteral("isFrozen"), method_isFrozen, 1);
115     ctor->defineDefaultProperty(QStringLiteral("isExtensible"), method_isExtensible, 1);
116     ctor->defineDefaultProperty(QStringLiteral("keys"), method_keys, 1);
117     ctor->defineDefaultProperty(QStringLiteral("setPrototypeOf"), method_setPrototypeOf, 2);
118     ctor->defineDefaultProperty(QStringLiteral("values"), method_values, 1);
119 
120     defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
121     defineDefaultProperty(v4->id_toString(), method_toString, 0);
122     defineDefaultProperty(v4->id_toLocaleString(), method_toLocaleString, 0);
123     defineDefaultProperty(v4->id_valueOf(), method_valueOf, 0);
124     defineDefaultProperty(QStringLiteral("hasOwnProperty"), method_hasOwnProperty, 1);
125     defineDefaultProperty(QStringLiteral("isPrototypeOf"), method_isPrototypeOf, 1);
126     defineDefaultProperty(QStringLiteral("propertyIsEnumerable"), method_propertyIsEnumerable, 1);
127     defineDefaultProperty(QStringLiteral("__defineGetter__"), method_defineGetter, 2);
128     defineDefaultProperty(QStringLiteral("__defineSetter__"), method_defineSetter, 2);
129 
130     defineAccessorProperty(v4->id___proto__(), method_get_proto, method_set_proto);
131 }
132 
method_getPrototypeOf(const FunctionObject * b,const Value *,const Value * argv,int argc)133 ReturnedValue ObjectPrototype::method_getPrototypeOf(const FunctionObject *b, const Value *, const Value *argv, int argc)
134 {
135     Scope scope(b);
136     if (argc < 1)
137         return scope.engine->throwTypeError();
138 
139     ScopedObject o(scope, argv[0].toObject(scope.engine));
140     if (scope.engine->hasException)
141         return QV4::Encode::undefined();
142 
143     ScopedObject p(scope, o->getPrototypeOf());
144     return (!!p ? p->asReturnedValue() : Encode::null());
145 }
146 
method_is(const FunctionObject *,const Value *,const Value * argv,int argc)147 ReturnedValue ObjectPrototype::method_is(const FunctionObject *, const Value *, const Value *argv, int argc)
148 {
149     if (!argc)
150         return Encode(true);
151     if (argc == 1)
152         return Encode((argv[0].isUndefined() ? true : false));
153     return Encode(argv[0].sameValue(argv[1]));
154 }
155 
method_getOwnPropertyDescriptor(const FunctionObject * b,const Value *,const Value * argv,int argc)156 ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(const FunctionObject *b, const Value *, const Value *argv, int argc)
157 {
158     Scope scope(b);
159     if (argc < 1)
160         return scope.engine->throwTypeError();
161 
162     ScopedObject O(scope, argv[0].toObject(scope.engine));
163     if (scope.engine->hasException)
164         return QV4::Encode::undefined();
165 
166     if (ArgumentsObject::isNonStrictArgumentsObject(O))
167         static_cast<ArgumentsObject *>(O.getPointer())->fullyCreate();
168 
169     ScopedValue v(scope, argc > 1 ? argv[1] : Value::undefinedValue());
170     ScopedPropertyKey name(scope, v->toPropertyKey(scope.engine));
171     if (scope.engine->hasException)
172         return QV4::Encode::undefined();
173 
174     ScopedProperty desc(scope);
175     PropertyAttributes attrs = O->getOwnProperty(name, desc);
176     return fromPropertyDescriptor(scope.engine, desc, attrs);
177 }
178 
method_getOwnPropertyDescriptors(const FunctionObject * f,const Value *,const Value * argv,int argc)179 ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptors(const FunctionObject *f, const Value *, const Value *argv, int argc)
180 {
181     Scope scope(f);
182     if (!argc)
183         return scope.engine->throwTypeError();
184 
185     ScopedObject o(scope, argv[0].toObject(scope.engine));
186     if (scope.engine->hasException)
187         return Encode::undefined();
188 
189     ScopedObject descriptors(scope, scope.engine->newObject());
190 
191     ObjectIterator it(scope, o, ObjectIterator::WithSymbols);
192     ScopedProperty pd(scope);
193     PropertyAttributes attrs;
194     ScopedPropertyKey key(scope);
195     ScopedObject entry(scope);
196     while (1) {
197         key = it.next(pd, &attrs);
198         if (!key->isValid())
199             break;
200         entry = fromPropertyDescriptor(scope.engine, pd, attrs);
201         descriptors->put(key, entry);
202     }
203 
204     return descriptors.asReturnedValue();
205 
206 }
207 
method_getOwnPropertyNames(const FunctionObject * b,const Value *,const Value * argv,int argc)208 ReturnedValue ObjectPrototype::method_getOwnPropertyNames(const FunctionObject *b, const Value *, const Value *argv, int argc)
209 {
210     Scope scope(b);
211     if (argc < 1)
212         return scope.engine->throwTypeError();
213 
214     ScopedObject O(scope, argv[0].toObject(scope.engine));
215     if (scope.engine->hasException)
216         return QV4::Encode::undefined();
217 
218     return Encode(getOwnPropertyNames(scope.engine, argv[0]));
219 }
220 
method_getOwnPropertySymbols(const FunctionObject * f,const Value *,const Value * argv,int argc)221 ReturnedValue ObjectPrototype::method_getOwnPropertySymbols(const FunctionObject *f, const Value *, const Value *argv, int argc)
222 {
223     Scope scope(f);
224     if (!argc)
225         return scope.engine->throwTypeError();
226 
227     ScopedObject O(scope, argv[0].toObject(scope.engine));
228     if (!O)
229         return Encode::undefined();
230 
231     ScopedArrayObject array(scope, scope.engine->newArrayObject());
232     if (O) {
233         ObjectIterator it(scope, O, ObjectIterator::WithSymbols);
234         ScopedValue name(scope);
235         while (1) {
236             name = it.nextPropertyNameAsString();
237             if (name->isNull())
238                 break;
239             if (!name->isSymbol())
240                 continue;
241             array->push_back(name);
242         }
243     }
244     return array->asReturnedValue();
245 }
246 
247 // 19.1.2.1
method_assign(const FunctionObject * b,const Value *,const Value * argv,int argc)248 ReturnedValue ObjectPrototype::method_assign(const FunctionObject *b, const Value *, const Value *argv, int argc)
249 {
250     Scope scope(b);
251     if (argc < 1)
252         return scope.engine->throwTypeError();
253 
254     ScopedObject to(scope, argv[0].toObject(scope.engine));
255     if (scope.engine->hasException)
256         return QV4::Encode::undefined();
257 
258     if (argc == 1)
259         return to.asReturnedValue();
260 
261     for (int i = 1, ei = argc; i < ei; ++i) {
262         if (argv[i].isUndefined() || argv[i].isNull())
263             continue;
264 
265         ScopedObject from(scope, argv[i].toObject(scope.engine));
266         if (scope.engine->hasException)
267         return QV4::Encode::undefined();
268         QV4::ScopedArrayObject keys(scope, QV4::ObjectPrototype::getOwnPropertyNames(scope.engine, from));
269         quint32 length = keys->getLength();
270 
271         ScopedString nextKey(scope);
272         ScopedValue propValue(scope);
273         for (quint32 i = 0; i < length; ++i) {
274             nextKey = Value::fromReturnedValue(keys->get(i)).toString(scope.engine);
275 
276             ScopedProperty prop(scope);
277             PropertyAttributes attrs = from->getOwnProperty(nextKey->toPropertyKey(), prop);
278 
279             if (attrs == PropertyFlag::Attr_Invalid)
280                 continue;
281 
282             if (!attrs.isEnumerable())
283                 continue;
284 
285             propValue = from->get(nextKey);
286             to->set(nextKey, propValue, Object::DoThrowOnRejection);
287             if (scope.engine->hasException)
288         return QV4::Encode::undefined();
289         }
290     }
291 
292     return to.asReturnedValue();
293 }
294 
method_create(const FunctionObject * builtin,const Value * thisObject,const Value * argv,int argc)295 ReturnedValue ObjectPrototype::method_create(const FunctionObject *builtin, const Value *thisObject, const Value *argv, int argc)
296 {
297     Scope scope(builtin);
298     if (!argc || (!argv[0].isObject() && !argv[0].isNull()))
299         return scope.engine->throwTypeError();
300 
301     ScopedObject O(scope, argv[0]);
302 
303     ScopedObject newObject(scope, scope.engine->newObject());
304     newObject->setPrototypeOf(O);
305 
306 
307     if (argc > 1 && !argv[1].isUndefined()) {
308         Value *arguments = scope.alloc(argc);
309         arguments[0] = newObject;
310         memcpy(arguments + 1, argv + 1, (argc - 1)*sizeof(Value));
311         return method_defineProperties(builtin, thisObject, arguments, argc);
312     }
313 
314     return newObject.asReturnedValue();
315 }
316 
method_defineProperty(const FunctionObject * b,const Value *,const Value * argv,int argc)317 ReturnedValue ObjectPrototype::method_defineProperty(const FunctionObject *b, const Value *, const Value *argv, int argc)
318 {
319     Scope scope(b);
320     if (!argc || !argv[0].isObject())
321         return scope.engine->throwTypeError();
322 
323     ScopedObject O(scope, argv[0]);
324     ScopedPropertyKey name(scope, (argc > 1 ? argv[1] : Value::undefinedValue()).toPropertyKey(scope.engine));
325     if (scope.engine->hasException)
326         return QV4::Encode::undefined();
327 
328     ScopedValue attributes(scope, argc > 2 ? argv[2] : Value::undefinedValue());
329     ScopedProperty pd(scope);
330     PropertyAttributes attrs;
331     toPropertyDescriptor(scope.engine, attributes, pd, &attrs);
332     if (scope.engine->hasException)
333         return QV4::Encode::undefined();
334 
335     if (!O->defineOwnProperty(name, pd, attrs))
336         THROW_TYPE_ERROR();
337 
338     return O.asReturnedValue();
339 }
340 
method_defineProperties(const FunctionObject * b,const Value *,const Value * argv,int argc)341 ReturnedValue ObjectPrototype::method_defineProperties(const FunctionObject *b, const Value *, const Value *argv, int argc)
342 {
343     Scope scope(b);
344     if (argc < 2 || !argv[0].isObject())
345         return scope.engine->throwTypeError();
346 
347     ScopedObject O(scope, argv[0]);
348 
349     ScopedObject o(scope, argv[1].toObject(scope.engine));
350     if (scope.engine->hasException)
351         return QV4::Encode::undefined();
352 
353     ScopedValue val(scope);
354 
355     ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
356     ScopedProperty pd(scope);
357     ScopedProperty n(scope);
358     ScopedPropertyKey key(scope);
359     while (1) {
360         PropertyAttributes attrs;
361         key = it.next(pd, &attrs);
362         if (!key->isValid())
363             break;
364         PropertyAttributes nattrs;
365         val = o->getValue(pd->value, attrs);
366         toPropertyDescriptor(scope.engine, val, n, &nattrs);
367         if (scope.engine->hasException)
368         return QV4::Encode::undefined();
369         bool ok = O->defineOwnProperty(key, n, nattrs);
370         if (!ok)
371             THROW_TYPE_ERROR();
372     }
373 
374     return O.asReturnedValue();
375 }
376 
method_entries(const FunctionObject * f,const Value *,const Value * argv,int argc)377 ReturnedValue ObjectPrototype::method_entries(const FunctionObject *f, const Value *, const Value *argv, int argc)
378 {
379     Scope scope(f);
380     if (!argc)
381         return scope.engine->throwTypeError();
382 
383     ScopedObject o(scope, argv[0].toObject(scope.engine));
384     if (scope.engine->hasException)
385         return Encode::undefined();
386 
387     ScopedArrayObject a(scope, scope.engine->newArrayObject());
388 
389     ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
390     ScopedString name(scope);
391     ScopedArrayObject entry(scope);
392     while (1) {
393         name = it.nextPropertyNameAsString();
394         if (!name)
395             break;
396         entry = scope.engine->newArrayObject();
397         entry->push_back(name);
398         a->push_back(entry);
399     }
400 
401     // now add values, do this after the loop above as reading out the values can have side effects
402     uint len = a->getLength();
403     ScopedValue value(scope);
404     for (uint i = 0; i < len; ++i) {
405         entry = a->get(PropertyKey::fromArrayIndex(i));
406         name = entry->get(PropertyKey::fromArrayIndex(0));
407         value = o->get(name->toPropertyKey());
408         if (scope.engine->hasException)
409             return Encode::undefined();
410         entry->push_back(value);
411     }
412 
413     return a.asReturnedValue();
414 }
415 
method_seal(const FunctionObject * b,const Value *,const Value * argv,int argc)416 ReturnedValue ObjectPrototype::method_seal(const FunctionObject *b, const Value *, const Value *argv, int argc)
417 {
418     const Value a = argc ? argv[0] : Value::undefinedValue();
419     if (!a.isObject())
420         // 19.1.2.17, 1
421         return a.asReturnedValue();
422 
423     Scope scope(b);
424     ScopedObject o(scope, a);
425     o->setInternalClass(o->internalClass()->canned());
426 
427     if (o->arrayData()) {
428         ArrayData::ensureAttributes(o);
429         for (uint i = 0; i < o->d()->arrayData->values.alloc; ++i) {
430             if (!o->arrayData()->isEmpty(i))
431                 o->d()->arrayData->attrs[i].setConfigurable(false);
432         }
433     }
434 
435     return o.asReturnedValue();
436 }
437 
method_freeze(const FunctionObject * b,const Value *,const Value * argv,int argc)438 ReturnedValue ObjectPrototype::method_freeze(const FunctionObject *b, const Value *, const Value *argv, int argc)
439 {
440     const Value a = argc ? argv[0] : Value::undefinedValue();
441     if (!a.isObject())
442         // 19.1.2.5, 1
443         return a.asReturnedValue();
444 
445     Scope scope(b);
446     ScopedObject o(scope, a);
447 
448     if (ArgumentsObject::isNonStrictArgumentsObject(o))
449         static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate();
450 
451     o->setInternalClass(o->internalClass()->cryopreserved());
452 
453     if (o->arrayData()) {
454         ArrayData::ensureAttributes(o);
455         for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
456             if (!o->arrayData()->isEmpty(i))
457                 o->arrayData()->attrs[i].setConfigurable(false);
458             if (o->arrayData()->attrs[i].isData())
459                 o->arrayData()->attrs[i].setWritable(false);
460         }
461     }
462     return o.asReturnedValue();
463 }
464 
method_preventExtensions(const FunctionObject * b,const Value *,const Value * argv,int argc)465 ReturnedValue ObjectPrototype::method_preventExtensions(const FunctionObject *b, const Value *, const Value *argv, int argc)
466 {
467     Scope scope(b);
468     if (!argc)
469         return Encode::undefined();
470 
471     ScopedObject o(scope, argv[0]);
472     if (!o)
473         return argv[0].asReturnedValue();
474 
475     o->preventExtensions();
476     return o.asReturnedValue();
477 }
478 
method_isSealed(const FunctionObject * b,const Value *,const Value * argv,int argc)479 ReturnedValue ObjectPrototype::method_isSealed(const FunctionObject *b, const Value *, const Value *argv, int argc)
480 {
481     Scope scope(b);
482     if (!argc)
483         return Encode(true);
484 
485     ScopedObject o(scope, argv[0]);
486     if (!o)
487         return Encode(true);
488 
489     if (o->isExtensible())
490         return  Encode(false);
491 
492     if (o->internalClass() != o->internalClass()->canned())
493         return Encode(false);
494 
495     if (!o->arrayData() || !o->arrayData()->length())
496         return Encode(true);
497 
498     Q_ASSERT(o->arrayData() && o->arrayData()->length());
499     if (!o->arrayData()->attrs)
500         return Encode(false);
501 
502     for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
503         if (!o->arrayData()->isEmpty(i))
504             if (o->arrayData()->attributes(i).isConfigurable())
505                 return Encode(false);
506     }
507 
508     return Encode(true);
509 }
510 
method_isFrozen(const FunctionObject * b,const Value *,const Value * argv,int argc)511 ReturnedValue ObjectPrototype::method_isFrozen(const FunctionObject *b, const Value *, const Value *argv, int argc)
512 {
513     Scope scope(b);
514     if (!argc)
515         return Encode(true);
516 
517     ScopedObject o(scope, argv[0]);
518     if (!o)
519         return Encode(true);
520 
521     if (o->isExtensible())
522         return Encode(false);
523 
524     if (!o->internalClass()->isImplicitlyFrozen())
525         return Encode(false);
526 
527     if (!o->arrayData() || !o->arrayData()->length())
528         return Encode(true);
529 
530     Q_ASSERT(o->arrayData() && o->arrayData()->length());
531     if (!o->arrayData()->attrs)
532         return Encode(false);
533 
534     for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
535         if (!o->arrayData()->isEmpty(i))
536             if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable())
537                 return Encode(false);
538     }
539 
540     return Encode(true);
541 }
542 
method_isExtensible(const FunctionObject * b,const Value *,const Value * argv,int argc)543 ReturnedValue ObjectPrototype::method_isExtensible(const FunctionObject *b, const Value *, const Value *argv, int argc)
544 {
545     Scope scope(b);
546     if (!argc)
547         return Encode(false);
548 
549     ScopedObject o(scope, argv[0]);
550     if (!o)
551         return Encode(false);
552 
553     return Encode((bool)o->isExtensible());
554 }
555 
method_keys(const FunctionObject * b,const Value *,const Value * argv,int argc)556 ReturnedValue ObjectPrototype::method_keys(const FunctionObject *b, const Value *, const Value *argv, int argc)
557 {
558     Scope scope(b);
559     if (!argc)
560         return scope.engine->throwTypeError();
561 
562     ScopedObject o(scope, argv[0].toObject(scope.engine));
563     if (scope.engine->hasException)
564         return QV4::Encode::undefined();
565 
566     ScopedArrayObject a(scope, scope.engine->newArrayObject());
567 
568     ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
569     ScopedValue name(scope);
570     ScopedValue value(scope);
571     while (1) {
572         name = it.nextPropertyNameAsString(value);
573         if (name->isNull())
574             break;
575         a->push_back(name);
576     }
577 
578     return a.asReturnedValue();
579 }
580 
method_setPrototypeOf(const FunctionObject * f,const Value *,const Value * argv,int argc)581 ReturnedValue ObjectPrototype::method_setPrototypeOf(const FunctionObject *f, const Value *, const Value *argv, int argc)
582 {
583     Scope scope(f->engine());
584     if (argc < 2 || argv[0].isNullOrUndefined() || !(argv[1].isObject() || argv[1].isNull()))
585         return scope.engine->throwTypeError();
586 
587     if (!argv[0].isObject())
588         return argv[0].asReturnedValue();
589 
590     ScopedObject o(scope, argv[0]);
591     const Object *p = argv[1].isNull() ? nullptr : static_cast<const Object *>(argv + 1);
592     bool ok = o->setPrototypeOf(p);
593     if (!ok)
594         return scope.engine->throwTypeError(QStringLiteral("Could not change prototype."));
595     return o->asReturnedValue();
596 }
597 
method_values(const FunctionObject * f,const Value *,const Value * argv,int argc)598 ReturnedValue ObjectPrototype::method_values(const FunctionObject *f, const Value *, const Value *argv, int argc)
599 {
600     Scope scope(f);
601     if (!argc)
602         return scope.engine->throwTypeError();
603 
604     ScopedObject o(scope, argv[0].toObject(scope.engine));
605     if (scope.engine->hasException)
606         return QV4::Encode::undefined();
607 
608     ScopedArrayObject a(scope, scope.engine->newArrayObject());
609 
610     ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
611     ScopedPropertyKey key(scope);
612     ScopedProperty pd(scope);
613     ScopedValue value(scope);
614     PropertyAttributes attrs;
615     while (1) {
616         key = it.next(pd, &attrs);
617         if (!key->isValid())
618             break;
619         value = o->getValue(pd->value, attrs);
620         a->push_back(value);
621     }
622 
623     return a.asReturnedValue();
624 }
625 
method_toString(const FunctionObject * b,const Value * thisObject,const Value *,int)626 ReturnedValue ObjectPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
627 {
628     ExecutionEngine *v4 = b->engine();
629     QString string;
630     if (thisObject->isUndefined()) {
631         string = QStringLiteral("[object Undefined]");
632     } else if (thisObject->isNull()) {
633         string = QStringLiteral("[object Null]");
634     } else {
635         const Object *o = thisObject->as<Object>();
636         if (!o) {
637             // primitive, get the proper prototype
638             if (thisObject->isBoolean())
639                 o = v4->booleanPrototype();
640             else if (thisObject->isNumber())
641                 o = v4->numberPrototype();
642             else if (thisObject->isString())
643                 o = v4->stringPrototype();
644             else if (thisObject->isSymbol())
645                 o = v4->symbolPrototype();
646             Q_ASSERT(o);
647         }
648         QString name = o->className();
649         Scope scope(v4);
650         ScopedString toStringTag(scope, o->get(v4->symbol_toStringTag()));
651         if (toStringTag)
652             name = toStringTag->toQString();
653         string = QStringLiteral("[object %1]").arg(name);
654     }
655     return Encode(v4->newString(string));
656 }
657 
method_toLocaleString(const FunctionObject * b,const Value * thisObject,const Value * argv,int argc)658 ReturnedValue ObjectPrototype::method_toLocaleString(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
659 {
660     Scope scope(b);
661     CHECK_STACK_LIMITS(scope.engine)
662     ScopedObject o(scope, thisObject->toObject(scope.engine));
663     if (!o)
664         RETURN_UNDEFINED();
665 
666     ScopedFunctionObject f(scope, o->get(scope.engine->id_toString()));
667     if (!f)
668         THROW_TYPE_ERROR();
669 
670     return checkedResult(scope.engine, f->call(thisObject, argv, argc));
671 }
672 
method_valueOf(const FunctionObject * b,const Value * thisObject,const Value *,int)673 ReturnedValue ObjectPrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int)
674 {
675     return Encode(thisObject->toObject(b->engine()));
676 }
677 
method_hasOwnProperty(const FunctionObject * b,const Value * thisObject,const Value * argv,int argc)678 ReturnedValue ObjectPrototype::method_hasOwnProperty(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
679 {
680     Scope scope(b);
681     ScopedPropertyKey P(scope, (argc ? argv[0] : Value::undefinedValue()).toPropertyKey(scope.engine));
682     if (scope.engine->hasException)
683         return QV4::Encode::undefined();
684     ScopedObject O(scope, thisObject->toObject(scope.engine));
685     if (scope.engine->hasException)
686         return QV4::Encode::undefined();
687     bool r = O->getOwnProperty(P) != Attr_Invalid;
688     return Encode(r);
689 }
690 
method_isPrototypeOf(const FunctionObject * b,const Value * thisObject,const Value * argv,int argc)691 ReturnedValue ObjectPrototype::method_isPrototypeOf(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
692 {
693     Scope scope(b);
694     if (!argc || !argv[0].isObject())
695         return Encode(false);
696 
697     ScopedObject V(scope, argv[0]);
698     ScopedObject O(scope, thisObject->toObject(scope.engine));
699     if (scope.engine->hasException)
700         return QV4::Encode::undefined();
701     ScopedObject proto(scope, V->getPrototypeOf());
702     while (proto) {
703         if (O->d() == proto->d())
704             return Encode(true);
705         proto = proto->getPrototypeOf();
706     }
707     return Encode(false);
708 }
709 
method_propertyIsEnumerable(const FunctionObject * b,const Value * thisObject,const Value * argv,int argc)710 ReturnedValue ObjectPrototype::method_propertyIsEnumerable(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
711 {
712     Scope scope(b);
713     ScopedPropertyKey p(scope, (argc ? argv[0] : Value::undefinedValue()).toPropertyKey(scope.engine));
714     if (scope.engine->hasException)
715         return QV4::Encode::undefined();
716 
717     ScopedObject o(scope, thisObject->toObject(scope.engine));
718     if (scope.engine->hasException)
719         return QV4::Encode::undefined();
720     PropertyAttributes attrs = o->getOwnProperty(p);
721     return Encode(attrs.isEnumerable());
722 }
723 
method_defineGetter(const FunctionObject * b,const Value * thisObject,const Value * argv,int argc)724 ReturnedValue ObjectPrototype::method_defineGetter(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
725 {
726     Scope scope(b);
727     if (argc < 2)
728         THROW_TYPE_ERROR();
729 
730     ScopedFunctionObject f(scope, argv[1]);
731     if (!f)
732         THROW_TYPE_ERROR();
733 
734     ScopedString prop(scope, argv[0], ScopedString::Convert);
735     if (scope.engine->hasException)
736         return QV4::Encode::undefined();
737 
738     ScopedObject o(scope, thisObject);
739     if (!o) {
740         if (!thisObject->isUndefined())
741             RETURN_UNDEFINED();
742         o = scope.engine->globalObject;
743     }
744 
745     ScopedProperty pd(scope);
746     pd->value = f;
747     pd->set = Value::emptyValue();
748     bool ok = o->defineOwnProperty(prop->toPropertyKey(), pd, Attr_Accessor);
749     if (!ok)
750         THROW_TYPE_ERROR();
751     RETURN_UNDEFINED();
752 }
753 
method_defineSetter(const FunctionObject * b,const Value * thisObject,const Value * argv,int argc)754 ReturnedValue ObjectPrototype::method_defineSetter(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
755 {
756     Scope scope(b);
757     if (argc < 2)
758         THROW_TYPE_ERROR();
759 
760     ScopedFunctionObject f(scope, argv[1]);
761     if (!f)
762         THROW_TYPE_ERROR();
763 
764     ScopedString prop(scope, argv[0], ScopedString::Convert);
765     if (scope.engine->hasException)
766         return QV4::Encode::undefined();
767 
768     ScopedObject o(scope, thisObject);
769     if (!o) {
770         if (!thisObject->isUndefined())
771             RETURN_UNDEFINED();
772         o = scope.engine->globalObject;
773     }
774 
775     ScopedProperty pd(scope);
776     pd->value = Value::emptyValue();
777     pd->set = f;
778     bool ok = o->defineOwnProperty(prop->toPropertyKey(), pd, Attr_Accessor);
779     if (!ok)
780         THROW_TYPE_ERROR();
781     RETURN_UNDEFINED();
782 }
783 
method_get_proto(const FunctionObject * b,const Value * thisObject,const Value *,int)784 ReturnedValue ObjectPrototype::method_get_proto(const FunctionObject *b, const Value *thisObject, const Value *, int)
785 {
786     Scope scope(b);
787     ScopedObject o(scope, thisObject->as<Object>());
788     if (!o)
789         THROW_TYPE_ERROR();
790 
791     return Encode(o->getPrototypeOf());
792 }
793 
method_set_proto(const FunctionObject * b,const Value * thisObject,const Value * argv,int argc)794 ReturnedValue ObjectPrototype::method_set_proto(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
795 {
796     Scope scope(b);
797     ScopedObject o(scope, thisObject);
798     if (!o || !argc || (!argv[0].isObject() && !argv[0].isNull()))
799         THROW_TYPE_ERROR();
800 
801     const Object *p = argv[0].isNull() ? nullptr : static_cast<const Object *>(argv);
802     bool ok = o->setPrototypeOf(p);
803     if (!ok)
804         return scope.engine->throwTypeError(QStringLiteral("Could not change prototype."));
805     return Encode::undefined();
806     RETURN_UNDEFINED();
807 }
808 
toPropertyDescriptor(ExecutionEngine * engine,const Value & v,Property * desc,PropertyAttributes * attrs)809 void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value &v, Property *desc, PropertyAttributes *attrs)
810 {
811     Scope scope(engine);
812     ScopedObject o(scope, v);
813     if (!o) {
814         engine->throwTypeError();
815         return;
816     }
817 
818     attrs->clear();
819     desc->value = Value::emptyValue();
820     desc->set = Value::emptyValue();
821     ScopedValue tmp(scope);
822 
823     if (o->hasProperty(engine->id_enumerable()->toPropertyKey()))
824         attrs->setEnumerable((tmp = o->get(engine->id_enumerable()))->toBoolean());
825 
826     if (o->hasProperty(engine->id_configurable()->toPropertyKey()))
827         attrs->setConfigurable((tmp = o->get(engine->id_configurable()))->toBoolean());
828 
829     if (o->hasProperty(engine->id_get()->toPropertyKey())) {
830         ScopedValue get(scope, o->get(engine->id_get()));
831         FunctionObject *f = get->as<FunctionObject>();
832         if (f || get->isUndefined()) {
833             desc->value = get;
834         } else {
835             engine->throwTypeError();
836             return;
837         }
838         attrs->setType(PropertyAttributes::Accessor);
839     }
840 
841     if (o->hasProperty(engine->id_set()->toPropertyKey())) {
842         ScopedValue set(scope, o->get(engine->id_set()));
843         FunctionObject *f = set->as<FunctionObject>();
844         if (f || set->isUndefined()) {
845             desc->set = set;
846         } else {
847             engine->throwTypeError();
848             return;
849         }
850         attrs->setType(PropertyAttributes::Accessor);
851     }
852 
853     if (o->hasProperty(engine->id_writable()->toPropertyKey())) {
854         if (attrs->isAccessor()) {
855             engine->throwTypeError();
856             return;
857         }
858         attrs->setWritable((tmp = o->get(engine->id_writable()))->toBoolean());
859     }
860 
861     if (o->hasProperty(engine->id_value()->toPropertyKey())) {
862         if (attrs->isAccessor()) {
863             engine->throwTypeError();
864             return;
865         }
866         desc->value = o->get(engine->id_value());
867         attrs->setType(PropertyAttributes::Data);
868     }
869 
870     if (attrs->isGeneric())
871         desc->value = Value::emptyValue();
872 }
873 
874 
fromPropertyDescriptor(ExecutionEngine * engine,const Property * desc,PropertyAttributes attrs)875 ReturnedValue ObjectPrototype::fromPropertyDescriptor(ExecutionEngine *engine, const Property *desc, PropertyAttributes attrs)
876 {
877     if (attrs.isEmpty())
878         return Encode::undefined();
879 
880     Scope scope(engine);
881     // Let obj be the result of creating a new object as if by the expression new Object() where Object
882     // is the standard built-in constructor with that name.
883     ScopedObject o(scope, engine->newObject());
884     ScopedString s(scope);
885     ScopedValue v(scope);
886 
887     if (attrs.isData()) {
888         s = engine->newString(QStringLiteral("value"));
889         o->put(s, desc->value);
890         v = Value::fromBoolean(attrs.isWritable());
891         s = engine->newString(QStringLiteral("writable"));
892         o->put(s, v);
893     } else {
894         v = desc->getter() ? desc->getter()->asReturnedValue() : Encode::undefined();
895         s = engine->newString(QStringLiteral("get"));
896         o->put(s, v);
897         v = desc->setter() ? desc->setter()->asReturnedValue() : Encode::undefined();
898         s = engine->newString(QStringLiteral("set"));
899         o->put(s, v);
900     }
901     v = Value::fromBoolean(attrs.isEnumerable());
902     s = engine->newString(QStringLiteral("enumerable"));
903     o->put(s, v);
904     v = Value::fromBoolean(attrs.isConfigurable());
905     s = engine->newString(QStringLiteral("configurable"));
906     o->put(s, v);
907 
908     return o.asReturnedValue();
909 }
910 
911 // es6: GetOwnPropertyKeys
getOwnPropertyNames(ExecutionEngine * v4,const Value & o)912 Heap::ArrayObject *ObjectPrototype::getOwnPropertyNames(ExecutionEngine *v4, const Value &o)
913 {
914     Scope scope(v4);
915     ScopedArrayObject array(scope, v4->newArrayObject());
916     ScopedObject O(scope, o.toObject(v4));
917     if (O) {
918         ObjectIterator it(scope, O, ObjectIterator::NoFlags);
919         ScopedValue name(scope);
920         while (1) {
921             name = it.nextPropertyNameAsString();
922             if (name->isNull())
923                 break;
924             if (name->isSymbol())
925                 continue;
926             array->push_back(name);
927         }
928     }
929     return array->d();
930 }
931