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