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
56using namespace QV4;
57
58
59DEFINE_OBJECT_VTABLE(ObjectCtor);
60
61void Heap::ObjectCtor::init(QV4::ExecutionContext *scope)
62{
63 Heap::FunctionObject::init(scope, QStringLiteral("Object"));
64}
65
66ReturnedValue 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(name: scope.engine->id_prototype()));
74 if (!!proto)
75 obj->setPrototypeOf(proto);
76 return obj.asReturnedValue();
77 } else {
78 return argv[0].toObject(e: v4)->asReturnedValue();
79 }
80}
81
82ReturnedValue 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(e: v4)->asReturnedValue();
89 }
90}
91
92void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
93{
94 Scope scope(v4);
95 ScopedObject o(scope, this);
96
97 ctor->defineReadonlyProperty(name: v4->id_prototype(), value: o);
98 ctor->defineReadonlyConfigurableProperty(name: v4->id_length(), value: Value::fromInt32(i: 1));
99 ctor->defineDefaultProperty(QStringLiteral("getPrototypeOf"), code: method_getPrototypeOf, argumentCount: 1);
100 ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), code: method_getOwnPropertyDescriptor, argumentCount: 2);
101 ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptors"), code: method_getOwnPropertyDescriptors, argumentCount: 1);
102 ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyNames"), code: method_getOwnPropertyNames, argumentCount: 1);
103 ctor->defineDefaultProperty(QStringLiteral("getOwnPropertySymbols"), code: method_getOwnPropertySymbols, argumentCount: 1);
104 ctor->defineDefaultProperty(QStringLiteral("assign"), code: method_assign, argumentCount: 2);
105 ctor->defineDefaultProperty(QStringLiteral("create"), code: method_create, argumentCount: 2);
106 ctor->defineDefaultProperty(QStringLiteral("defineProperty"), code: method_defineProperty, argumentCount: 3);
107 ctor->defineDefaultProperty(QStringLiteral("defineProperties"), code: method_defineProperties, argumentCount: 2);
108 ctor->defineDefaultProperty(QStringLiteral("entries"), code: method_entries, argumentCount: 1);
109 ctor->defineDefaultProperty(QStringLiteral("seal"), code: method_seal, argumentCount: 1);
110 ctor->defineDefaultProperty(QStringLiteral("freeze"), code: method_freeze, argumentCount: 1);
111 ctor->defineDefaultProperty(QStringLiteral("preventExtensions"), code: method_preventExtensions, argumentCount: 1);
112 ctor->defineDefaultProperty(QStringLiteral("is"), code: method_is, argumentCount: 2);
113 ctor->defineDefaultProperty(QStringLiteral("isSealed"), code: method_isSealed, argumentCount: 1);
114 ctor->defineDefaultProperty(QStringLiteral("isFrozen"), code: method_isFrozen, argumentCount: 1);
115 ctor->defineDefaultProperty(QStringLiteral("isExtensible"), code: method_isExtensible, argumentCount: 1);
116 ctor->defineDefaultProperty(QStringLiteral("keys"), code: method_keys, argumentCount: 1);
117 ctor->defineDefaultProperty(QStringLiteral("setPrototypeOf"), code: method_setPrototypeOf, argumentCount: 2);
118 ctor->defineDefaultProperty(QStringLiteral("values"), code: method_values, argumentCount: 1);
119
120 defineDefaultProperty(QStringLiteral("constructor"), value: (o = ctor));
121 defineDefaultProperty(name: v4->id_toString(), code: method_toString, argumentCount: 0);
122 defineDefaultProperty(name: v4->id_toLocaleString(), code: method_toLocaleString, argumentCount: 0);
123 defineDefaultProperty(name: v4->id_valueOf(), code: method_valueOf, argumentCount: 0);
124 defineDefaultProperty(QStringLiteral("hasOwnProperty"), code: method_hasOwnProperty, argumentCount: 1);
125 defineDefaultProperty(QStringLiteral("isPrototypeOf"), code: method_isPrototypeOf, argumentCount: 1);
126 defineDefaultProperty(QStringLiteral("propertyIsEnumerable"), code: method_propertyIsEnumerable, argumentCount: 1);
127 defineDefaultProperty(QStringLiteral("__defineGetter__"), code: method_defineGetter, argumentCount: 2);
128 defineDefaultProperty(QStringLiteral("__defineSetter__"), code: method_defineSetter, argumentCount: 2);
129
130 defineAccessorProperty(name: v4->id___proto__(), getter: method_get_proto, setter: method_set_proto);
131}
132
133ReturnedValue 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(e: 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
147ReturnedValue 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(other: argv[1]));
154}
155
156ReturnedValue 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(e: scope.engine));
163 if (scope.engine->hasException)
164 return QV4::Encode::undefined();
165
166 if (ArgumentsObject::isNonStrictArgumentsObject(m: 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(e: scope.engine));
171 if (scope.engine->hasException)
172 return QV4::Encode::undefined();
173
174 ScopedProperty desc(scope);
175 PropertyAttributes attrs = O->getOwnProperty(id: name, p: desc);
176 return fromPropertyDescriptor(engine: scope.engine, desc, attrs);
177}
178
179ReturnedValue 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(e: 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, attributes: &attrs);
198 if (!key->isValid())
199 break;
200 entry = fromPropertyDescriptor(engine: scope.engine, desc: pd, attrs);
201 descriptors->put(id: key, v: entry);
202 }
203
204 return descriptors.asReturnedValue();
205
206}
207
208ReturnedValue 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(e: scope.engine));
215 if (scope.engine->hasException)
216 return QV4::Encode::undefined();
217
218 return Encode(getOwnPropertyNames(v4: scope.engine, o: argv[0]));
219}
220
221ReturnedValue 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(e: 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(v: name);
242 }
243 }
244 return array->asReturnedValue();
245}
246
247// 19.1.2.1
248ReturnedValue 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(e: 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(e: scope.engine));
266 if (scope.engine->hasException)
267 return QV4::Encode::undefined();
268 QV4::ScopedArrayObject keys(scope, QV4::ObjectPrototype::getOwnPropertyNames(v4: scope.engine, o: 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(val: keys->get(idx: i)).toString(e: scope.engine);
275
276 ScopedProperty prop(scope);
277 PropertyAttributes attrs = from->getOwnProperty(id: nextKey->toPropertyKey(), p: prop);
278
279 if (attrs == PropertyFlag::Attr_Invalid)
280 continue;
281
282 if (!attrs.isEnumerable())
283 continue;
284
285 propValue = from->get(name: nextKey);
286 to->set(name: nextKey, v: propValue, shouldThrow: Object::DoThrowOnRejection);
287 if (scope.engine->hasException)
288 return QV4::Encode::undefined();
289 }
290 }
291
292 return to.asReturnedValue();
293}
294
295ReturnedValue 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(nValues: argc);
309 arguments[0] = newObject;
310 memcpy(dest: arguments + 1, src: argv + 1, n: (argc - 1)*sizeof(Value));
311 return method_defineProperties(builtin, thisObject, argv: arguments, argc);
312 }
313
314 return newObject.asReturnedValue();
315}
316
317ReturnedValue 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(e: 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(engine: scope.engine, v: attributes, desc: pd, attrs: &attrs);
332 if (scope.engine->hasException)
333 return QV4::Encode::undefined();
334
335 if (!O->defineOwnProperty(id: name, p: pd, attrs))
336 THROW_TYPE_ERROR();
337
338 return O.asReturnedValue();
339}
340
341ReturnedValue 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(e: 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, attributes: &attrs);
362 if (!key->isValid())
363 break;
364 PropertyAttributes nattrs;
365 val = o->getValue(v: pd->value, attrs);
366 toPropertyDescriptor(engine: scope.engine, v: val, desc: n, attrs: &nattrs);
367 if (scope.engine->hasException)
368 return QV4::Encode::undefined();
369 bool ok = O->defineOwnProperty(id: key, p: n, attrs: nattrs);
370 if (!ok)
371 THROW_TYPE_ERROR();
372 }
373
374 return O.asReturnedValue();
375}
376
377ReturnedValue 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(e: 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(v: name);
398 a->push_back(v: 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(id: PropertyKey::fromArrayIndex(idx: i));
406 name = entry->get(id: PropertyKey::fromArrayIndex(idx: 0));
407 value = o->get(id: name->toPropertyKey());
408 if (scope.engine->hasException)
409 return Encode::undefined();
410 entry->push_back(v: value);
411 }
412
413 return a.asReturnedValue();
414}
415
416ReturnedValue 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
438ReturnedValue 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(m: 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
465ReturnedValue 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
479ReturnedValue 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
511ReturnedValue 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
543ReturnedValue 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
556ReturnedValue 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(e: 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(v: name);
576 }
577
578 return a.asReturnedValue();
579}
580
581ReturnedValue 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
598ReturnedValue 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(e: 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, attributes: &attrs);
617 if (!key->isValid())
618 break;
619 value = o->getValue(v: pd->value, attrs);
620 a->push_back(v: value);
621 }
622
623 return a.asReturnedValue();
624}
625
626ReturnedValue 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(name: v4->symbol_toStringTag()));
651 if (toStringTag)
652 name = toStringTag->toQString();
653 string = QStringLiteral("[object %1]").arg(a: name);
654 }
655 return Encode(v4->newString(s: string));
656}
657
658ReturnedValue 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(e: scope.engine));
663 if (!o)
664 RETURN_UNDEFINED();
665
666 ScopedFunctionObject f(scope, o->get(name: scope.engine->id_toString()));
667 if (!f)
668 THROW_TYPE_ERROR();
669
670 return checkedResult(v4: scope.engine, result: f->call(thisObject, argv, argc));
671}
672
673ReturnedValue ObjectPrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int)
674{
675 return Encode(thisObject->toObject(e: b->engine()));
676}
677
678ReturnedValue 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(e: scope.engine));
682 if (scope.engine->hasException)
683 return QV4::Encode::undefined();
684 ScopedObject O(scope, thisObject->toObject(e: scope.engine));
685 if (scope.engine->hasException)
686 return QV4::Encode::undefined();
687 bool r = O->getOwnProperty(id: P) != Attr_Invalid;
688 return Encode(r);
689}
690
691ReturnedValue 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(e: 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
710ReturnedValue 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(e: scope.engine));
714 if (scope.engine->hasException)
715 return QV4::Encode::undefined();
716
717 ScopedObject o(scope, thisObject->toObject(e: scope.engine));
718 if (scope.engine->hasException)
719 return QV4::Encode::undefined();
720 PropertyAttributes attrs = o->getOwnProperty(id: p);
721 return Encode(attrs.isEnumerable());
722}
723
724ReturnedValue 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(id: prop->toPropertyKey(), p: pd, attrs: Attr_Accessor);
749 if (!ok)
750 THROW_TYPE_ERROR();
751 RETURN_UNDEFINED();
752}
753
754ReturnedValue 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(id: prop->toPropertyKey(), p: pd, attrs: Attr_Accessor);
779 if (!ok)
780 THROW_TYPE_ERROR();
781 RETURN_UNDEFINED();
782}
783
784ReturnedValue 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
794ReturnedValue 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
809void 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(id: engine->id_enumerable()->toPropertyKey()))
824 attrs->setEnumerable((tmp = o->get(name: engine->id_enumerable()))->toBoolean());
825
826 if (o->hasProperty(id: engine->id_configurable()->toPropertyKey()))
827 attrs->setConfigurable((tmp = o->get(name: engine->id_configurable()))->toBoolean());
828
829 if (o->hasProperty(id: engine->id_get()->toPropertyKey())) {
830 ScopedValue get(scope, o->get(name: 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(id: engine->id_set()->toPropertyKey())) {
842 ScopedValue set(scope, o->get(name: 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(id: engine->id_writable()->toPropertyKey())) {
854 if (attrs->isAccessor()) {
855 engine->throwTypeError();
856 return;
857 }
858 attrs->setWritable((tmp = o->get(name: engine->id_writable()))->toBoolean());
859 }
860
861 if (o->hasProperty(id: engine->id_value()->toPropertyKey())) {
862 if (attrs->isAccessor()) {
863 engine->throwTypeError();
864 return;
865 }
866 desc->value = o->get(name: engine->id_value());
867 attrs->setType(PropertyAttributes::Data);
868 }
869
870 if (attrs->isGeneric())
871 desc->value = Value::emptyValue();
872}
873
874
875ReturnedValue 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(name: s, v: desc->value);
890 v = Value::fromBoolean(b: attrs.isWritable());
891 s = engine->newString(QStringLiteral("writable"));
892 o->put(name: s, v);
893 } else {
894 v = desc->getter() ? desc->getter()->asReturnedValue() : Encode::undefined();
895 s = engine->newString(QStringLiteral("get"));
896 o->put(name: s, v);
897 v = desc->setter() ? desc->setter()->asReturnedValue() : Encode::undefined();
898 s = engine->newString(QStringLiteral("set"));
899 o->put(name: s, v);
900 }
901 v = Value::fromBoolean(b: attrs.isEnumerable());
902 s = engine->newString(QStringLiteral("enumerable"));
903 o->put(name: s, v);
904 v = Value::fromBoolean(b: attrs.isConfigurable());
905 s = engine->newString(QStringLiteral("configurable"));
906 o->put(name: s, v);
907
908 return o.asReturnedValue();
909}
910
911// es6: GetOwnPropertyKeys
912Heap::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(e: 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(v: name);
927 }
928 }
929 return array->d();
930}
931

source code of qtdeclarative/src/qml/jsruntime/qv4objectproto.cpp