Changeset 266236 in webkit for trunk/Source/JavaScriptCore
- Timestamp:
- Aug 27, 2020, 9:41:27 AM (5 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/API/APICallbackFunction.h
r261464 r266236 80 80 VM& vm = getVM(globalObject); 81 81 auto scope = DECLARE_THROW_SCOPE(vm); 82 JSObject* constructor = callFrame->jsCallee(); 82 JSValue callee = callFrame->jsCallee(); 83 T* constructor = jsCast<T*>(callFrame->jsCallee()); 83 84 JSContextRef ctx = toRef(globalObject); 84 85 JSObjectRef constructorRef = toRef(constructor); 85 86 86 JSObjectCallAsConstructorCallback callback = jsCast<T*>(constructor)->constructCallback();87 JSObjectCallAsConstructorCallback callback = constructor->constructCallback(); 87 88 if (callback) { 89 JSValue prototype; 90 JSValue newTarget = callFrame->newTarget(); 91 // If we are doing a derived class construction get the .prototype property off the new target first so we behave closer to normal JS. 92 if (newTarget != constructor) { 93 prototype = newTarget.get(globalObject, vm.propertyNames->prototype); 94 RETURN_IF_EXCEPTION(scope, { }); 95 } 96 88 97 size_t argumentCount = callFrame->argumentCount(); 89 98 Vector<JSValueRef, 16> arguments; … … 98 107 result = callback(ctx, constructorRef, argumentCount, arguments.data(), &exception); 99 108 } 109 100 110 if (exception) { 101 111 throwException(globalObject, scope, toJS(globalObject, exception)); … … 105 115 if (!result) 106 116 return throwVMTypeError(globalObject, scope); 107 return JSValue::encode(toJS(result)); 117 118 JSObject* newObject = toJS(result); 119 // This won't trigger proxy traps on newObject's prototype handler but that's probably desirable here anyway. 120 if (newTarget != constructor && newObject->getPrototypeDirect(vm) == constructor->get(globalObject, vm.propertyNames->prototype)) { 121 RETURN_IF_EXCEPTION(scope, { }); 122 newObject->setPrototype(vm, globalObject, prototype); 123 RETURN_IF_EXCEPTION(scope, { }); 124 } 125 126 return JSValue::encode(newObject); 108 127 } 109 128 110 return JSValue::encode(toJS(JSObjectMake(ctx, jsCast<JSCallbackConstructor*>(c onstructor)->classRef(), nullptr)));129 return JSValue::encode(toJS(JSObjectMake(ctx, jsCast<JSCallbackConstructor*>(callee)->classRef(), nullptr))); 111 130 } 112 131 -
trunk/Source/JavaScriptCore/API/JSObjectRef.h
r248833 r266236 340 340 341 341 A NULL callback specifies that the default object callback should substitute, except in the case of hasProperty, where it specifies that getProperty should substitute. 342 343 It is not possible to use JS subclassing with objects created from a class definition that sets callAsConstructor by default. Subclassing is supported via the JSObjectMakeConstructor function, however. 342 344 */ 343 345 typedef struct { … … 427 429 @param callAsConstructor A JSObjectCallAsConstructorCallback to invoke when your constructor is used in a 'new' expression. Pass NULL to use the default object constructor. 428 430 @result A JSObject that is a constructor. The object's prototype will be the default object prototype. 429 @discussion The default object constructor takes no arguments and constructs an object of class jsClass with no private data. 431 @discussion The default object constructor takes no arguments and constructs an object of class jsClass with no private data. If the constructor is inherited via JS subclassing and the value returned from callAsConstructor was created with jsClass, then the returned object will have it's prototype overridden to the derived class's prototype. 430 432 */ 431 433 JS_EXPORT JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObjectCallAsConstructorCallback callAsConstructor); -
trunk/Source/JavaScriptCore/API/tests/testapi.cpp
r261755 r266236 30 30 #include "MarkedJSValueRefArray.h" 31 31 #include <JavaScriptCore/JSContextRefPrivate.h> 32 #include <JavaScriptCore/JSObjectRefPrivate.h> 32 33 #include <JavaScriptCore/JavaScript.h> 33 34 #include <wtf/DataLog.h> … … 48 49 APIString(const char* string) 49 50 : m_string(JSStringCreateWithUTF8CString(string)) 51 { 52 } 53 54 APIString(const String& string) 55 : APIString(string.utf8().data()) 50 56 { 51 57 } … … 144 150 void topCallFrameAccess(); 145 151 void markedJSValueArrayAndGC(); 152 void classDefinitionWithJSSubclass(); 153 void proxyReturnedWithJSSubclassing(); 146 154 147 155 int failed() const { return m_failed; } … … 163 171 bool functionReturnsTrue(const char* functionSource, ArgumentTypes... arguments); 164 172 173 bool scriptResultIs(ScriptResult, JSValueRef); 174 165 175 // Ways to make sets of interesting things. 166 176 APIVector<JSObjectRef> interestingObjects(); … … 237 247 return false; 238 248 return JSValueIsStrictEqual(context, trueValue, result.value()); 249 } 250 251 bool TestAPI::scriptResultIs(ScriptResult result, JSValueRef value) 252 { 253 if (!result) 254 return false; 255 return JSValueIsStrictEqual(context, result.value(), value); 239 256 } 240 257 … … 622 639 void TestAPI::markedJSValueArrayAndGC() 623 640 { 624 auto testMarkedJSValueArray = [&] (unsigned count) {641 auto testMarkedJSValueArray = [&] (unsigned count) { 625 642 auto* globalObject = toJS(context); 626 643 JSC::JSLockHolder locker(globalObject->vm()); 627 644 JSC::MarkedJSValueRefArray values(context, count); 628 645 for (unsigned index = 0; index < count; ++index) { 629 String target = makeString("Prefix", index); 630 auto holder = OpaqueJSString::tryCreate(target); 631 JSValueRef string = JSValueMakeString(context, holder.get()); 646 JSValueRef string = JSValueMakeString(context, APIString(makeString("Prefix", index))); 632 647 values[index] = string; 633 648 } … … 635 650 bool ok = true; 636 651 for (unsigned index = 0; index < count; ++index) { 637 String target = makeString("Prefix", index); 638 auto holder = OpaqueJSString::tryCreate(target); 639 JSValueRef string = JSValueMakeString(context, holder.get()); 652 JSValueRef string = JSValueMakeString(context, APIString(makeString("Prefix", index))); 640 653 if (!JSValueIsStrictEqual(context, values[index], string)) 641 654 ok = false; … … 645 658 testMarkedJSValueArray(4); 646 659 testMarkedJSValueArray(1000); 660 } 661 662 void TestAPI::classDefinitionWithJSSubclass() 663 { 664 const static JSClassDefinition definition = kJSClassDefinitionEmpty; 665 static JSClassRef jsClass = JSClassCreate(&definition); 666 667 auto constructor = [] (JSContextRef ctx, JSObjectRef, size_t, const JSValueRef*, JSValueRef*) -> JSObjectRef { 668 return JSObjectMake(ctx, jsClass, nullptr); 669 }; 670 671 JSObjectRef Superclass = JSObjectMakeConstructor(context, jsClass, constructor); 672 673 ScriptResult result = callFunction("(function (Superclass) { class Subclass extends Superclass { method() { return 'value'; } }; return new Subclass(); })", Superclass); 674 check(!!result, "creating a subclass should not throw."); 675 check(JSValueIsObject(context, result.value()), "result of construction should have been an object."); 676 JSObjectRef subclass = const_cast<JSObjectRef>(result.value()); 677 678 check(JSObjectHasProperty(context, subclass, APIString("method")), "subclass should have derived classes functions."); 679 check(functionReturnsTrue("(function (subclass, Superclass) { return subclass instanceof Superclass; })", subclass, Superclass), "JS subclass should instanceof the Superclass"); 680 681 JSClassRelease(jsClass); 682 } 683 684 void TestAPI::proxyReturnedWithJSSubclassing() 685 { 686 const static JSClassDefinition definition = kJSClassDefinitionEmpty; 687 static JSClassRef jsClass = JSClassCreate(&definition); 688 static TestAPI& test = *this; 689 690 auto constructor = [] (JSContextRef ctx, JSObjectRef, size_t, const JSValueRef*, JSValueRef*) -> JSObjectRef { 691 ScriptResult result = test.callFunction("(function (object) { return new Proxy(object, { getPrototypeOf: () => { globalThis.triggeredProxy = true; return object.__proto__; }}); })", JSObjectMake(ctx, jsClass, nullptr)); 692 test.check(!!result, "creating a proxy should not throw"); 693 test.check(JSValueIsObject(ctx, result.value()), "result of proxy creation should have been an object."); 694 return const_cast<JSObjectRef>(result.value()); 695 }; 696 697 JSObjectRef Superclass = JSObjectMakeConstructor(context, jsClass, constructor); 698 699 ScriptResult result = callFunction("(function (Superclass) { class Subclass extends Superclass { method() { return 'value'; } }; return new Subclass(); })", Superclass); 700 check(!!result, "creating a subclass should not throw."); 701 check(JSValueIsObject(context, result.value()), "result of construction should have been an object."); 702 JSObjectRef subclass = const_cast<JSObjectRef>(result.value()); 703 704 check(scriptResultIs(evaluateScript("globalThis.triggeredProxy"), JSValueMakeUndefined(context)), "creating a subclass should not have triggered the proxy"); 705 check(functionReturnsTrue("(function (subclass, Superclass) { return subclass.__proto__ == Superclass.prototype; })", subclass, Superclass), "proxy's prototype should match Superclass.prototype"); 647 706 } 648 707 … … 687 746 RUN(promiseEarlyHandledRejections()); 688 747 RUN(markedJSValueArrayAndGC()); 748 RUN(classDefinitionWithJSSubclass()); 749 RUN(proxyReturnedWithJSSubclassing()); 689 750 690 751 if (tasks.isEmpty()) { -
trunk/Source/JavaScriptCore/API/tests/testapi.mm
r266030 r266236 2860 2860 RUN(parallelPromiseResolveTest()); 2861 2861 2862 testObjectiveCAPIMain(); 2862 if (!filter) 2863 testObjectiveCAPIMain(); 2863 2864 } 2864 2865 -
trunk/Source/JavaScriptCore/ChangeLog
r266223 r266236 1 2020-08-27 Keith Miller <[email protected]> 2 3 JSClassRef should work with JS class syntax. 4 https://bugs.webkit.org/show_bug.cgi?id=215047 5 6 Reviewed by Darin Adler. 7 8 This is done by checking if value returned by the 9 callAsConstructor parameter to JSObjectMakeConstructor returns an 10 object allocated as the jsClass parameter. When that happens we 11 replace the prototype of the returned object with the prototype of 12 the new.target. Ideally we would have passed the derived classes 13 constructor from the beginning of our support for JS subclassing 14 but at this point that's probably not compatible with too many 15 applications. 16 17 * API/APICallbackFunction.h: 18 (JSC::APICallbackFunction::construct): 19 * API/JSObjectRef.h: 20 * API/tests/testapi.cpp: 21 (APIString::APIString): 22 (TestAPI::markedJSValueArrayAndGC): 23 (TestAPI::classDefinitionWithJSSubclass): 24 (testCAPIViaCpp): 25 * API/tests/testapi.mm: 26 (testObjectiveCAPI): 27 1 28 2020-08-26 Alexey Shvayka <[email protected]> 2 29
Note:
See TracChangeset
for help on using the changeset viewer.