Changeset 197136 in webkit
- Timestamp:
- Feb 25, 2016, 2:58:23 PM (11 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 1 added
- 8 edited
-
ChangeLog (modified) (1 diff)
-
runtime/JSObject.cpp (modified) (2 diffs)
-
runtime/JSObject.h (modified) (1 diff)
-
runtime/JSObjectInlines.h (modified) (2 diffs)
-
runtime/JSType.h (modified) (1 diff)
-
runtime/ProxyObject.cpp (modified) (3 diffs)
-
runtime/ProxyObject.h (modified) (4 diffs)
-
tests/es6.yaml (modified) (4 diffs)
-
tests/stress/proxy-set.js (added)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r197134 r197136 1 2016-02-25 Saam barati <sbarati@apple.com> 2 3 [ES6] Implement Proxy.[[Set]] 4 https://bugs.webkit.org/show_bug.cgi?id=154511 5 6 Reviewed by Filip Pizlo. 7 8 This patch is mostly an implementation of 9 Proxy.[[Set]] with respect to section 9.5.9 10 of the ECMAScript spec. 11 https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver 12 13 This patch also changes JSObject::putInline and JSObject::putByIndex 14 to be aware that a Proxy in the prototype chain will intercept 15 property accesses. 16 17 * runtime/JSObject.cpp: 18 (JSC::JSObject::putInlineSlow): 19 (JSC::JSObject::attemptToInterceptPutByIndexOnHoleForPrototype): 20 * runtime/JSObject.h: 21 * runtime/JSObjectInlines.h: 22 (JSC::JSObject::canPerformFastPutInline): 23 (JSC::JSObject::putInline): 24 * runtime/JSType.h: 25 * runtime/ProxyObject.cpp: 26 (JSC::ProxyObject::getOwnPropertySlotByIndex): 27 (JSC::ProxyObject::performPut): 28 (JSC::ProxyObject::put): 29 (JSC::ProxyObject::putByIndexCommon): 30 (JSC::ProxyObject::putByIndex): 31 (JSC::performProxyCall): 32 (JSC::ProxyObject::getCallData): 33 (JSC::performProxyConstruct): 34 (JSC::ProxyObject::deletePropertyByIndex): 35 (JSC::ProxyObject::visitChildren): 36 * runtime/ProxyObject.h: 37 (JSC::ProxyObject::create): 38 (JSC::ProxyObject::createStructure): 39 (JSC::ProxyObject::target): 40 (JSC::ProxyObject::handler): 41 * tests/es6.yaml: 42 * tests/stress/proxy-set.js: Added. 43 (assert): 44 (throw.new.Error.let.handler.set 45): 45 (throw.new.Error): 46 (let.target.set x): 47 (let.target.get x): 48 (set let): 49 1 50 2016-02-25 Benjamin Poulain <bpoulain@apple.com> 2 51 -
trunk/Source/JavaScriptCore/runtime/JSObject.cpp
r196999 r197136 422 422 } 423 423 } 424 } 425 if (obj->type() == ProxyObjectType) { 426 ProxyObject* proxy = jsCast<ProxyObject*>(obj); 427 proxy->ProxyObject::put(proxy, exec, propertyName, value, slot); 428 return; 424 429 } 425 430 JSValue prototype = obj->prototype(); … … 1917 1922 } 1918 1923 } 1924 1925 if (current->type() == ProxyObjectType) { 1926 ProxyObject* proxy = jsCast<ProxyObject*>(current); 1927 proxy->putByIndexCommon(exec, thisValue, i, value, shouldThrow); 1928 return true; 1929 } 1919 1930 1920 1931 JSValue prototypeValue = current->prototype(); -
trunk/Source/JavaScriptCore/runtime/JSObject.h
r196849 r197136 856 856 template<PutMode> 857 857 bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&); 858 bool canPerformFastPutInline(ExecState* exec, VM&, PropertyName); 858 859 859 860 JS_EXPORT_PRIVATE NEVER_INLINE void putInlineSlow(ExecState*, PropertyName, JSValue, PutPropertySlot&); -
trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h
r194175 r197136 31 31 namespace JSC { 32 32 33 ALWAYS_INLINE bool JSObject::canPerformFastPutInline(ExecState* exec, VM& vm, PropertyName propertyName) 34 { 35 if (UNLIKELY(propertyName == exec->propertyNames().underscoreProto)) 36 return false; 37 38 // Check if there are any setters or getters in the prototype chain 39 JSValue prototype; 40 JSObject* obj = this; 41 while (true) { 42 if (obj->structure(vm)->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || obj->type() == ProxyObjectType) 43 return false; 44 45 prototype = obj->prototype(); 46 if (prototype.isNull()) 47 return true; 48 49 obj = asObject(prototype); 50 } 51 52 ASSERT_NOT_REACHED(); 53 } 54 33 55 // ECMA 8.6.2.2 34 56 ALWAYS_INLINE void JSObject::putInline(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) … … 45 67 return; 46 68 } 47 48 // Check if there are any setters or getters in the prototype chain49 JSValue prototype;50 if (propertyName != exec->propertyNames().underscoreProto) {51 for (JSObject* obj = thisObject; !obj->structure(vm)->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {52 prototype = obj->prototype();53 if (prototype.isNull()) {54 ASSERT(!thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName));55 if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot)56 && slot.isStrictMode())57 throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));58 return;59 }60 }61 }62 69 63 thisObject->putInlineSlow(exec, propertyName, value, slot); 70 if (thisObject->canPerformFastPutInline(exec, vm, propertyName)) { 71 ASSERT(!thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName)); 72 if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot) 73 && slot.isStrictMode()) 74 throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)); 75 } else 76 thisObject->putInlineSlow(exec, propertyName, value, slot); 64 77 } 65 78 -
trunk/Source/JavaScriptCore/runtime/JSType.h
r189279 r197136 79 79 ClosureObjectType, 80 80 81 LastJSCObjectType = ClosureObjectType, 81 ProxyObjectType, 82 83 LastJSCObjectType = ProxyObjectType, 82 84 }; 83 85 -
trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp
r197042 r197136 301 301 } 302 302 303 template <typename PerformDefaultPutFunction> 304 void ProxyObject::performPut(ExecState* exec, JSValue putValue, JSValue thisValue, PropertyName propertyName, PerformDefaultPutFunction performDefaultPutFunction) 305 { 306 VM& vm = exec->vm(); 307 JSValue handlerValue = this->handler(); 308 if (handlerValue.isNull()) { 309 throwVMTypeError(exec, ASCIILiteral("Proxy 'handler' is null. It should be an Object.")); 310 return; 311 } 312 313 JSObject* handler = jsCast<JSObject*>(handlerValue); 314 CallData callData; 315 CallType callType; 316 JSValue setMethod = handler->getMethod(exec, callData, callType, vm.propertyNames->set, ASCIILiteral("'set' property of a Proxy's handler should be callable.")); 317 if (exec->hadException()) 318 return; 319 JSObject* target = this->target(); 320 if (setMethod.isUndefined()) { 321 performDefaultPutFunction(); 322 return; 323 } 324 325 MarkedArgumentBuffer arguments; 326 arguments.append(target); 327 arguments.append(identifierToSafePublicJSValue(vm, Identifier::fromUid(&vm, propertyName.uid()))); 328 arguments.append(putValue); 329 arguments.append(thisValue); 330 JSValue trapResult = call(exec, setMethod, callType, callData, handler, arguments); 331 if (exec->hadException()) 332 return; 333 bool trapResultAsBool = trapResult.toBoolean(exec); 334 if (exec->hadException()) 335 return; 336 if (!trapResultAsBool) 337 return; 338 339 PropertyDescriptor descriptor; 340 if (target->getOwnPropertyDescriptor(exec, propertyName, descriptor)) { 341 if (descriptor.isDataDescriptor() && !descriptor.configurable() && !descriptor.writable()) { 342 if (!sameValue(exec, descriptor.value(), putValue)) { 343 throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'set' on a non-configurable and non-writable property on 'target' should either return false or be the same value already on the 'target'.")); 344 return; 345 } 346 } else if (descriptor.isAccessorDescriptor() && !descriptor.configurable() && descriptor.setter().isUndefined()) { 347 throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'set' method on a non-configurable accessor property without a setter should return false.")); 348 return; 349 } 350 } 351 } 352 353 void ProxyObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) 354 { 355 VM& vm = exec->vm(); 356 ProxyObject* thisObject = jsCast<ProxyObject*>(cell); 357 auto performDefaultPut = [&] () { 358 JSObject* target = jsCast<JSObject*>(thisObject->target()); 359 target->methodTable(vm)->put(target, exec, propertyName, value, slot); 360 }; 361 thisObject->performPut(exec, value, slot.thisValue(), propertyName, performDefaultPut); 362 } 363 364 void ProxyObject::putByIndexCommon(ExecState* exec, JSValue thisValue, unsigned propertyName, JSValue putValue, bool shouldThrow) 365 { 366 VM& vm = exec->vm(); 367 Identifier ident = Identifier::from(exec, propertyName); 368 if (exec->hadException()) 369 return; 370 auto performDefaultPut = [&] () { 371 JSObject* target = this->target(); 372 bool isStrictMode = shouldThrow; 373 PutPropertySlot slot(thisValue, isStrictMode); // We must preserve the "this" target of the putByIndex. 374 target->methodTable(vm)->put(target, exec, ident.impl(), putValue, slot); 375 }; 376 performPut(exec, putValue, thisValue, ident.impl(), performDefaultPut); 377 } 378 379 void ProxyObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow) 380 { 381 ProxyObject* thisObject = jsCast<ProxyObject*>(cell); 382 thisObject->putByIndexCommon(exec, thisObject, propertyName, value, shouldThrow); 383 } 384 303 385 static EncodedJSValue JSC_HOST_CALL performProxyCall(ExecState* exec) 304 386 { … … 346 428 } 347 429 348 void ProxyObject::visitChildren(JSCell* cell, SlotVisitor& visitor)349 {350 ProxyObject* thisObject = jsCast<ProxyObject*>(cell);351 ASSERT_GC_OBJECT_INHERITS(thisObject, info());352 Base::visitChildren(thisObject, visitor);353 354 visitor.append(&thisObject->m_target);355 visitor.append(&thisObject->m_handler);356 }357 358 430 static EncodedJSValue JSC_HOST_CALL performProxyConstruct(ExecState* exec) 359 431 { … … 477 549 } 478 550 551 void ProxyObject::visitChildren(JSCell* cell, SlotVisitor& visitor) 552 { 553 ProxyObject* thisObject = jsCast<ProxyObject*>(cell); 554 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 555 Base::visitChildren(thisObject, visitor); 556 557 visitor.append(&thisObject->m_target); 558 visitor.append(&thisObject->m_handler); 559 } 560 479 561 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/ProxyObject.h
r197042 r197136 36 36 typedef JSNonFinalObject Base; 37 37 38 const static unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | TypeOfShouldCallGetCallData ;38 const static unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | TypeOfShouldCallGetCallData | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero; 39 39 40 40 static ProxyObject* create(ExecState* exec, Structure* structure, JSValue target, JSValue handler) … … 48 48 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) 49 49 { 50 return Structure::create(vm, globalObject, prototype, TypeInfo( ObjectType, StructureFlags), info());50 return Structure::create(vm, globalObject, prototype, TypeInfo(ProxyObjectType, StructureFlags), info(), NonArray | MayHaveIndexedAccessors); 51 51 } 52 52 … … 55 55 JSObject* target() { return m_target.get(); } 56 56 JSValue handler() { return m_handler.get(); } 57 58 static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); 59 static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); 60 void putByIndexCommon(ExecState*, JSValue thisValue, unsigned propertyName, JSValue putValue, bool shouldThrow); 57 61 58 62 private: … … 73 77 template <typename DefaultDeleteFunction> 74 78 bool performDelete(ExecState*, PropertyName, DefaultDeleteFunction); 79 template <typename PerformDefaultPutFunction> 80 void performPut(ExecState*, JSValue putValue, JSValue thisValue, PropertyName, PerformDefaultPutFunction); 75 81 76 82 WriteBarrier<JSObject> m_target; -
trunk/Source/JavaScriptCore/tests/es6.yaml
r197042 r197136 964 964 cmd: runES6 :normal 965 965 - path: es6/Proxy_internal_get_calls_Array.prototype_iteration_methods.js 966 cmd: runES6 : fail966 cmd: runES6 :normal 967 967 - path: es6/Proxy_internal_get_calls_ClassDefinitionEvaluation.js 968 968 cmd: runES6 :normal … … 1034 1034 cmd: runES6 :fail 1035 1035 - path: es6/Proxy_internal_set_calls_Array.from.js 1036 cmd: runES6 : fail1036 cmd: runES6 :normal 1037 1037 - path: es6/Proxy_internal_set_calls_Array.of.js 1038 cmd: runES6 : fail1038 cmd: runES6 :normal 1039 1039 - path: es6/Proxy_internal_set_calls_Array.prototype.copyWithin.js 1040 cmd: runES6 : fail1040 cmd: runES6 :normal 1041 1041 - path: es6/Proxy_internal_set_calls_Array.prototype.fill.js 1042 cmd: runES6 : fail1042 cmd: runES6 :normal 1043 1043 - path: es6/Proxy_internal_set_calls_Array.prototype.pop.js 1044 cmd: runES6 : fail1044 cmd: runES6 :normal 1045 1045 - path: es6/Proxy_internal_set_calls_Array.prototype.push.js 1046 cmd: runES6 : fail1046 cmd: runES6 :normal 1047 1047 - path: es6/Proxy_internal_set_calls_Array.prototype.reverse.js 1048 1048 cmd: runES6 :fail … … 1050 1050 cmd: runES6 :fail 1051 1051 - path: es6/Proxy_internal_set_calls_Array.prototype.splice.js 1052 cmd: runES6 : fail1052 cmd: runES6 :normal 1053 1053 - path: es6/Proxy_internal_set_calls_Array.prototype.unshift.js 1054 1054 cmd: runES6 :fail 1055 1055 - path: es6/Proxy_internal_set_calls_Object.assign.js 1056 cmd: runES6 : fail1056 cmd: runES6 :normal 1057 1057 - path: es6/Proxy_isExtensible_handler.js 1058 1058 cmd: runES6 :fail … … 1066 1066 cmd: runES6 :fail 1067 1067 - path: es6/Proxy_set_handler.js 1068 cmd: runES6 : fail1068 cmd: runES6 :normal 1069 1069 - path: es6/Proxy_set_handler_instances_of_proxies.js 1070 cmd: runES6 : fail1070 cmd: runES6 :normal 1071 1071 - path: es6/Proxy_setPrototypeOf_handler.js 1072 1072 cmd: runES6 :fail
Note:
See TracChangeset
for help on using the changeset viewer.