Changeset 228725 in webkit
- Timestamp:
- Feb 19, 2018 7:45:03 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r228565 r228725 1 2018-02-19 Saam Barati <sbarati@apple.com> 2 3 Don't use JSFunction's allocation profile when getting the prototype can be effectful 4 https://bugs.webkit.org/show_bug.cgi?id=182942 5 <rdar://problem/37584764> 6 7 Reviewed by Mark Lam. 8 9 * stress/get-prototype-create-this-effectful.js: Added. 10 1 11 2018-02-16 Saam Barati <sbarati@apple.com> 2 12 -
trunk/Source/JavaScriptCore/ChangeLog
r228720 r228725 1 2018-02-19 Saam Barati <sbarati@apple.com> 2 3 Don't use JSFunction's allocation profile when getting the prototype can be effectful 4 https://bugs.webkit.org/show_bug.cgi?id=182942 5 <rdar://problem/37584764> 6 7 Reviewed by Mark Lam. 8 9 Prior to this patch, the create_this implementation assumed that anything 10 that is a JSFunction can use the object allocation profile and go down the 11 fast path to allocate the |this| object. Implied by this approach is that 12 accessing the 'prototype' property of the incoming function is not an 13 effectful operation. This is inherent to the ObjectAllocationProfile 14 data structure: it caches the prototype field. However, getting the 15 'prototype' property might be an effectful operation, e.g, it could 16 be a getter. Many variants of functions in JS have the 'prototype' property 17 as non-configurable. However, some functions, like bound functions, do not 18 have the 'prototype' field with these attributes. 19 20 This patch adds the notion of 'canUseAllocationProfile' to JSFunction 21 and threads it through so that we only go down the fast path and use 22 the allocation profile when the prototype property is non-configurable. 23 24 * bytecompiler/NodesCodegen.cpp: 25 (JSC::ClassExprNode::emitBytecode): 26 * dfg/DFGOperations.cpp: 27 * runtime/CommonSlowPaths.cpp: 28 (JSC::SLOW_PATH_DECL): 29 * runtime/JSFunction.cpp: 30 (JSC::JSFunction::prototypeForConstruction): 31 (JSC::JSFunction::allocateAndInitializeRareData): 32 (JSC::JSFunction::initializeRareData): 33 (JSC::JSFunction::getOwnPropertySlot): 34 (JSC::JSFunction::canUseAllocationProfileNonInline): 35 * runtime/JSFunction.h: 36 (JSC::JSFunction::ensureRareDataAndAllocationProfile): 37 * runtime/JSFunctionInlines.h: 38 (JSC::JSFunction::canUseAllocationProfile): 39 1 40 2018-02-19 Saam Barati <sbarati@apple.com> 2 41 -
trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
r226650 r228725 3898 3898 bool needsHomeObject = false; 3899 3899 3900 // FIXME: Make the prototype non-configurable & non-writable.3901 3900 if (m_constructorExpression) { 3902 3901 ASSERT(m_constructorExpression->isFuncExprNode()); -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r227723 r228725 247 247 NativeCallFrameTracer tracer(&vm, exec); 248 248 auto scope = DECLARE_THROW_SCOPE(vm); 249 if (constructor->type() == JSFunctionType ) {250 auto rareData = jsCast<JSFunction*>(constructor)-> rareData(exec, inlineCapacity);249 if (constructor->type() == JSFunctionType && jsCast<JSFunction*>(constructor)->canUseAllocationProfile()) { 250 auto rareData = jsCast<JSFunction*>(constructor)->ensureRareDataAndAllocationProfile(exec, inlineCapacity); 251 251 RETURN_IF_EXCEPTION(scope, nullptr); 252 252 Structure* structure = rareData->objectAllocationProfile()->structure(); -
trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
r226436 r228725 223 223 JSObject* result; 224 224 JSObject* constructorAsObject = asObject(GET(bytecode.callee()).jsValue()); 225 if (constructorAsObject->type() == JSFunctionType ) {225 if (constructorAsObject->type() == JSFunctionType && jsCast<JSFunction*>(constructorAsObject)->canUseAllocationProfile()) { 226 226 JSFunction* constructor = jsCast<JSFunction*>(constructorAsObject); 227 227 WriteBarrier<JSCell>& cachedCallee = bytecode.cachedCallee(); … … 232 232 233 233 size_t inlineCapacity = bytecode.inlineCapacity(); 234 Structure* structure = constructor-> rareData(exec, inlineCapacity)->objectAllocationProfile()->structure();234 Structure* structure = constructor->ensureRareDataAndAllocationProfile(exec, inlineCapacity)->objectAllocationProfile()->structure(); 235 235 result = constructEmptyObject(exec, structure); 236 236 if (structure->hasPolyProto()) { -
trunk/Source/JavaScriptCore/runtime/JSFunction.cpp
r228500 r228725 140 140 JSObject* JSFunction::prototypeForConstruction(VM& vm, ExecState* exec) 141 141 { 142 // This code assumes getting the prototype is not effectful. That's only 143 // true when we can use the allocation profile. 144 ASSERT(canUseAllocationProfile()); 142 145 auto scope = DECLARE_CATCH_SCOPE(vm); 143 146 JSValue prototype = get(exec, vm.propertyNames->prototype); 144 ASSERT_UNUSED(scope, !scope.exception());147 scope.releaseAssertNoException(); 145 148 if (prototype.isObject()) 146 149 return asObject(prototype); … … 152 155 { 153 156 ASSERT(!m_rareData); 157 ASSERT(canUseAllocationProfile()); 154 158 VM& vm = exec->vm(); 155 159 JSObject* prototype = prototypeForConstruction(vm, exec); … … 168 172 { 169 173 ASSERT(!!m_rareData); 174 ASSERT(canUseAllocationProfile()); 170 175 VM& vm = exec->vm(); 171 176 JSObject* prototype = prototypeForConstruction(vm, exec); … … 375 380 376 381 if (propertyName == vm.propertyNames->prototype && thisObject->jsExecutable()->hasPrototypeProperty() && !thisObject->jsExecutable()->isClassConstructorFunction()) { 382 // NOTE: class constructors define the prototype property in bytecode using 383 // defineOwnProperty, which ends up calling into this code (see our defineOwnProperty 384 // implementation below). The bytecode will end up doing the proper definition 385 // with the property being non-writable/non-configurable. However, we must ignore 386 // the initial materialization of the property so that the defineOwnProperty call 387 // from bytecode succeeds. Otherwise, the materialization here would prevent the 388 // defineOwnProperty from being able to overwrite the property. 377 389 unsigned attributes; 378 390 PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName, attributes); -
trunk/Source/JavaScriptCore/runtime/JSFunction.h
r228420 r228725 131 131 } 132 132 133 FunctionRareData* rareData(ExecState* exec, unsigned inlineCapacity) 134 { 135 if (UNLIKELY(!m_rareData)) 136 return allocateAndInitializeRareData(exec, inlineCapacity); 137 if (UNLIKELY(!m_rareData->isObjectAllocationProfileInitialized())) 138 return initializeRareData(exec, inlineCapacity); 139 return m_rareData.get(); 140 } 133 FunctionRareData* ensureRareDataAndAllocationProfile(ExecState*, unsigned inlineCapacity); 141 134 142 135 FunctionRareData* rareData() … … 161 154 JSObject* prototypeForConstruction(VM&, ExecState*); 162 155 156 bool canUseAllocationProfile(); 157 bool canUseAllocationProfileNonInline(); 158 163 159 protected: 164 160 JS_EXPORT_PRIVATE JSFunction(VM&, JSGlobalObject*, Structure*); … … 167 163 void finishCreation(VM&, NativeExecutable*, int length, const String& name); 168 164 void finishCreation(VM&); 169 170 FunctionRareData* allocateRareData(VM&);171 FunctionRareData* allocateAndInitializeRareData(ExecState*, size_t inlineCapacity);172 FunctionRareData* initializeRareData(ExecState*, size_t inlineCapacity);173 165 174 166 static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); … … 192 184 return function; 193 185 } 186 187 FunctionRareData* allocateRareData(VM&); 188 FunctionRareData* allocateAndInitializeRareData(ExecState*, size_t inlineCapacity); 189 FunctionRareData* initializeRareData(ExecState*, size_t inlineCapacity); 194 190 195 191 bool hasReifiedLength() const; -
trunk/Source/JavaScriptCore/runtime/JSFunctionInlines.h
r225891 r228725 108 108 } 109 109 110 inline bool JSFunction::canUseAllocationProfile() 111 { 112 if (isHostFunction()) 113 return false; 114 115 // If we don't have a prototype property, we're not guaranteed it's 116 // non-configurable. For example, user code can define the prototype 117 // as a getter. JS semantics require that the getter is called every 118 // time |construct| occurs with this function as new.target. 119 return jsExecutable()->hasPrototypeProperty(); 120 } 121 122 inline FunctionRareData* JSFunction::ensureRareDataAndAllocationProfile(ExecState* exec, unsigned inlineCapacity) 123 { 124 ASSERT(canUseAllocationProfile()); 125 if (UNLIKELY(!m_rareData)) 126 return allocateAndInitializeRareData(exec, inlineCapacity); 127 if (UNLIKELY(!m_rareData->isObjectAllocationProfileInitialized())) 128 return initializeRareData(exec, inlineCapacity); 129 return m_rareData.get(); 130 } 131 110 132 } // namespace JSC
Note: See TracChangeset
for help on using the changeset viewer.