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 Scope loopScope(b);
228 ScopedObject from(loopScope, argv[i].toObject(loopScope.engine));
229 if (loopScope.hasException())
230 return QV4::Encode::undefined();
231 QV4::ScopedArrayObject keys(loopScope, QV4::ObjectPrototype::getOwnPropertyNames(loopScope.engine, from));
232 quint32 length = keys->getLength();
233
234 ScopedString nextKey(loopScope);
235 ScopedValue propValue(loopScope);
236 ScopedProperty prop(loopScope);
237 for (quint32 i = 0; i < length; ++i) {
238 nextKey = Value::fromReturnedValue(keys->get(i)).toString(loopScope.engine);
239
240 PropertyAttributes attrs = from->getOwnProperty(nextKey->toPropertyKey(), prop);
241
242 if (attrs == PropertyFlag::Attr_Invalid)
243 continue;
244
245 if (!attrs.isEnumerable())
246 continue;
247
248 propValue = from->get(nextKey);
249 to->set(nextKey, propValue, Object::DoThrowOnRejection);
250 if (loopScope.hasException())
251 return QV4::Encode::undefined();
252 }
253 }
254
255 return to.asReturnedValue();
256}
257
258ReturnedValue ObjectPrototype::method_create(const FunctionObject *builtin, const Value *thisObject, const Value *argv, int argc)
259{
260 Scope scope(builtin);
261 if (!argc || (!argv[0].isObject() && !argv[0].isNull()))
262 return scope.engine->throwTypeError();
263
264 ScopedObject O(scope, argv[0]);
265
266 ScopedObject newObject(scope, scope.engine->newObject());
267 newObject->setPrototypeOf(O);
268
269
270 if (argc > 1 && !argv[1].isUndefined()) {
271 Value *arguments = scope.constructUndefined(argc);
272 arguments[0] = newObject;
273 memcpy(arguments + 1, argv + 1, (argc - 1)*sizeof(Value));
274 return method_defineProperties(builtin, thisObject, arguments, argc);
275 }
276
277 return newObject.asReturnedValue();
278}
279
280ReturnedValue ObjectPrototype::method_defineProperty(const FunctionObject *b, const Value *, const Value *argv, int argc)
281{
282 Scope scope(b);
283 if (!argc || !argv[0].isObject())
284 return scope.engine->throwTypeError();
285
286 ScopedObject O(scope, argv[0]);
287 ScopedPropertyKey name(scope, (argc > 1 ? argv[1] : Value::undefinedValue()).toPropertyKey(scope.engine));
288 if (scope.hasException())
289 return QV4::Encode::undefined();
290
291 ScopedValue attributes(scope, argc > 2 ? argv[2] : Value::undefinedValue());
292 ScopedProperty pd(scope);
293 PropertyAttributes attrs;
294 toPropertyDescriptor(scope.engine, attributes, pd, &attrs);
295 if (scope.hasException())
296 return QV4::Encode::undefined();
297
298 if (!O->defineOwnProperty(name, pd, attrs))
300
301 return O.asReturnedValue();
302}
303
304ReturnedValue ObjectPrototype::method_defineProperties(const FunctionObject *b, const Value *, const Value *argv, int argc)
305{
306 Scope scope(b);
307 if (argc < 2 || !argv[0].isObject())
308 return scope.engine->throwTypeError();
309
310 ScopedObject O(scope, argv[0]);
311
312 ScopedObject o(scope, argv[1].toObject(scope.engine));
313 if (scope.hasException())
314 return QV4::Encode::undefined();
315
316 ScopedValue val(scope);
317
318 ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
319 ScopedProperty pd(scope);
320 ScopedProperty n(scope);
321 ScopedPropertyKey key(scope);
322 while (1) {
323 PropertyAttributes attrs;
324 key = it.next(pd, &attrs);
325 if (!key->isValid())
326 break;
327 PropertyAttributes nattrs;
328 val = o->getValue(pd->value, attrs);
329 toPropertyDescriptor(scope.engine, val, n, &nattrs);
330 if (scope.hasException())
331 return QV4::Encode::undefined();
332 bool ok = O->defineOwnProperty(key, n, nattrs);
333 if (!ok)
335 }
336
337 return O.asReturnedValue();
338}
339
340ReturnedValue ObjectPrototype::method_entries(const FunctionObject *f, const Value *, const Value *argv, int argc)
341{
342 Scope scope(f);
343 if (!argc)
344 return scope.engine->throwTypeError();
345
346 ScopedObject o(scope, argv[0].toObject(scope.engine));
347 if (scope.hasException())
348 return Encode::undefined();
349
350 ScopedArrayObject a(scope, scope.engine->newArrayObject());
351
352 ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
353 ScopedString name(scope);
354 ScopedArrayObject entry(scope);
355 while (1) {
356 name = it.nextPropertyNameAsString();
357 if (!name)
358 break;
359 entry = scope.engine->newArrayObject();
360 entry->push_back(name);
361 a->push_back(entry);
362 }
363
364 // now add values, do this after the loop above as reading out the values can have side effects
365 uint len = a->getLength();
366 ScopedValue value(scope);
367 for (uint i = 0; i < len; ++i) {
368 entry = a->get(PropertyKey::fromArrayIndex(i));
369 name = entry->get(PropertyKey::fromArrayIndex(0));
370 value = o->get(name->toPropertyKey());
371 if (scope.hasException())
372 return Encode::undefined();
373 entry->push_back(value);
374 }
375
376 return a.asReturnedValue();
377}
378
379ReturnedValue ObjectPrototype::method_seal(const FunctionObject *b, const Value *, const Value *argv, int argc)
380{
381 const Value a = argc ? argv[0] : Value::undefinedValue();
382 if (!a.isObject())
383 // 19.1.2.17, 1
384 return a.asReturnedValue();
385
386 Scope scope(b);
387 ScopedObject o(scope, a);
388 o->setInternalClass(o->internalClass()->canned());
389
390 if (o->arrayData()) {
391 ArrayData::ensureAttributes(o);
392 for (uint i = 0; i < o->d()->arrayData->values.alloc; ++i) {
393 if (!o->arrayData()->isEmpty(i))
394 o->d()->arrayData->attrs[i].setConfigurable(false);
395 }
396 }
397
398 return o.asReturnedValue();
399}
400
401ReturnedValue ObjectPrototype::method_freeze(const FunctionObject *b, const Value *, const Value *argv, int argc)
402{
403 const Value a = argc ? argv[0] : Value::undefinedValue();
404 if (!a.isObject())
405 // 19.1.2.5, 1
406 return a.asReturnedValue();
407
408 Scope scope(b);
409 ScopedObject o(scope, a);
410
411 if (ArgumentsObject::isNonStrictArgumentsObject(o))
412 static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate();
413
414 o->setInternalClass(o->internalClass()->cryopreserved());
415
416 if (o->arrayData()) {
417 ArrayData::ensureAttributes(o);
418 for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
419 if (!o->arrayData()->isEmpty(i))
420 o->arrayData()->attrs[i].setConfigurable(false);
421 if (o->arrayData()->attrs[i].isData())
422 o->arrayData()->attrs[i].setWritable(false);
423 }
424 }
425 return o.asReturnedValue();
426}
427
428ReturnedValue ObjectPrototype::method_preventExtensions(const FunctionObject *b, const Value *, const Value *argv, int argc)
429{
430 Scope scope(b);
431 if (!argc)
432 return Encode::undefined();
433
434 ScopedObject o(scope, argv[0]);
435 if (!o)
436 return argv[0].asReturnedValue();
437
438 o->preventExtensions();
439 return o.asReturnedValue();
440}
441
442ReturnedValue ObjectPrototype::method_isSealed(const FunctionObject *b, const Value *, const Value *argv, int argc)
443{
444 Scope scope(b);
445 if (!argc)
446 return Encode(true);
447
448 ScopedObject o(scope, argv[0]);
449 if (!o)
450 return Encode(true);
451
452 if (o->isExtensible())
453 return Encode(false);
454
455 if (o->internalClass() != o->internalClass()->canned())
456 return Encode(false);
457
458 if (!o->arrayData() || !o->arrayData()->length())
459 return Encode(true);
460
461 Q_ASSERT(o->arrayData() && o->arrayData()->length());
462 if (!o->arrayData()->attrs)
463 return Encode(false);
464
465 for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
466 if (!o->arrayData()->isEmpty(i))
467 if (o->arrayData()->attributes(i).isConfigurable())
468 return Encode(false);
469 }
470
471 return Encode(true);
472}
473
474ReturnedValue ObjectPrototype::method_isFrozen(const FunctionObject *b, const Value *, const Value *argv, int argc)
475{
476 Scope scope(b);
477 if (!argc)
478 return Encode(true);
479
480 ScopedObject o(scope, argv[0]);
481 if (!o)
482 return Encode(true);
483
484 if (o->isExtensible())
485 return Encode(false);
486
487 if (!o->internalClass()->isImplicitlyFrozen())
488 return Encode(false);
489
490 if (!o->arrayData() || !o->arrayData()->length())
491 return Encode(true);
492
493 Q_ASSERT(o->arrayData() && o->arrayData()->length());
494 if (!o->arrayData()->attrs)
495 return Encode(false);
496
497 for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
498 if (!o->arrayData()->isEmpty(i))
499 if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable())
500 return Encode(false);
501 }
502
503 return Encode(true);
504}
505
506ReturnedValue ObjectPrototype::method_isExtensible(const FunctionObject *b, const Value *, const Value *argv, int argc)
507{
508 Scope scope(b);
509 if (!argc)
510 return Encode(false);
511
512 ScopedObject o(scope, argv[0]);
513 if (!o)
514 return Encode(false);
515
516 return Encode((bool)o->isExtensible());
517}
518
519ReturnedValue ObjectPrototype::method_keys(const FunctionObject *b, const Value *, const Value *argv, int argc)
520{
521 Scope scope(b);
522 if (!argc)
523 return scope.engine->throwTypeError();
524
525 ScopedObject o(scope, argv[0].toObject(scope.engine));
526 if (scope.hasException())
527 return QV4::Encode::undefined();
528
529 ScopedArrayObject a(scope, scope.engine->newArrayObject());
530
531 ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
532 ScopedValue name(scope);
533 ScopedValue value(scope);
534 while (1) {
535 name = it.nextPropertyNameAsString(value);
536 if (name->isNull())
537 break;
538 a->push_back(name);
539 }
540
541 return a.asReturnedValue();
542}
543
544ReturnedValue ObjectPrototype::method_setPrototypeOf(const FunctionObject *f, const Value *, const Value *argv, int argc)
545{
546 Scope scope(f->engine());
547 if (argc < 2 || argv[0].isNullOrUndefined() || !(argv[1].isObject() || argv[1].isNull()))
548 return scope.engine->throwTypeError();
549
550 if (!argv[0].isObject())
551 return argv[0].asReturnedValue();
552
553 ScopedObject o(scope, argv[0]);
554 const Object *p = argv[1].isNull() ? nullptr : static_cast<const Object *>(argv + 1);
555 bool ok = o->setPrototypeOf(p);
556 if (!ok)
557 return scope.engine->throwTypeError(QStringLiteral("Could not change prototype."));
558 return o->asReturnedValue();
559}
560
561ReturnedValue ObjectPrototype::method_values(const FunctionObject *f, const Value *, const Value *argv, int argc)
562{
563 Scope scope(f);
564 if (!argc)
565 return scope.engine->throwTypeError();
566
567 ScopedObject o(scope, argv[0].toObject(scope.engine));
568 if (scope.hasException())
569 return QV4::Encode::undefined();
570
571 ScopedArrayObject a(scope, scope.engine->newArrayObject());
572
573 ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
574 ScopedPropertyKey key(scope);
575 ScopedProperty pd(scope);
576 ScopedValue value(scope);
577 PropertyAttributes attrs;
578 while (1) {
579 key = it.next(pd, &attrs);
580 if (!key->isValid())
581 break;
582 value = o->getValue(pd->value, attrs);
583 a->push_back(value);
584 }
585
586 return a.asReturnedValue();
587}
588
589ReturnedValue ObjectPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
590{
591 ExecutionEngine *v4 = b->engine();
592 QString string;
593 if (thisObject->isUndefined()) {
594 string = QStringLiteral("[object Undefined]");
595 } else if (thisObject->isNull()) {
596 string = QStringLiteral("[object Null]");
597 } else {
598 const Object *o = thisObject->as<Object>();
599 if (!o) {
600 // primitive, get the proper prototype
601 if (thisObject->isBoolean())
602 o = v4->booleanPrototype();
603 else if (thisObject->isNumber())
604 o = v4->numberPrototype();
605 else if (thisObject->isString())
606 o = v4->stringPrototype();
607 else if (thisObject->isSymbol())
608 o = v4->symbolPrototype();
609 Q_ASSERT(o);
610 }
611 QString name = o->className();
612 Scope scope(v4);
613 ScopedString toStringTag(scope, o->get(v4->symbol_toStringTag()));
614 if (toStringTag)
615 name = toStringTag->toQString();
616 string = QStringLiteral("[object %1]").arg(name);
617 }
618 return Encode(v4->newString(string));
619}
620
621ReturnedValue ObjectPrototype::method_toLocaleString(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
622{
623 Scope scope(b);
624 CHECK_STACK_LIMITS(scope.engine)
625 ScopedObject o(scope, thisObject->toObject(scope.engine));
626 if (!o)
628
629 ScopedFunctionObject f(scope, o->get(scope.engine->id_toString()));
630 if (!f)
632
633 return checkedResult(scope.engine, f->call(thisObject, argv, argc));
634}
635
636ReturnedValue ObjectPrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int)
637{
638 return Encode(thisObject->toObject(b->engine()));
639}
640
641ReturnedValue ObjectPrototype::method_hasOwnProperty(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
642{
643 Scope scope(b);
644 ScopedPropertyKey P(scope, (argc ? argv[0] : Value::undefinedValue()).toPropertyKey(scope.engine));
645 if (scope.hasException())
646 return QV4::Encode::undefined();
647 ScopedObject O(scope, thisObject->toObject(scope.engine));
648 if (scope.hasException())
649 return QV4::Encode::undefined();
650 bool r = O->getOwnProperty(P) != Attr_Invalid;
651 return Encode(r);
652}
653
654ReturnedValue ObjectPrototype::method_isPrototypeOf(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
655{
656 Scope scope(b);
657 if (!argc || !argv[0].isObject())
658 return Encode(false);
659
660 ScopedObject V(scope, argv[0]);
661 ScopedObject O(scope, thisObject->toObject(scope.engine));
662 if (scope.hasException())
663 return QV4::Encode::undefined();
664 ScopedObject proto(scope, V->getPrototypeOf());
665 while (proto) {
666 if (O->d() == proto->d())
667 return Encode(true);
668 proto = proto->getPrototypeOf();
669 }
670 return Encode(false);
671}
672
673ReturnedValue ObjectPrototype::method_propertyIsEnumerable(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
674{
675 Scope scope(b);
676 ScopedPropertyKey p(scope, (argc ? argv[0] : Value::undefinedValue()).toPropertyKey(scope.engine));
677 if (scope.hasException())
678 return QV4::Encode::undefined();
679
680 ScopedObject o(scope, thisObject->toObject(scope.engine));
681 if (scope.hasException())
682 return QV4::Encode::undefined();
683 PropertyAttributes attrs = o->getOwnProperty(p);
684 return Encode(attrs.isEnumerable());
685}
686
687ReturnedValue ObjectPrototype::method_defineGetter(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
688{
689 Scope scope(b);
690 if (argc < 2)
692
693 ScopedFunctionObject f(scope, argv[1]);
694 if (!f)
696
697 ScopedString prop(scope, argv[0], ScopedString::Convert);
698 if (scope.hasException())
699 return QV4::Encode::undefined();
700
701 ScopedObject o(scope, thisObject);
702 if (!o) {
703 if (!thisObject->isUndefined())
705 o = scope.engine->globalObject;
706 }
707
708 ScopedProperty pd(scope);
709 pd->value = f;
710 pd->set = Value::emptyValue();
711 bool ok = o->defineOwnProperty(prop->toPropertyKey(), pd, Attr_Accessor);
712 if (!ok)
715}
716
717ReturnedValue ObjectPrototype::method_defineSetter(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
718{
719 Scope scope(b);
720 if (argc < 2)
722
723 ScopedFunctionObject f(scope, argv[1]);
724 if (!f)
726
727 ScopedString prop(scope, argv[0], ScopedString::Convert);
728 if (scope.hasException())
729 return QV4::Encode::undefined();
730
731 ScopedObject o(scope, thisObject);
732 if (!o) {
733 if (!thisObject->isUndefined())
735 o = scope.engine->globalObject;
736 }
737
738 ScopedProperty pd(scope);
739 pd->value = Value::emptyValue();
740 pd->set = f;
741 bool ok = o->defineOwnProperty(prop->toPropertyKey(), pd, Attr_Accessor);
742 if (!ok)
745}
746
747ReturnedValue ObjectPrototype::method_get_proto(const FunctionObject *b, const Value *thisObject, const Value *, int)
748{
749 Scope scope(b);
750 ScopedObject o(scope, thisObject->as<Object>());
751 if (!o)
753
754 return Encode(o->getPrototypeOf());
755}
756
757ReturnedValue ObjectPrototype::method_set_proto(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
758{
759 Scope scope(b);
760 ScopedObject o(scope, thisObject);
761 if (!o || !argc || (!argv[0].isObject() && !argv[0].isNull()))
763
764 const Object *p = argv[0].isNull() ? nullptr : static_cast<const Object *>(argv);
765 bool ok = o->setPrototypeOf(p);
766 if (!ok)
767 return scope.engine->throwTypeError(QStringLiteral("Could not change prototype."));
768 return Encode::undefined();
770}
771
772void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value &v, Property *desc, PropertyAttributes *attrs)
773{
774 Scope scope(engine);
775 ScopedObject o(scope, v);
776 if (!o) {
777 engine->throwTypeError();
778 return;
779 }
780
781 attrs->clear();
782 desc->value = Value::emptyValue();
783 desc->set = Value::emptyValue();
784 ScopedValue tmp(scope);
785
786 if (o->hasProperty(engine->id_enumerable()->toPropertyKey()))
787 attrs->setEnumerable((tmp = o->get(engine->id_enumerable()))->toBoolean());
788
789 if (o->hasProperty(engine->id_configurable()->toPropertyKey()))
790 attrs->setConfigurable((tmp = o->get(engine->id_configurable()))->toBoolean());
791
792 if (o->hasProperty(engine->id_get()->toPropertyKey())) {
793 ScopedValue get(scope, o->get(engine->id_get()));
794 FunctionObject *f = get->as<FunctionObject>();
795 if (f || get->isUndefined()) {
796 desc->value = get;
797 } else {
798 engine->throwTypeError();
799 return;
800 }
801 attrs->setType(PropertyAttributes::Accessor);
802 }
803
804 if (o->hasProperty(engine->id_set()->toPropertyKey())) {
805 ScopedValue set(scope, o->get(engine->id_set()));
806 FunctionObject *f = set->as<FunctionObject>();
807 if (f || set->isUndefined()) {
808 desc->set = set;
809 } else {
810 engine->throwTypeError();
811 return;
812 }
813 attrs->setType(PropertyAttributes::Accessor);
814 }
815
816 if (o->hasProperty(engine->id_writable()->toPropertyKey())) {
817 if (attrs->isAccessor()) {
818 engine->throwTypeError();
819 return;
820 }
821 attrs->setWritable((tmp = o->get(engine->id_writable()))->toBoolean());
822 }
823
824 if (o->hasProperty(engine->id_value()->toPropertyKey())) {
825 if (attrs->isAccessor()) {
826 engine->throwTypeError();
827 return;
828 }
829 desc->value = o->get(engine->id_value());
830 attrs->setType(PropertyAttributes::Data);
831 }
832
833 if (attrs->isGeneric())
834 desc->value = Value::emptyValue();
835}
836
837
838ReturnedValue ObjectPrototype::fromPropertyDescriptor(ExecutionEngine *engine, const Property *desc, PropertyAttributes attrs)
839{
840 if (attrs.isEmpty())
841 return Encode::undefined();
842
843 Scope scope(engine);
844 // Let obj be the result of creating a new object as if by the expression new Object() where Object
845 // is the standard built-in constructor with that name.
846 ScopedObject o(scope, engine->newObject());
847 ScopedString s(scope);
848 ScopedValue v(scope);
849
850 if (attrs.isData()) {
851 s = engine->newString(QStringLiteral("value"));
852 o->put(s, desc->value);
853 v = Value::fromBoolean(attrs.isWritable());
854 s = engine->newString(QStringLiteral("writable"));
855 o->put(s, v);
856 } else {
857 v = desc->getter() ? desc->getter()->asReturnedValue() : Encode::undefined();
858 s = engine->newString(QStringLiteral("get"));
859 o->put(s, v);
860 v = desc->setter() ? desc->setter()->asReturnedValue() : Encode::undefined();
861 s = engine->newString(QStringLiteral("set"));
862 o->put(s, v);
863 }
864 v = Value::fromBoolean(attrs.isEnumerable());
865 s = engine->newString(QStringLiteral("enumerable"));
866 o->put(s, v);
867 v = Value::fromBoolean(attrs.isConfigurable());
868 s = engine->newString(QStringLiteral("configurable"));
869 o->put(s, v);
870
871 return o.asReturnedValue();
872}
873
874// es6: GetOwnPropertyKeys
875Heap::ArrayObject *ObjectPrototype::getOwnPropertyNames(ExecutionEngine *v4, const Value &o)
876{
877 Scope scope(v4);
878 ScopedArrayObject array(scope, v4->newArrayObject());
879 ScopedObject O(scope, o.toObject(v4));
880 if (O) {
881 ObjectIterator it(scope, O, ObjectIterator::NoFlags);
882 ScopedValue name(scope);
883 while (1) {
884 name = it.nextPropertyNameAsString();
885 if (name->isNull())
886 break;
887 if (name->isSymbol())
888 continue;
889 array->push_back(name);
890 }
891 }
892 return array->d();
893}
#define CHECK_STACK_LIMITS(v4)
DEFINE_OBJECT_VTABLE(ObjectCtor)
#define THROW_TYPE_ERROR()
#define RETURN_UNDEFINED()