Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qv4proxy.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4
5#include "qv4proxy_p.h"
6#include "qv4symbol_p.h"
7#include "qv4jscall_p.h"
8#include "qv4objectproto_p.h"
9#include "qv4persistent_p.h"
10#include "qv4objectiterator_p.h"
11
12using namespace QV4;
13
17
18void Heap::ProxyObject::init(const QV4::Object *target, const QV4::Object *handler)
19{
20 Object::init();
21 ExecutionEngine *e = internalClass->engine;
22 this->target.set(e, target->d());
23 this->handler.set(e, handler->d());
24}
25
27{
29 FunctionObject::init(e);
30 this->target.set(e, target->d());
31 this->handler.set(e, handler->d());
32}
33
34
35ReturnedValue ProxyObject::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
36{
37 Scope scope(m);
38 const ProxyObject *o = static_cast<const ProxyObject *>(m);
39 if (!o->d()->handler)
40 return scope.engine->throwTypeError();
41
42 ScopedObject target(scope, o->d()->target);
44 ScopedObject handler(scope, o->d()->handler);
45 ScopedValue trap(scope, handler->get(scope.engine->id_get()));
46 if (scope.hasException())
47 return Encode::undefined();
48 if (trap->isNullOrUndefined())
49 return target->get(id, receiver, hasProperty);
50 if (!trap->isFunctionObject())
51 return scope.engine->throwTypeError();
52 if (hasProperty)
53 *hasProperty = true;
54
55 Value *args = scope.alloc(3);
56 args[0] = target;
57 args[1] = id.toStringOrSymbol(scope.engine);
58 args[2] = *receiver;
59 JSCallData cdata(handler, args, 3);
60
61 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
62 if (scope.hasException())
63 return Encode::undefined();
64 ScopedProperty targetDesc(scope);
65 PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
66 if (attributes != Attr_Invalid && !attributes.isConfigurable()) {
67 if (attributes.isData() && !attributes.isWritable()) {
68 if (!trapResult->sameValue(targetDesc->value))
69 return scope.engine->throwTypeError();
70 }
71 if (attributes.isAccessor() && targetDesc->value.isUndefined()) {
72 if (!trapResult->isUndefined())
73 return scope.engine->throwTypeError();
74 }
75 }
76 return trapResult->asReturnedValue();
77}
78
80{
81 Scope scope(m);
82 const ProxyObject *o = static_cast<const ProxyObject *>(m);
83 if (!o->d()->handler)
84 return scope.engine->throwTypeError();
85
86 ScopedObject target(scope, o->d()->target);
88 ScopedObject handler(scope, o->d()->handler);
89 ScopedValue trap(scope, handler->get(scope.engine->id_set()));
90 if (scope.hasException())
91 return Encode::undefined();
92 if (trap->isNullOrUndefined())
93 return target->put(id, value, receiver);
94 if (!trap->isFunctionObject())
95 return scope.engine->throwTypeError();
96
97 Value *args = scope.alloc(4);
98 args[0] = target;
99 args[1] = id.toStringOrSymbol(scope.engine);
100 args[2] = value;
101 args[3] = *receiver;
102 JSCallData cdata(handler, args, 4);
103
104 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
105 if (scope.hasException() || !trapResult->toBoolean())
106 return false;
107 ScopedProperty targetDesc(scope);
108 PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
109 if (attributes != Attr_Invalid && !attributes.isConfigurable()) {
110 if (attributes.isData() && !attributes.isWritable()) {
111 if (!value.sameValue(targetDesc->value))
112 return scope.engine->throwTypeError();
113 }
114 if (attributes.isAccessor() && targetDesc->set.isUndefined())
115 return scope.engine->throwTypeError();
116 }
117 return true;
118}
119
121{
122 Scope scope(m);
123 const ProxyObject *o = static_cast<const ProxyObject *>(m);
124 if (!o->d()->handler)
125 return scope.engine->throwTypeError();
126
127 ScopedObject target(scope, o->d()->target);
129 ScopedObject handler(scope, o->d()->handler);
130 ScopedString deleteProp(scope, scope.engine->newString(QStringLiteral("deleteProperty")));
131 ScopedValue trap(scope, handler->get(deleteProp));
132 if (scope.hasException())
133 return Encode::undefined();
134 if (trap->isNullOrUndefined())
135 return target->deleteProperty(id);
136 if (!trap->isFunctionObject())
137 return scope.engine->throwTypeError();
138
139 Value *args = scope.alloc(3);
140 args[0] = target;
141 args[1] = id.toStringOrSymbol(scope.engine);
142 args[2] = o->d(); // ### fix receiver handling
143 JSCallData cdata(handler, args, 3);
144
145 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
146 if (scope.hasException() || !trapResult->toBoolean())
147 return false;
148 ScopedProperty targetDesc(scope);
149 PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
150 if (attributes == Attr_Invalid)
151 return true;
152 if (!attributes.isConfigurable())
153 return scope.engine->throwTypeError();
154 return true;
155}
156
158{
159 Scope scope(m);
160 const ProxyObject *o = static_cast<const ProxyObject *>(m);
161 if (!o->d()->handler)
162 return scope.engine->throwTypeError();
163
164 ScopedObject target(scope, o->d()->target);
166 ScopedObject handler(scope, o->d()->handler);
167 ScopedString hasProp(scope, scope.engine->newString(QStringLiteral("has")));
168 ScopedValue trap(scope, handler->get(hasProp));
169 if (scope.hasException())
170 return Encode::undefined();
171 if (trap->isNullOrUndefined())
172 return target->hasProperty(id);
173 if (!trap->isFunctionObject())
174 return scope.engine->throwTypeError();
175
176 Value *args = scope.alloc(2);
177 args[0] = target;
178 args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
179 JSCallData cdata(handler, args, 2);
180
181 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
182 if (scope.hasException())
183 return false;
184 bool result = trapResult->toBoolean();
185 if (!result) {
186 ScopedProperty targetDesc(scope);
187 PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
188 if (attributes != Attr_Invalid) {
189 if (!attributes.isConfigurable() || !target->isExtensible())
190 return scope.engine->throwTypeError();
191 }
192 }
193 return result;
194}
195
197{
198 Scope scope(m);
199 const ProxyObject *o = static_cast<const ProxyObject *>(m);
200 if (!o->d()->handler) {
201 scope.engine->throwTypeError();
202 return Attr_Invalid;
203 }
204
205 ScopedObject target(scope, o->d()->target);
207 ScopedObject handler(scope, o->d()->handler);
208 ScopedString deleteProp(scope, scope.engine->newString(QStringLiteral("getOwnPropertyDescriptor")));
209 ScopedValue trap(scope, handler->get(deleteProp));
210 if (scope.hasException())
211 return Attr_Invalid;
212 if (trap->isNullOrUndefined())
213 return target->getOwnProperty(id, p);
214 if (!trap->isFunctionObject()) {
215 scope.engine->throwTypeError();
216 return Attr_Invalid;
217 }
218
219 Value *args = scope.alloc(2);
220 args[0] = target;
221 args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
222 JSCallData cdata(handler, args, 2);
223
224 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
225 if (scope.hasException())
226 return Attr_Invalid;
227 if (!trapResult->isObject() && !trapResult->isUndefined()) {
228 scope.engine->throwTypeError();
229 return Attr_Invalid;
230 }
231
232 ScopedProperty targetDesc(scope);
233 PropertyAttributes targetAttributes = target->getOwnProperty(id, targetDesc);
234 if (trapResult->isUndefined()) {
235 if (p)
236 p->value = Encode::undefined();
237 if (targetAttributes == Attr_Invalid) {
238 return Attr_Invalid;
239 }
240 if (!targetAttributes.isConfigurable() || !target->isExtensible()) {
241 scope.engine->throwTypeError();
242 return Attr_Invalid;
243 }
244 return Attr_Invalid;
245 }
246
247 //bool extensibleTarget = target->isExtensible();
248 ScopedProperty resultDesc(scope);
249 PropertyAttributes resultAttributes;
250 ObjectPrototype::toPropertyDescriptor(scope.engine, trapResult, resultDesc, &resultAttributes);
251 resultDesc->completed(&resultAttributes);
252
253 if (!targetDesc->isCompatible(targetAttributes, resultDesc, resultAttributes)) {
254 scope.engine->throwTypeError();
255 return Attr_Invalid;
256 }
257
258 if (!resultAttributes.isConfigurable()) {
259 if (targetAttributes == Attr_Invalid || targetAttributes.isConfigurable()) {
260 scope.engine->throwTypeError();
261 return Attr_Invalid;
262 }
263 }
264
265 if (p) {
266 p->value = resultDesc->value;
267 p->set = resultDesc->set;
268 }
269 return resultAttributes;
270}
271
273{
274 Scope scope(m);
275 const ProxyObject *o = static_cast<const ProxyObject *>(m);
276 if (!o->d()->handler) {
277 scope.engine->throwTypeError();
278 return false;
279 }
280
281 ScopedObject target(scope, o->d()->target);
283 ScopedObject handler(scope, o->d()->handler);
284 ScopedString prop(scope, scope.engine->newString(QStringLiteral("defineProperty")));
285 ScopedValue trap(scope, handler->get(prop));
286 if (scope.hasException())
287 return false;
288 if (trap->isNullOrUndefined())
289 return target->defineOwnProperty(id, p, attrs);
290 if (!trap->isFunctionObject()) {
291 scope.engine->throwTypeError();
292 return false;
293 }
294
295 Value *args = scope.alloc(3);
296 args[0] = target;
297 args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
299 JSCallData cdata(handler, args, 3);
300
301 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
302 bool result = !scope.hasException() && trapResult->toBoolean();
303 if (!result)
304 return false;
305
306 ScopedProperty targetDesc(scope);
307 PropertyAttributes targetAttributes = target->getOwnProperty(id, targetDesc);
308 bool extensibleTarget = target->isExtensible();
309 bool settingConfigFalse = attrs.hasConfigurable() && !attrs.isConfigurable();
310 if (targetAttributes == Attr_Invalid) {
311 if (!extensibleTarget || settingConfigFalse) {
312 scope.engine->throwTypeError();
313 return false;
314 }
315 } else {
316 if (!targetDesc->isCompatible(targetAttributes, p, attrs)) {
317 scope.engine->throwTypeError();
318 return false;
319 }
320 if (settingConfigFalse && targetAttributes.isConfigurable()) {
321 scope.engine->throwTypeError();
322 return false;
323 }
324 }
325
326 return true;
327}
328
330{
331 Scope scope(m);
332 const ProxyObject *o = static_cast<const ProxyObject *>(m);
333 if (!o->d()->handler)
334 return scope.engine->throwTypeError();
335
336 ScopedObject target(scope, o->d()->target);
338 ScopedObject handler(scope, o->d()->handler);
339 ScopedString hasProp(scope, scope.engine->newString(QStringLiteral("isExtensible")));
340 ScopedValue trap(scope, handler->get(hasProp));
341 if (scope.hasException())
342 return Encode::undefined();
343 if (trap->isNullOrUndefined())
344 return target->isExtensible();
345 if (!trap->isFunctionObject())
346 return scope.engine->throwTypeError();
347
348 Value *args = scope.alloc(1);
349 args[0] = target;
350 JSCallData cdata(handler, args, 1);
351
352 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
353 if (scope.hasException())
354 return false;
355 bool result = trapResult->toBoolean();
356 if (result != target->isExtensible()) {
357 scope.engine->throwTypeError();
358 return false;
359 }
360 return result;
361}
362
364{
365 Scope scope(m);
366 const ProxyObject *o = static_cast<const ProxyObject *>(m);
367 if (!o->d()->handler)
368 return scope.engine->throwTypeError();
369
370 ScopedObject target(scope, o->d()->target);
372 ScopedObject handler(scope, o->d()->handler);
373 ScopedString hasProp(scope, scope.engine->newString(QStringLiteral("preventExtensions")));
374 ScopedValue trap(scope, handler->get(hasProp));
375 if (scope.hasException())
376 return Encode::undefined();
377 if (trap->isNullOrUndefined())
378 return target->preventExtensions();
379 if (!trap->isFunctionObject())
380 return scope.engine->throwTypeError();
381
382 Value *args = scope.alloc(1);
383 args[0] = target;
384 JSCallData cdata(handler, args, 1);
385
386 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
387 if (scope.hasException())
388 return false;
389 bool result = trapResult->toBoolean();
390 if (result && target->isExtensible()) {
391 scope.engine->throwTypeError();
392 return false;
393 }
394 return result;
395}
396
398{
399 Scope scope(m);
400 const ProxyObject *o = static_cast<const ProxyObject *>(m);
401 if (!o->d()->handler) {
402 scope.engine->throwTypeError();
403 return nullptr;
404 }
405
406 ScopedObject target(scope, o->d()->target);
408 ScopedObject handler(scope, o->d()->handler);
409 ScopedString name(scope, scope.engine->newString(QStringLiteral("getPrototypeOf")));
410 ScopedValue trap(scope, handler->get(name));
411 if (scope.hasException())
412 return nullptr;
413 if (trap->isNullOrUndefined())
414 return target->getPrototypeOf();
415 if (!trap->isFunctionObject()) {
416 scope.engine->throwTypeError();
417 return nullptr;
418 }
419
420 Value *args = scope.alloc(1);
421 args[0] = target;
422 JSCallData cdata(handler, args, 1);
423
424 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
425 if (scope.hasException())
426 return nullptr;
427 if (!trapResult->isNull() && !trapResult->isObject()) {
428 scope.engine->throwTypeError();
429 return nullptr;
430 }
431 Heap::Object *proto = trapResult->isNull() ? nullptr : static_cast<Heap::Object *>(trapResult->heapObject());
432 if (!target->isExtensible()) {
433 Heap::Object *targetProto = target->getPrototypeOf();
434 if (proto != targetProto) {
435 scope.engine->throwTypeError();
436 return nullptr;
437 }
438 }
439 return proto;
440}
441
443{
444 Scope scope(m);
445 const ProxyObject *o = static_cast<const ProxyObject *>(m);
446 if (!o->d()->handler) {
447 scope.engine->throwTypeError();
448 return false;
449 }
450
451 ScopedObject target(scope, o->d()->target);
453 ScopedObject handler(scope, o->d()->handler);
454 ScopedString name(scope, scope.engine->newString(QStringLiteral("setPrototypeOf")));
455 ScopedValue trap(scope, handler->get(name));
456 if (scope.hasException())
457 return false;
458 if (trap->isNullOrUndefined())
459 return target->setPrototypeOf(p);
460 if (!trap->isFunctionObject()) {
461 scope.engine->throwTypeError();
462 return false;
463 }
464
465 Value *args = scope.alloc(2);
466 args[0] = target;
467 args[1] = p ? p->asReturnedValue() : Encode::null();
468 JSCallData cdata(handler, args, 2);
469
470 ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
471 bool result = !scope.hasException() && trapResult->toBoolean();
472 if (!result)
473 return false;
474 if (!target->isExtensible()) {
475 Heap::Object *targetProto = target->getPrototypeOf();
476 if (p->d() != targetProto) {
477 scope.engine->throwTypeError();
478 return false;
479 }
480 }
481 return true;
482}
483
495
501
503{
504 if (index >= len || m == nullptr)
505 return PropertyKey::invalid();
506
507 Scope scope(m);
508 ScopedObject keys(scope, ownKeys.asManaged());
510 ++index;
511
512 if (pd || attrs) {
513 ScopedProperty p(scope);
514 PropertyAttributes a = const_cast<Object *>(m)->getOwnProperty(key, pd ? pd : p);
515 if (attrs)
516 *attrs = a;
517 }
518
519 return key;
520}
521
523 uint len = target->getLength();
524 bool found = false;
525 for (uint i = 0; i < len; ++i) {
526 ReturnedValue v = target->get(i);
527 if (v == val) {
528 found = true;
530 }
531 }
532 return found;
533}
534
536{
537 Scope scope(m);
538 const ProxyObject *o = static_cast<const ProxyObject *>(m);
539 if (!o->d()->handler) {
540 scope.engine->throwTypeError();
541 return nullptr;
542 }
543
544 ScopedObject target(scope, o->d()->target);
546 ScopedObject handler(scope, o->d()->handler);
547 ScopedString name(scope, scope.engine->newString(QStringLiteral("ownKeys")));
548 ScopedValue trap(scope, handler->get(name));
549
550 if (scope.hasException())
551 return nullptr;
552 if (trap->isUndefined())
553 return target->ownPropertyKeys(iteratorTarget);
554 if (!trap->isFunctionObject()) {
555 scope.engine->throwTypeError();
556 return nullptr;
557 }
558
559 Value *args = scope.alloc(1);
560 args[0] = target;
561 JSCallData cdata(handler, args, 1);
562 ScopedObject trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
563 if (scope.hasException())
564 return nullptr;
565 if (!trapResult) {
566 scope.engine->throwTypeError();
567 return nullptr;
568 }
569
570 uint len = trapResult->getLength();
571 ScopedArrayObject trapKeys(scope, scope.engine->newArrayObject());
573 for (uint i = 0; i < len; ++i) {
574 key = trapResult->get(i);
575 if (scope.hasException())
576 return nullptr;
577 if (!key) {
578 scope.engine->throwTypeError();
579 return nullptr;
580 }
581 Value keyAsValue = Value::fromReturnedValue(key->toPropertyKey().id());
582 trapKeys->push_back(keyAsValue);
583 }
584
585 ScopedArrayObject targetConfigurableKeys(scope, scope.engine->newArrayObject());
586 ScopedArrayObject targetNonConfigurableKeys(scope, scope.engine->newArrayObject());
588 ScopedPropertyKey k(scope);
589 while (1) {
591 k = it.next(nullptr, &attrs);
592 if (!k->isValid())
593 break;
594 Value keyAsValue = Value::fromReturnedValue(k->id());
595 if (attrs.isConfigurable())
596 targetConfigurableKeys->push_back(keyAsValue);
597 else
598 targetNonConfigurableKeys->push_back(keyAsValue);
599 }
600 if (target->isExtensible() && targetNonConfigurableKeys->getLength() == 0) {
601 *iteratorTarget = *m;
602 return new ProxyObjectOwnPropertyKeyIterator(trapKeys);
603 }
604
605 ScopedArrayObject uncheckedResultKeys(scope, scope.engine->newArrayObject());
606 uncheckedResultKeys->copyArrayData(trapKeys);
607
608 len = targetNonConfigurableKeys->getLength();
609 for (uint i = 0; i < len; ++i) {
610 k = PropertyKey::fromId(targetNonConfigurableKeys->get(i));
611 if (!removeAllOccurrences(uncheckedResultKeys, k->id())) {
612 scope.engine->throwTypeError();
613 return nullptr;
614 }
615 }
616
617 if (target->isExtensible()) {
618 *iteratorTarget = *m;
619 return new ProxyObjectOwnPropertyKeyIterator(trapKeys);
620 }
621
622 len = targetConfigurableKeys->getLength();
623 for (uint i = 0; i < len; ++i) {
624 k = PropertyKey::fromId(targetConfigurableKeys->get(i));
625 if (!removeAllOccurrences(uncheckedResultKeys, k->id())) {
626 scope.engine->throwTypeError();
627 return nullptr;
628 }
629 }
630
631 len = uncheckedResultKeys->getLength();
632 for (uint i = 0; i < len; ++i) {
633 if (uncheckedResultKeys->get(i) != Encode::undefined()) {
634 scope.engine->throwTypeError();
635 return nullptr;
636 }
637 }
638
639 *iteratorTarget = *m;
640 return new ProxyObjectOwnPropertyKeyIterator(trapKeys);
641}
642
643
645 const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
646{
647 Scope scope(f);
648 const ProxyObject *o = static_cast<const ProxyObject *>(f);
649 if (!o->d()->handler)
650 return scope.engine->throwTypeError();
651
652 ScopedFunctionObject target(scope, o->d()->target);
654 ScopedObject handler(scope, o->d()->handler);
655 ScopedString name(scope, scope.engine->newString(QStringLiteral("construct")));
656 ScopedValue trap(scope, handler->get(name));
657
658 if (scope.hasException())
659 return Encode::undefined();
660 if (trap->isNullOrUndefined())
661 return target->callAsConstructor(argv, argc, newTarget);
662 if (!trap->isFunctionObject())
663 return scope.engine->throwTypeError();
664
665 ScopedFunctionObject trapFunction(scope, trap);
666 Value *arguments = scope.alloc(3);
667 arguments[0] = target;
668 arguments[1] = scope.engine->newArrayObject(argv, argc);
669 arguments[2] = newTarget ? *newTarget : Value::undefinedValue();
670 ScopedObject result(scope, trapFunction->call(handler, arguments, 3));
671
672 if (!result)
673 return scope.engine->throwTypeError();
674 return result->asReturnedValue();
675}
676
677ReturnedValue ProxyFunctionObject::virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
678{
679 Scope scope(f);
680
681 const ProxyObject *o = static_cast<const ProxyObject *>(f);
682 if (!o->d()->handler)
683 return scope.engine->throwTypeError();
684
685 ScopedFunctionObject target(scope, o->d()->target);
687 ScopedObject handler(scope, o->d()->handler);
688 ScopedString name(scope, scope.engine->newString(QStringLiteral("apply")));
689 ScopedValue trap(scope, handler->get(name));
690
691 if (scope.hasException())
692 return Encode::undefined();
693 if (trap->isNullOrUndefined())
694 return checkedResult(scope.engine, target->call(thisObject, argv, argc));
695 if (!trap->isFunctionObject())
696 return scope.engine->throwTypeError();
697
698 ScopedFunctionObject trapFunction(scope, trap);
699 Value *arguments = scope.alloc(3);
700 arguments[0] = target;
701 arguments[1] = thisObject ? *thisObject : Value::undefinedValue();
702 arguments[2] = scope.engine->newArrayObject(argv, argc);
703 return trapFunction->call(handler, arguments, 3);
704}
705
707
708void Heap::Proxy::init(QV4::ExecutionEngine *engine)
709{
710 Heap::FunctionObject::init(engine, QStringLiteral("Proxy"));
711
712 Scope scope(engine);
713 Scoped<QV4::Proxy> ctor(scope, this);
714 ctor->defineDefaultProperty(QStringLiteral("revocable"), QV4::Proxy::method_revocable, 2);
715 ctor->defineReadonlyConfigurableProperty(scope.engine->id_length(), Value::fromInt32(2));
716}
717
719{
720 Scope scope(f);
721 if (argc < 2 || !argv[0].isObject() || !argv[1].isObject())
722 return scope.engine->throwTypeError();
723
724 const Object *target = static_cast<const Object *>(argv);
725 const Object *handler = static_cast<const Object *>(argv + 1);
726 if (const ProxyObject *ptarget = target->as<ProxyObject>())
727 if (!ptarget->d()->handler)
728 return scope.engine->throwTypeError();
729 if (const ProxyObject *phandler = handler->as<ProxyObject>())
730 if (!phandler->d()->handler)
731 return scope.engine->throwTypeError();
732
733 const FunctionObject *targetFunction = target->as<FunctionObject>();
734 if (!targetFunction) {
735 return scope.engine->memoryManager->allocate<ProxyObject>(target, handler)
736 ->asReturnedValue();
737 }
738
739 if (targetFunction->isConstructor()) {
741 targetFunction, handler)->asReturnedValue();
742 }
743
744 return scope.engine->memoryManager->allocate<ProxyFunctionObject>(targetFunction, handler)
745 ->asReturnedValue();
746}
747
749{
750 return f->engine()->throwTypeError();
751}
752
753ReturnedValue Proxy::method_revocable(const FunctionObject *f, const Value *, const Value *argv, int argc)
754{
755 Scope scope(f);
757 if (scope.hasException())
758 return Encode::undefined();
760
761 ScopedString revoke(scope, scope.engine->newString(QStringLiteral("revoke")));
762 ScopedFunctionObject revoker(
763 scope,
765 scope.engine, nullptr, method_revoke));
766 revoker->defineReadonlyConfigurableProperty(scope.engine->id_length(), Value::fromInt32(0));
767 revoker->defineDefaultProperty(scope.engine->symbol_revokableProxy(), proxy);
768
769 ScopedObject o(scope, scope.engine->newObject());
770 ScopedString p(scope, scope.engine->newString(QStringLiteral("proxy")));
771 o->defineDefaultProperty(p, proxy);
772 o->defineDefaultProperty(revoke, revoker);
773 return o->asReturnedValue();
774}
775
777{
778 Scope scope(f);
779 ScopedObject o(scope, f->get(scope.engine->symbol_revokableProxy()));
780 Q_ASSERT(o);
781 ProxyObject *proxy = o->cast<ProxyObject>();
782
783 proxy->d()->target.set(scope.engine, nullptr);
784 proxy->d()->handler.set(scope.engine, nullptr);
785 return Encode::undefined();
786}
ObjectType::Data * allocate(Args &&... args)
Definition qv4mm_p.h:298
QSet< QString >::iterator it
QList< QVariant > arguments
short next
Definition keywords.cpp:445
Scoped< FunctionObject > ScopedFunctionObject
quint64 ReturnedValue
ReturnedValue checkedResult(QV4::ExecutionEngine *v4, ReturnedValue result)
Scoped< String > ScopedString
Scoped< StringOrSymbol > ScopedStringOrSymbol
@ Attr_Invalid
static struct AttrInfo attrs[]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLfloat GLfloat f
GLenum target
GLuint name
GLuint GLfloat * val
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLenum GLsizei len
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
unsigned int uint
Definition qtypes.h:34
static bool removeAllOccurrences(ArrayObject *target, ReturnedValue val)
Definition qv4proxy.cpp:522
#define DEFINE_OBJECT_VTABLE(classname)
QStringList keys
QObject::connect nullptr
QNetworkProxy proxy
[0]
QJSValueList args
QJSEngine engine
[0]
PropertyKey next(const Object *o, Property *pd=nullptr, PropertyAttributes *attrs=nullptr) override
Definition qv4proxy.cpp:502
ProxyObjectOwnPropertyKeyIterator(ArrayObject *keys)
Definition qv4proxy.cpp:496
~ProxyObjectOwnPropertyKeyIterator() override=default
static constexpr ReturnedValue undefined()
static constexpr ReturnedValue null()
MemoryManager * memoryManager
String * id_length() const
String * id_get() const
Heap::Object * newObject()
Heap::String * newString(char16_t c)
Symbol * symbol_revokableProxy() const
String * id_set() const
Heap::ArrayObject * newArrayObject(int count=0)
ReturnedValue throwTypeError()
ReturnedValue name() const
ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const
void init(const QV4::FunctionObject *target, const QV4::Object *handler)
Definition qv4proxy.cpp:26
Heap::InternalClass * internalClass() const
static void toPropertyDescriptor(ExecutionEngine *engine, const Value &v, Property *desc, PropertyAttributes *attrs)
static ReturnedValue fromPropertyDescriptor(ExecutionEngine *engine, const Property *desc, PropertyAttributes attrs)
bool set(StringOrSymbol *name, const Value &v, ThrowOnFailure shouldThrow)
ReturnedValue get(StringOrSymbol *name, bool *hasProperty=nullptr, const Value *receiver=nullptr) const
bool isConfigurable() const
bool isValid() const
static PropertyKey fromId(quint64 id)
static PropertyKey invalid()
static PropertyKey fromArrayIndex(uint idx)
quint64 id() const
static ReturnedValue method_revocable(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
Definition qv4proxy.cpp:753
static ReturnedValue method_revoke(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
Definition qv4proxy.cpp:776
Value * alloc(qint64 nValues) const =delete
bool hasException() const
ExecutionEngine * engine
static constexpr VTable::SetPrototypeOf virtualSetPrototypeOf
static constexpr VTable::DefineOwnProperty virtualDefineOwnProperty
static constexpr VTable::OwnPropertyKeys virtualOwnPropertyKeys
static constexpr VTable::GetOwnProperty virtualGetOwnProperty
static constexpr VTable::CallAsConstructor virtualCallAsConstructor
static constexpr VTable::Call virtualCall
static constexpr VTable::PreventExtensions virtualPreventExtensions
static constexpr VTable::GetPrototypeOf virtualGetPrototypeOf
static constexpr VTable::DeleteProperty virtualDeleteProperty
static constexpr VTable::Get virtualGet
static constexpr VTable::HasProperty virtualHasProperty
static constexpr VTable::Put virtualPut
static constexpr VTable::IsExtensible virtualIsExtensible
static constexpr Value fromInt32(int i)
Definition qv4value_p.h:187
static constexpr Value undefinedValue()
Definition qv4value_p.h:191
static constexpr Value fromReturnedValue(ReturnedValue val)
Definition qv4value_p.h:165
const T * as() const
Definition qv4value_p.h:132
static Value fromUInt32(uint i)
Definition qv4value_p.h:203