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