36ReturnedValue ProxyObject::virtualGet(
const Managed *m, PropertyKey id,
const Value *receiver,
bool *hasProperty)
39 const ProxyObject *o =
static_cast<
const ProxyObject *>(m);
41 return scope.engine->throwTypeError();
43 ScopedObject target(scope, o->d()->target);
45 ScopedObject handler(scope, o->d()->handler);
46 ScopedValue trap(scope, handler->get(scope.engine->id_get()));
47 if (scope.hasException())
48 return Encode::undefined();
49 if (trap->isNullOrUndefined())
50 return target->get(id, receiver, hasProperty);
51 if (!trap->isFunctionObject())
52 return scope.engine->throwTypeError();
56 Value *args = scope.constructUndefined(3);
58 args[1] = id.toStringOrSymbol(scope.engine);
60 JSCallData cdata(handler, args, 3);
62 ScopedValue trapResult(scope,
static_cast<
const FunctionObject *>(trap.ptr)->call(cdata));
63 if (scope.hasException())
64 return Encode::undefined();
65 ScopedProperty targetDesc(scope);
66 PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
67 if (attributes != Attr_Invalid && !attributes.isConfigurable()) {
68 if (attributes.isData() && !attributes.isWritable()) {
69 if (!trapResult->sameValue(targetDesc->value))
70 return scope.engine->throwTypeError();
72 if (attributes.isAccessor() && targetDesc->value.isUndefined()) {
73 if (!trapResult->isUndefined())
74 return scope.engine->throwTypeError();
77 return trapResult->asReturnedValue();
80bool ProxyObject::virtualPut(Managed *m, PropertyKey id,
const Value &value, Value *receiver)
83 const ProxyObject *o =
static_cast<
const ProxyObject *>(m);
85 return scope.engine->throwTypeError();
87 ScopedObject target(scope, o->d()->target);
89 ScopedObject handler(scope, o->d()->handler);
90 ScopedValue trap(scope, handler->get(scope.engine->id_set()));
91 if (scope.hasException())
92 return Encode::undefined();
93 if (trap->isNullOrUndefined())
94 return target->put(id, value, receiver);
95 if (!trap->isFunctionObject())
96 return scope.engine->throwTypeError();
98 Value *args = scope.constructUndefined(4);
100 args[1] = id.toStringOrSymbol(scope.engine);
103 JSCallData cdata(handler, args, 4);
105 ScopedValue trapResult(scope,
static_cast<
const FunctionObject *>(trap.ptr)->call(cdata));
106 if (scope.hasException() || !trapResult->toBoolean())
108 ScopedProperty targetDesc(scope);
109 PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
110 if (attributes != Attr_Invalid && !attributes.isConfigurable()) {
111 if (attributes.isData() && !attributes.isWritable()) {
112 if (!value.sameValue(targetDesc->value))
113 return scope.engine->throwTypeError();
115 if (attributes.isAccessor() && targetDesc->set.isUndefined())
116 return scope.engine->throwTypeError();
121bool ProxyObject::virtualDeleteProperty(Managed *m, PropertyKey id)
124 const ProxyObject *o =
static_cast<
const ProxyObject *>(m);
125 if (!o->d()->handler)
126 return scope.engine->throwTypeError();
128 ScopedObject target(scope, o->d()->target);
130 ScopedObject handler(scope, o->d()->handler);
131 ScopedString deleteProp(scope, scope.engine->newString(QStringLiteral(
"deleteProperty")));
132 ScopedValue trap(scope, handler->get(deleteProp));
133 if (scope.hasException())
134 return Encode::undefined();
135 if (trap->isNullOrUndefined())
136 return target->deleteProperty(id);
137 if (!trap->isFunctionObject())
138 return scope.engine->throwTypeError();
140 Value *args = scope.constructUndefined(3);
142 args[1] = id.toStringOrSymbol(scope.engine);
144 JSCallData cdata(handler, args, 3);
146 ScopedValue trapResult(scope,
static_cast<
const FunctionObject *>(trap.ptr)->call(cdata));
147 if (scope.hasException() || !trapResult->toBoolean())
149 ScopedProperty targetDesc(scope);
150 PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
151 if (attributes == Attr_Invalid)
153 if (!attributes.isConfigurable())
154 return scope.engine->throwTypeError();
158bool ProxyObject::virtualHasProperty(
const Managed *m, PropertyKey id)
161 const ProxyObject *o =
static_cast<
const ProxyObject *>(m);
162 if (!o->d()->handler)
163 return scope.engine->throwTypeError();
165 ScopedObject target(scope, o->d()->target);
167 ScopedObject handler(scope, o->d()->handler);
168 ScopedString hasProp(scope, scope.engine->newString(QStringLiteral(
"has")));
169 ScopedValue trap(scope, handler->get(hasProp));
170 if (scope.hasException())
171 return Encode::undefined();
172 if (trap->isNullOrUndefined())
173 return target->hasProperty(id);
174 if (!trap->isFunctionObject())
175 return scope.engine->throwTypeError();
177 Value *args = scope.constructUndefined(2);
179 args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
180 JSCallData cdata(handler, args, 2);
182 ScopedValue trapResult(scope,
static_cast<
const FunctionObject *>(trap.ptr)->call(cdata));
183 if (scope.hasException())
185 bool result = trapResult->toBoolean();
187 ScopedProperty targetDesc(scope);
188 PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
189 if (attributes != Attr_Invalid) {
190 if (!attributes.isConfigurable() || !target->isExtensible())
191 return scope.engine->throwTypeError();
197PropertyAttributes ProxyObject::virtualGetOwnProperty(
const Managed *m, PropertyKey id, Property *p)
200 const ProxyObject *o =
static_cast<
const ProxyObject *>(m);
201 if (!o->d()->handler) {
202 scope.engine->throwTypeError();
206 ScopedObject target(scope, o->d()->target);
208 ScopedObject handler(scope, o->d()->handler);
209 ScopedString deleteProp(scope, scope.engine->newString(QStringLiteral(
"getOwnPropertyDescriptor")));
210 ScopedValue trap(scope, handler->get(deleteProp));
211 if (scope.hasException())
213 if (trap->isNullOrUndefined())
214 return target->getOwnProperty(id, p);
215 if (!trap->isFunctionObject()) {
216 scope.engine->throwTypeError();
220 Value *args = scope.constructUndefined(2);
222 args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
223 JSCallData cdata(handler, args, 2);
225 ScopedValue trapResult(scope,
static_cast<
const FunctionObject *>(trap.ptr)->call(cdata));
226 if (scope.hasException())
228 if (!trapResult->isObject() && !trapResult->isUndefined()) {
229 scope.engine->throwTypeError();
233 ScopedProperty targetDesc(scope);
234 PropertyAttributes targetAttributes = target->getOwnProperty(id, targetDesc);
235 if (trapResult->isUndefined()) {
237 p->value = Encode::undefined();
238 if (targetAttributes == Attr_Invalid) {
241 if (!targetAttributes.isConfigurable() || !target->isExtensible()) {
242 scope.engine->throwTypeError();
249 ScopedProperty resultDesc(scope);
250 PropertyAttributes resultAttributes;
251 ObjectPrototype::toPropertyDescriptor(scope.engine, trapResult, resultDesc, &resultAttributes);
252 resultDesc->completed(&resultAttributes);
254 if (!targetDesc->isCompatible(targetAttributes, resultDesc, resultAttributes)) {
255 scope.engine->throwTypeError();
259 if (!resultAttributes.isConfigurable()) {
260 if (targetAttributes == Attr_Invalid || targetAttributes.isConfigurable()) {
261 scope.engine->throwTypeError();
267 p->value = resultDesc->value;
268 p->set = resultDesc->set;
270 return resultAttributes;
273bool ProxyObject::virtualDefineOwnProperty(Managed *m, PropertyKey id,
const Property *p, PropertyAttributes attrs)
276 const ProxyObject *o =
static_cast<
const ProxyObject *>(m);
277 if (!o->d()->handler) {
278 scope.engine->throwTypeError();
282 ScopedObject target(scope, o->d()->target);
284 ScopedObject handler(scope, o->d()->handler);
285 ScopedString prop(scope, scope.engine->newString(QStringLiteral(
"defineProperty")));
286 ScopedValue trap(scope, handler->get(prop));
287 if (scope.hasException())
289 if (trap->isNullOrUndefined())
290 return target->defineOwnProperty(id, p, attrs);
291 if (!trap->isFunctionObject()) {
292 scope.engine->throwTypeError();
296 Value *args = scope.constructUndefined(3);
298 args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
299 args[2] = ObjectPrototype::fromPropertyDescriptor(scope.engine, p, attrs);
300 JSCallData cdata(handler, args, 3);
302 ScopedValue trapResult(scope,
static_cast<
const FunctionObject *>(trap.ptr)->call(cdata));
303 bool result = !scope.hasException() && trapResult->toBoolean();
307 ScopedProperty targetDesc(scope);
308 PropertyAttributes targetAttributes = target->getOwnProperty(id, targetDesc);
309 bool extensibleTarget = target->isExtensible();
310 bool settingConfigFalse = attrs.hasConfigurable() && !attrs.isConfigurable();
311 if (targetAttributes == Attr_Invalid) {
312 if (!extensibleTarget || settingConfigFalse) {
313 scope.engine->throwTypeError();
317 if (!targetDesc->isCompatible(targetAttributes, p, attrs)) {
318 scope.engine->throwTypeError();
321 if (settingConfigFalse && targetAttributes.isConfigurable()) {
322 scope.engine->throwTypeError();
330bool ProxyObject::virtualIsExtensible(
const Managed *m)
333 const ProxyObject *o =
static_cast<
const ProxyObject *>(m);
334 if (!o->d()->handler)
335 return scope.engine->throwTypeError();
337 ScopedObject target(scope, o->d()->target);
339 ScopedObject handler(scope, o->d()->handler);
340 ScopedString hasProp(scope, scope.engine->newString(QStringLiteral(
"isExtensible")));
341 ScopedValue trap(scope, handler->get(hasProp));
342 if (scope.hasException())
343 return Encode::undefined();
344 if (trap->isNullOrUndefined())
345 return target->isExtensible();
346 if (!trap->isFunctionObject())
347 return scope.engine->throwTypeError();
349 Value *args = scope.constructUndefined(1);
351 JSCallData cdata(handler, args, 1);
353 ScopedValue trapResult(scope,
static_cast<
const FunctionObject *>(trap.ptr)->call(cdata));
354 if (scope.hasException())
356 bool result = trapResult->toBoolean();
357 if (result != target->isExtensible()) {
358 scope.engine->throwTypeError();
364bool ProxyObject::virtualPreventExtensions(Managed *m)
367 const ProxyObject *o =
static_cast<
const ProxyObject *>(m);
368 if (!o->d()->handler)
369 return scope.engine->throwTypeError();
371 ScopedObject target(scope, o->d()->target);
373 ScopedObject handler(scope, o->d()->handler);
374 ScopedString hasProp(scope, scope.engine->newString(QStringLiteral(
"preventExtensions")));
375 ScopedValue trap(scope, handler->get(hasProp));
376 if (scope.hasException())
377 return Encode::undefined();
378 if (trap->isNullOrUndefined())
379 return target->preventExtensions();
380 if (!trap->isFunctionObject())
381 return scope.engine->throwTypeError();
383 Value *args = scope.constructUndefined(1);
385 JSCallData cdata(handler, args, 1);
387 ScopedValue trapResult(scope,
static_cast<
const FunctionObject *>(trap.ptr)->call(cdata));
388 if (scope.hasException())
390 bool result = trapResult->toBoolean();
391 if (result && target->isExtensible()) {
392 scope.engine->throwTypeError();
398Heap::Object *ProxyObject::virtualGetPrototypeOf(
const Managed *m)
401 const ProxyObject *o =
static_cast<
const ProxyObject *>(m);
402 if (!o->d()->handler) {
403 scope.engine->throwTypeError();
407 ScopedObject target(scope, o->d()->target);
409 ScopedObject handler(scope, o->d()->handler);
410 ScopedString name(scope, scope.engine->newString(QStringLiteral(
"getPrototypeOf")));
411 ScopedValue trap(scope, handler->get(name));
412 if (scope.hasException())
414 if (trap->isNullOrUndefined())
415 return target->getPrototypeOf();
416 if (!trap->isFunctionObject()) {
417 scope.engine->throwTypeError();
421 Value *args = scope.constructUndefined(1);
423 JSCallData cdata(handler, args, 1);
425 ScopedValue trapResult(scope,
static_cast<
const FunctionObject *>(trap.ptr)->call(cdata));
426 if (scope.hasException())
428 if (!trapResult->isNull() && !trapResult->isObject()) {
429 scope.engine->throwTypeError();
432 Heap::Object *proto = trapResult->isNull() ?
nullptr :
static_cast<Heap::Object *>(trapResult->heapObject());
433 if (!target->isExtensible()) {
434 Heap::Object *targetProto = target->getPrototypeOf();
435 if (proto != targetProto) {
436 scope.engine->throwTypeError();
443bool ProxyObject::virtualSetPrototypeOf(Managed *m,
const Object *p)
446 const ProxyObject *o =
static_cast<
const ProxyObject *>(m);
447 if (!o->d()->handler) {
448 scope.engine->throwTypeError();
452 ScopedObject target(scope, o->d()->target);
454 ScopedObject handler(scope, o->d()->handler);
455 ScopedString name(scope, scope.engine->newString(QStringLiteral(
"setPrototypeOf")));
456 ScopedValue trap(scope, handler->get(name));
457 if (scope.hasException())
459 if (trap->isNullOrUndefined())
460 return target->setPrototypeOf(p);
461 if (!trap->isFunctionObject()) {
462 scope.engine->throwTypeError();
466 Value *args = scope.constructUndefined(2);
468 args[1] = p ? p->asReturnedValue() : Encode::null();
469 JSCallData cdata(handler, args, 2);
471 ScopedValue trapResult(scope,
static_cast<
const FunctionObject *>(trap.ptr)->call(cdata));
472 bool result = !scope.hasException() && trapResult->toBoolean();
475 if (!target->isExtensible()) {
476 Heap::Object *targetProto = target->getPrototypeOf();
477 if (p->d() != targetProto) {
478 scope.engine->throwTypeError();
540OwnPropertyKeyIterator *ProxyObject::virtualOwnPropertyKeys(
const Object *m, Value *iteratorTarget)
543 const ProxyObject *o =
static_cast<
const ProxyObject *>(m);
544 if (!o->d()->handler) {
545 scope.engine->throwTypeError();
549 ScopedObject target(scope, o->d()->target);
551 ScopedObject handler(scope, o->d()->handler);
552 ScopedString name(scope, scope.engine->newString(QStringLiteral(
"ownKeys")));
553 ScopedValue trap(scope, handler->get(name));
555 if (scope.hasException())
557 if (trap->isUndefined())
558 return target->ownPropertyKeys(iteratorTarget);
559 if (!trap->isFunctionObject()) {
560 scope.engine->throwTypeError();
564 Value *args = scope.constructUndefined(1);
566 JSCallData cdata(handler, args, 1);
567 ScopedObject trapResult(scope,
static_cast<
const FunctionObject *>(trap.ptr)->call(cdata));
568 if (scope.hasException())
571 scope.engine->throwTypeError();
575 uint len = trapResult->getLength();
576 ScopedArrayObject trapKeys(scope, scope.engine->newArrayObject());
577 ScopedStringOrSymbol key(scope);
578 for (uint i = 0; i < len; ++i) {
579 key = trapResult->get(i);
580 if (scope.hasException())
583 scope.engine->throwTypeError();
586 Value keyAsValue = Value::fromReturnedValue(key->toPropertyKey().id());
587 trapKeys->push_back(keyAsValue);
590 ScopedArrayObject targetConfigurableKeys(scope, scope.engine->newArrayObject());
591 ScopedArrayObject targetNonConfigurableKeys(scope, scope.engine->newArrayObject());
592 ObjectIterator it(scope, target, ObjectIterator::EnumerableOnly);
593 ScopedPropertyKey k(scope);
595 PropertyAttributes attrs;
596 k = it.next(
nullptr, &attrs);
599 Value keyAsValue = Value::fromReturnedValue(k->id());
600 if (attrs.isConfigurable())
601 targetConfigurableKeys->push_back(keyAsValue);
603 targetNonConfigurableKeys->push_back(keyAsValue);
605 if (target->isExtensible() && targetNonConfigurableKeys->getLength() == 0) {
606 *iteratorTarget = *m;
607 return new ProxyObjectOwnPropertyKeyIterator(trapKeys);
610 ScopedArrayObject uncheckedResultKeys(scope, scope.engine->newArrayObject());
611 uncheckedResultKeys->copyArrayData(trapKeys);
613 len = targetNonConfigurableKeys->getLength();
614 for (uint i = 0; i < len; ++i) {
615 k = PropertyKey::fromId(targetNonConfigurableKeys->get(i));
616 if (!removeAllOccurrences(uncheckedResultKeys, k->id())) {
617 scope.engine->throwTypeError();
622 if (target->isExtensible()) {
623 *iteratorTarget = *m;
624 return new ProxyObjectOwnPropertyKeyIterator(trapKeys);
627 len = targetConfigurableKeys->getLength();
628 for (uint i = 0; i < len; ++i) {
629 k = PropertyKey::fromId(targetConfigurableKeys->get(i));
630 if (!removeAllOccurrences(uncheckedResultKeys, k->id())) {
631 scope.engine->throwTypeError();
636 len = uncheckedResultKeys->getLength();
637 for (uint i = 0; i < len; ++i) {
638 if (uncheckedResultKeys->get(i) != Encode::undefined()) {
639 scope.engine->throwTypeError();
644 *iteratorTarget = *m;
645 return new ProxyObjectOwnPropertyKeyIterator(trapKeys);
649ReturnedValue ProxyConstructorObject::virtualCallAsConstructor(
650 const FunctionObject *f,
const Value *argv,
int argc,
const Value *newTarget)
653 const ProxyObject *o =
static_cast<
const ProxyObject *>(f);
654 if (!o->d()->handler)
655 return scope.engine->throwTypeError();
657 ScopedFunctionObject target(scope, o->d()->target);
659 ScopedObject handler(scope, o->d()->handler);
660 ScopedString name(scope, scope.engine->newString(QStringLiteral(
"construct")));
661 ScopedValue trap(scope, handler->get(name));
663 if (scope.hasException())
664 return Encode::undefined();
665 if (trap->isNullOrUndefined())
666 return target->callAsConstructor(argv, argc, newTarget);
667 if (!trap->isFunctionObject())
668 return scope.engine->throwTypeError();
670 ScopedFunctionObject trapFunction(scope, trap);
671 Value *arguments = scope.constructUndefined(3);
672 arguments[0] = target;
673 arguments[1] = scope.engine->newArrayObject(argv, argc);
674 arguments[2] = newTarget ? *newTarget : Value::undefinedValue();
675 ScopedObject result(scope, trapFunction->call(handler, arguments, 3));
678 return scope.engine->throwTypeError();
679 return result->asReturnedValue();
682ReturnedValue ProxyFunctionObject::virtualCall(
const FunctionObject *f,
const Value *thisObject,
const Value *argv,
int argc)
686 const ProxyObject *o =
static_cast<
const ProxyObject *>(f);
687 if (!o->d()->handler)
688 return scope.engine->throwTypeError();
690 ScopedFunctionObject target(scope, o->d()->target);
692 ScopedObject handler(scope, o->d()->handler);
693 ScopedString name(scope, scope.engine->newString(QStringLiteral(
"apply")));
694 ScopedValue trap(scope, handler->get(name));
696 if (scope.hasException())
697 return Encode::undefined();
698 if (trap->isNullOrUndefined())
699 return checkedResult(scope.engine, target->call(thisObject, argv, argc));
700 if (!trap->isFunctionObject())
701 return scope.engine->throwTypeError();
703 ScopedFunctionObject trapFunction(scope, trap);
704 Value *arguments = scope.constructUndefined(3);
705 arguments[0] = target;
706 arguments[1] = thisObject ? *thisObject : Value::undefinedValue();
707 arguments[2] = scope.engine->newArrayObject(argv, argc);
708 return trapFunction->call(handler, arguments, 3);
723ReturnedValue Proxy::virtualCallAsConstructor(
const FunctionObject *f,
const Value *argv,
int argc,
const Value *)
726 if (argc < 2 || !argv[0].isObject() || !argv[1].isObject())
727 return scope.engine->throwTypeError();
729 const Object *target =
static_cast<
const Object *>(argv);
730 const Object *handler =
static_cast<
const Object *>(argv + 1);
731 if (
const ProxyObject *ptarget = target->as<ProxyObject>())
732 if (!ptarget->d()->handler)
733 return scope.engine->throwTypeError();
734 if (
const ProxyObject *phandler = handler->as<ProxyObject>())
735 if (!phandler->d()->handler)
736 return scope.engine->throwTypeError();
738 const FunctionObject *targetFunction = target->as<FunctionObject>();
739 if (!targetFunction) {
740 return scope.engine->memoryManager->allocate<ProxyObject>(target, handler)
744 if (targetFunction->isConstructor()) {
745 return scope.engine->memoryManager->allocate<ProxyConstructorObject>(
746 targetFunction, handler)->asReturnedValue();
749 return scope.engine->memoryManager->allocate<ProxyFunctionObject>(targetFunction, handler)
758ReturnedValue Proxy::method_revocable(
const FunctionObject *f,
const Value *,
const Value *argv,
int argc)
761 ScopedObject proxy(scope, Proxy::virtualCallAsConstructor(f, argv, argc, f));
762 if (scope.hasException())
763 return Encode::undefined();
766 ScopedString revoke(scope, scope.engine->newString(QStringLiteral(
"revoke")));
767 ScopedFunctionObject revoker(
769 scope.engine->memoryManager->allocate<DynamicFunctionObject>(
770 scope.engine,
nullptr, method_revoke));
771 revoker->defineReadonlyConfigurableProperty(scope.engine->id_length(), Value::fromInt32(0));
772 revoker->defineDefaultProperty(scope.engine->symbol_revokableProxy(), proxy);
774 ScopedObject o(scope, scope.engine->newObject());
775 ScopedString p(scope, scope.engine->newString(QStringLiteral(
"proxy")));
776 o->defineDefaultProperty(p, proxy);
777 o->defineDefaultProperty(revoke, revoker);
778 return o->asReturnedValue();