From 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Tue, 27 Jun 2017 06:07:23 +0000 Subject: webkitgtk-2.16.5 --- .../runtime/AbstractModuleRecord.cpp | 769 ++++++ .../JavaScriptCore/runtime/AbstractModuleRecord.h | 180 ++ Source/JavaScriptCore/runtime/ArgList.cpp | 73 +- Source/JavaScriptCore/runtime/ArgList.h | 57 +- Source/JavaScriptCore/runtime/Arguments.cpp | 387 --- Source/JavaScriptCore/runtime/Arguments.h | 298 --- .../runtime/ArgumentsIteratorConstructor.cpp | 45 - .../runtime/ArgumentsIteratorConstructor.h | 63 - .../runtime/ArgumentsIteratorPrototype.cpp | 61 - .../runtime/ArgumentsIteratorPrototype.h | 61 - Source/JavaScriptCore/runtime/ArgumentsMode.h | 35 + Source/JavaScriptCore/runtime/ArityCheckMode.h | 35 + Source/JavaScriptCore/runtime/ArrayBuffer.cpp | 289 +- Source/JavaScriptCore/runtime/ArrayBuffer.h | 232 +- .../runtime/ArrayBufferNeuteringWatchpoint.cpp | 11 +- .../runtime/ArrayBufferNeuteringWatchpoint.h | 19 +- .../runtime/ArrayBufferSharingMode.h | 59 + Source/JavaScriptCore/runtime/ArrayBufferView.cpp | 10 +- Source/JavaScriptCore/runtime/ArrayBufferView.h | 62 +- Source/JavaScriptCore/runtime/ArrayConstructor.cpp | 102 +- Source/JavaScriptCore/runtime/ArrayConstructor.h | 41 +- Source/JavaScriptCore/runtime/ArrayConventions.cpp | 68 + Source/JavaScriptCore/runtime/ArrayConventions.h | 64 +- .../runtime/ArrayIteratorAdaptiveWatchpoint.cpp | 45 + .../runtime/ArrayIteratorAdaptiveWatchpoint.h | 45 + .../runtime/ArrayIteratorConstructor.cpp | 42 - .../runtime/ArrayIteratorConstructor.h | 63 - .../runtime/ArrayIteratorPrototype.cpp | 29 +- .../runtime/ArrayIteratorPrototype.h | 10 +- Source/JavaScriptCore/runtime/ArrayPrototype.cpp | 2051 ++++++++------- Source/JavaScriptCore/runtime/ArrayPrototype.h | 38 +- Source/JavaScriptCore/runtime/ArrayStorage.h | 81 +- .../runtime/AsyncFunctionConstructor.cpp | 77 + .../runtime/AsyncFunctionConstructor.h | 59 + .../runtime/AsyncFunctionPrototype.cpp | 57 + .../runtime/AsyncFunctionPrototype.h | 57 + Source/JavaScriptCore/runtime/AtomicsObject.cpp | 396 +++ Source/JavaScriptCore/runtime/AtomicsObject.h | 50 + Source/JavaScriptCore/runtime/AuxiliaryBarrier.h | 62 + .../runtime/AuxiliaryBarrierInlines.h | 51 + .../JavaScriptCore/runtime/BasicBlockLocation.cpp | 100 + Source/JavaScriptCore/runtime/BasicBlockLocation.h | 70 + .../runtime/BatchedTransitionOptimizer.h | 23 +- Source/JavaScriptCore/runtime/BigInteger.h | 8 +- .../JavaScriptCore/runtime/BooleanConstructor.cpp | 27 +- Source/JavaScriptCore/runtime/BooleanConstructor.h | 11 +- Source/JavaScriptCore/runtime/BooleanObject.cpp | 6 +- Source/JavaScriptCore/runtime/BooleanObject.h | 7 +- Source/JavaScriptCore/runtime/BooleanPrototype.cpp | 38 +- Source/JavaScriptCore/runtime/BooleanPrototype.h | 8 +- Source/JavaScriptCore/runtime/BundlePath.h | 35 + Source/JavaScriptCore/runtime/Butterfly.h | 21 +- Source/JavaScriptCore/runtime/ButterflyInlines.h | 125 +- Source/JavaScriptCore/runtime/CallData.cpp | 34 +- Source/JavaScriptCore/runtime/CallData.h | 45 +- Source/JavaScriptCore/runtime/CatchScope.cpp | 47 + Source/JavaScriptCore/runtime/CatchScope.h | 71 + Source/JavaScriptCore/runtime/ClassInfo.h | 101 +- Source/JavaScriptCore/runtime/ClonedArguments.cpp | 280 ++ Source/JavaScriptCore/runtime/ClonedArguments.h | 80 + Source/JavaScriptCore/runtime/CodeCache.cpp | 184 +- Source/JavaScriptCore/runtime/CodeCache.h | 195 +- .../runtime/CodeSpecializationKind.h | 6 +- .../JavaScriptCore/runtime/CommonIdentifiers.cpp | 57 +- Source/JavaScriptCore/runtime/CommonIdentifiers.h | 219 +- Source/JavaScriptCore/runtime/CommonSlowPaths.cpp | 789 +++++- Source/JavaScriptCore/runtime/CommonSlowPaths.h | 235 +- .../runtime/CommonSlowPathsExceptions.cpp | 14 +- .../runtime/CommonSlowPathsExceptions.h | 10 +- Source/JavaScriptCore/runtime/CompilationResult.h | 6 +- Source/JavaScriptCore/runtime/Completion.cpp | 206 +- Source/JavaScriptCore/runtime/Completion.h | 56 +- Source/JavaScriptCore/runtime/ConcurrentJITLock.h | 123 - Source/JavaScriptCore/runtime/ConcurrentJSLock.h | 134 + Source/JavaScriptCore/runtime/ConsoleClient.cpp | 251 ++ Source/JavaScriptCore/runtime/ConsoleClient.h | 71 + Source/JavaScriptCore/runtime/ConsoleObject.cpp | 370 +++ Source/JavaScriptCore/runtime/ConsoleObject.h | 57 + Source/JavaScriptCore/runtime/ConsoleTypes.h | 72 + Source/JavaScriptCore/runtime/ConstantMode.cpp | 46 + Source/JavaScriptCore/runtime/ConstantMode.h | 17 +- Source/JavaScriptCore/runtime/ConstructAbility.h | 35 + Source/JavaScriptCore/runtime/ConstructData.cpp | 33 +- Source/JavaScriptCore/runtime/ConstructData.h | 47 +- .../JavaScriptCore/runtime/ControlFlowProfiler.cpp | 137 + .../JavaScriptCore/runtime/ControlFlowProfiler.h | 112 + .../JavaScriptCore/runtime/CustomGetterSetter.cpp | 63 + Source/JavaScriptCore/runtime/CustomGetterSetter.h | 81 + Source/JavaScriptCore/runtime/DataView.cpp | 21 +- Source/JavaScriptCore/runtime/DataView.h | 19 +- Source/JavaScriptCore/runtime/DateConstructor.cpp | 180 +- Source/JavaScriptCore/runtime/DateConstructor.h | 58 +- Source/JavaScriptCore/runtime/DateConversion.cpp | 3 +- Source/JavaScriptCore/runtime/DateConversion.h | 7 +- Source/JavaScriptCore/runtime/DateInstance.cpp | 8 +- Source/JavaScriptCore/runtime/DateInstance.h | 125 +- Source/JavaScriptCore/runtime/DateInstanceCache.h | 94 +- Source/JavaScriptCore/runtime/DatePrototype.cpp | 476 ++-- Source/JavaScriptCore/runtime/DatePrototype.h | 50 +- .../runtime/DefinePropertyAttributes.h | 164 ++ Source/JavaScriptCore/runtime/DirectArguments.cpp | 166 ++ Source/JavaScriptCore/runtime/DirectArguments.h | 170 ++ .../runtime/DirectArgumentsOffset.cpp | 42 + .../JavaScriptCore/runtime/DirectArgumentsOffset.h | 49 + .../runtime/DirectEvalExecutable.cpp | 78 + .../JavaScriptCore/runtime/DirectEvalExecutable.h | 39 + Source/JavaScriptCore/runtime/DumpContext.cpp | 4 +- Source/JavaScriptCore/runtime/DumpContext.h | 9 +- .../runtime/ECMAScriptSpecInternalFunctions.cpp | 42 + .../runtime/ECMAScriptSpecInternalFunctions.h | 34 + Source/JavaScriptCore/runtime/EnumerationMode.h | 77 + Source/JavaScriptCore/runtime/Error.cpp | 275 +- Source/JavaScriptCore/runtime/Error.h | 235 +- Source/JavaScriptCore/runtime/ErrorConstructor.cpp | 36 +- Source/JavaScriptCore/runtime/ErrorConstructor.h | 50 +- .../JavaScriptCore/runtime/ErrorHandlingScope.cpp | 48 + Source/JavaScriptCore/runtime/ErrorHandlingScope.h | 41 + Source/JavaScriptCore/runtime/ErrorInstance.cpp | 198 +- Source/JavaScriptCore/runtime/ErrorInstance.h | 72 +- Source/JavaScriptCore/runtime/ErrorPrototype.cpp | 47 +- Source/JavaScriptCore/runtime/ErrorPrototype.h | 53 +- Source/JavaScriptCore/runtime/EvalExecutable.cpp | 57 + Source/JavaScriptCore/runtime/EvalExecutable.h | 76 + Source/JavaScriptCore/runtime/Exception.cpp | 84 + Source/JavaScriptCore/runtime/Exception.h | 78 + .../runtime/ExceptionEventLocation.cpp | 39 + .../runtime/ExceptionEventLocation.h | 51 + Source/JavaScriptCore/runtime/ExceptionFuzz.cpp | 67 + Source/JavaScriptCore/runtime/ExceptionFuzz.h | 46 + Source/JavaScriptCore/runtime/ExceptionHelpers.cpp | 270 +- Source/JavaScriptCore/runtime/ExceptionHelpers.h | 53 +- Source/JavaScriptCore/runtime/ExceptionScope.cpp | 52 + Source/JavaScriptCore/runtime/ExceptionScope.h | 78 + Source/JavaScriptCore/runtime/Executable.cpp | 635 ----- Source/JavaScriptCore/runtime/Executable.h | 673 ----- Source/JavaScriptCore/runtime/ExecutableBase.cpp | 155 ++ Source/JavaScriptCore/runtime/ExecutableBase.h | 240 ++ Source/JavaScriptCore/runtime/Float32Array.h | 6 +- Source/JavaScriptCore/runtime/Float64Array.h | 6 +- .../JavaScriptCore/runtime/FunctionConstructor.cpp | 120 +- .../JavaScriptCore/runtime/FunctionConstructor.h | 62 +- .../JavaScriptCore/runtime/FunctionExecutable.cpp | 109 + Source/JavaScriptCore/runtime/FunctionExecutable.h | 189 ++ .../runtime/FunctionExecutableDump.cpp | 8 +- .../runtime/FunctionExecutableDump.h | 9 +- .../runtime/FunctionHasExecutedCache.cpp | 100 + .../runtime/FunctionHasExecutedCache.h | 62 + .../JavaScriptCore/runtime/FunctionPrototype.cpp | 206 +- Source/JavaScriptCore/runtime/FunctionPrototype.h | 61 +- Source/JavaScriptCore/runtime/FunctionRareData.cpp | 94 + Source/JavaScriptCore/runtime/FunctionRareData.h | 129 + .../JavaScriptCore/runtime/GCActivityCallback.cpp | 191 -- Source/JavaScriptCore/runtime/GCActivityCallback.h | 112 - .../runtime/GeneratorFunctionConstructor.cpp | 77 + .../runtime/GeneratorFunctionConstructor.h | 65 + .../runtime/GeneratorFunctionPrototype.cpp | 59 + .../runtime/GeneratorFunctionPrototype.h | 59 + .../JavaScriptCore/runtime/GeneratorPrototype.cpp | 55 + Source/JavaScriptCore/runtime/GeneratorPrototype.h | 61 + Source/JavaScriptCore/runtime/GenericArguments.h | 66 + .../runtime/GenericArgumentsInlines.h | 316 +++ Source/JavaScriptCore/runtime/GenericOffset.h | 109 + .../JavaScriptCore/runtime/GenericTypedArrayView.h | 26 +- .../runtime/GenericTypedArrayViewInlines.h | 54 +- Source/JavaScriptCore/runtime/GetPutInfo.h | 234 ++ Source/JavaScriptCore/runtime/GetterSetter.cpp | 69 +- Source/JavaScriptCore/runtime/GetterSetter.h | 172 +- .../JavaScriptCore/runtime/HasOwnPropertyCache.h | 153 ++ Source/JavaScriptCore/runtime/HashMapImpl.cpp | 94 + Source/JavaScriptCore/runtime/HashMapImpl.h | 638 +++++ Source/JavaScriptCore/runtime/Identifier.cpp | 127 +- Source/JavaScriptCore/runtime/Identifier.h | 495 ++-- Source/JavaScriptCore/runtime/IdentifierInlines.h | 151 ++ Source/JavaScriptCore/runtime/IndexingHeader.h | 18 +- .../JavaScriptCore/runtime/IndexingHeaderInlines.h | 8 +- Source/JavaScriptCore/runtime/IndexingType.h | 78 +- .../runtime/IndirectEvalExecutable.cpp | 77 + .../runtime/IndirectEvalExecutable.h | 39 + Source/JavaScriptCore/runtime/InferredType.cpp | 613 +++++ Source/JavaScriptCore/runtime/InferredType.h | 289 ++ .../JavaScriptCore/runtime/InferredTypeTable.cpp | 184 ++ Source/JavaScriptCore/runtime/InferredTypeTable.h | 109 + Source/JavaScriptCore/runtime/InferredValue.cpp | 139 + Source/JavaScriptCore/runtime/InferredValue.h | 134 + .../JavaScriptCore/runtime/InitializeThreading.cpp | 22 +- .../JavaScriptCore/runtime/InitializeThreading.h | 15 +- .../runtime/InspectorInstrumentationObject.cpp | 95 + .../runtime/InspectorInstrumentationObject.h | 62 + Source/JavaScriptCore/runtime/Int16Array.h | 6 +- Source/JavaScriptCore/runtime/Int32Array.h | 6 +- Source/JavaScriptCore/runtime/Int8Array.h | 6 +- .../runtime/IntegralTypedArrayBase.h | 63 - .../runtime/IntendedStructureChain.cpp | 141 - .../runtime/IntendedStructureChain.h | 70 - Source/JavaScriptCore/runtime/InternalFunction.cpp | 80 +- Source/JavaScriptCore/runtime/InternalFunction.h | 59 +- Source/JavaScriptCore/runtime/IntlCollator.cpp | 454 ++++ Source/JavaScriptCore/runtime/IntlCollator.h | 86 + .../runtime/IntlCollatorConstructor.cpp | 168 ++ .../runtime/IntlCollatorConstructor.h | 63 + .../runtime/IntlCollatorPrototype.cpp | 154 ++ .../JavaScriptCore/runtime/IntlCollatorPrototype.h | 54 + .../JavaScriptCore/runtime/IntlDateTimeFormat.cpp | 896 +++++++ Source/JavaScriptCore/runtime/IntlDateTimeFormat.h | 108 + .../runtime/IntlDateTimeFormatConstructor.cpp | 169 ++ .../runtime/IntlDateTimeFormatConstructor.h | 63 + .../runtime/IntlDateTimeFormatPrototype.cpp | 175 ++ .../runtime/IntlDateTimeFormatPrototype.h | 54 + Source/JavaScriptCore/runtime/IntlNumberFormat.cpp | 519 ++++ Source/JavaScriptCore/runtime/IntlNumberFormat.h | 90 + .../runtime/IntlNumberFormatConstructor.cpp | 169 ++ .../runtime/IntlNumberFormatConstructor.h | 63 + .../runtime/IntlNumberFormatPrototype.cpp | 163 ++ .../runtime/IntlNumberFormatPrototype.h | 54 + Source/JavaScriptCore/runtime/IntlObject.cpp | 1057 ++++++++ Source/JavaScriptCore/runtime/IntlObject.h | 73 + Source/JavaScriptCore/runtime/IntlObjectInlines.h | 66 + Source/JavaScriptCore/runtime/Intrinsic.h | 57 +- Source/JavaScriptCore/runtime/IterationKind.h | 37 + Source/JavaScriptCore/runtime/IterationStatus.h | 35 + .../JavaScriptCore/runtime/IteratorOperations.cpp | 206 ++ Source/JavaScriptCore/runtime/IteratorOperations.h | 73 + .../JavaScriptCore/runtime/IteratorPrototype.cpp | 48 + Source/JavaScriptCore/runtime/IteratorPrototype.h | 59 + .../JavaScriptCore/runtime/JSAPIValueWrapper.cpp | 2 +- Source/JavaScriptCore/runtime/JSAPIValueWrapper.h | 76 +- Source/JavaScriptCore/runtime/JSActivation.cpp | 234 -- Source/JavaScriptCore/runtime/JSActivation.h | 208 -- .../JavaScriptCore/runtime/JSArgumentsIterator.cpp | 41 - .../JavaScriptCore/runtime/JSArgumentsIterator.h | 79 - Source/JavaScriptCore/runtime/JSArray.cpp | 1337 ++++------ Source/JavaScriptCore/runtime/JSArray.h | 233 +- Source/JavaScriptCore/runtime/JSArrayBuffer.cpp | 79 +- Source/JavaScriptCore/runtime/JSArrayBuffer.h | 54 +- .../runtime/JSArrayBufferConstructor.cpp | 68 +- .../runtime/JSArrayBufferConstructor.h | 21 +- .../runtime/JSArrayBufferPrototype.cpp | 83 +- .../runtime/JSArrayBufferPrototype.h | 16 +- .../JavaScriptCore/runtime/JSArrayBufferView.cpp | 168 +- Source/JavaScriptCore/runtime/JSArrayBufferView.h | 55 +- .../runtime/JSArrayBufferViewInlines.h | 48 +- Source/JavaScriptCore/runtime/JSArrayInlines.h | 101 + Source/JavaScriptCore/runtime/JSArrayIterator.cpp | 169 -- Source/JavaScriptCore/runtime/JSArrayIterator.h | 93 - Source/JavaScriptCore/runtime/JSAsyncFunction.cpp | 74 + Source/JavaScriptCore/runtime/JSAsyncFunction.h | 64 + Source/JavaScriptCore/runtime/JSBoundFunction.cpp | 158 +- Source/JavaScriptCore/runtime/JSBoundFunction.h | 31 +- Source/JavaScriptCore/runtime/JSCInlines.h | 54 + Source/JavaScriptCore/runtime/JSCJSValue.cpp | 282 +- Source/JavaScriptCore/runtime/JSCJSValue.h | 194 +- Source/JavaScriptCore/runtime/JSCJSValueInlines.h | 380 ++- Source/JavaScriptCore/runtime/JSCallee.cpp | 66 + Source/JavaScriptCore/runtime/JSCallee.h | 105 + Source/JavaScriptCore/runtime/JSCell.cpp | 131 +- Source/JavaScriptCore/runtime/JSCell.h | 211 +- Source/JavaScriptCore/runtime/JSCellInlines.h | 265 +- .../runtime/JSCustomGetterSetterFunction.cpp | 96 + .../runtime/JSCustomGetterSetterFunction.h | 71 + Source/JavaScriptCore/runtime/JSDataView.cpp | 116 +- Source/JavaScriptCore/runtime/JSDataView.h | 32 +- .../JavaScriptCore/runtime/JSDataViewPrototype.cpp | 264 +- .../JavaScriptCore/runtime/JSDataViewPrototype.h | 14 +- Source/JavaScriptCore/runtime/JSDateMath.cpp | 5 +- Source/JavaScriptCore/runtime/JSDateMath.h | 15 +- .../JavaScriptCore/runtime/JSDestructibleObject.h | 47 +- .../runtime/JSDestructibleObjectSubspace.cpp | 66 + .../runtime/JSDestructibleObjectSubspace.h | 42 + .../JavaScriptCore/runtime/JSEnvironmentRecord.cpp | 67 + .../JavaScriptCore/runtime/JSEnvironmentRecord.h | 114 + Source/JavaScriptCore/runtime/JSExportMacros.h | 12 +- Source/JavaScriptCore/runtime/JSFixedArray.cpp | 43 + Source/JavaScriptCore/runtime/JSFixedArray.h | 140 + Source/JavaScriptCore/runtime/JSFloat32Array.h | 6 +- Source/JavaScriptCore/runtime/JSFloat64Array.h | 6 +- Source/JavaScriptCore/runtime/JSFunction.cpp | 636 +++-- Source/JavaScriptCore/runtime/JSFunction.h | 326 +-- Source/JavaScriptCore/runtime/JSFunctionInlines.h | 65 +- .../JavaScriptCore/runtime/JSGeneratorFunction.cpp | 72 + .../JavaScriptCore/runtime/JSGeneratorFunction.h | 95 + .../runtime/JSGenericTypedArrayView.h | 188 +- .../runtime/JSGenericTypedArrayViewConstructor.h | 24 +- .../JSGenericTypedArrayViewConstructorInlines.h | 253 +- .../runtime/JSGenericTypedArrayViewInlines.h | 399 +-- .../runtime/JSGenericTypedArrayViewPrototype.h | 20 +- .../JSGenericTypedArrayViewPrototypeFunctions.h | 579 ++++ .../JSGenericTypedArrayViewPrototypeInlines.h | 110 +- .../runtime/JSGlobalLexicalEnvironment.cpp | 71 + .../runtime/JSGlobalLexicalEnvironment.h | 74 + Source/JavaScriptCore/runtime/JSGlobalObject.cpp | 1443 +++++++--- Source/JavaScriptCore/runtime/JSGlobalObject.h | 718 +++-- .../runtime/JSGlobalObjectDebuggable.cpp | 88 + .../runtime/JSGlobalObjectDebuggable.h | 71 + .../runtime/JSGlobalObjectFunctions.cpp | 766 +++--- .../runtime/JSGlobalObjectFunctions.h | 20 +- .../JavaScriptCore/runtime/JSGlobalObjectInlines.h | 69 + Source/JavaScriptCore/runtime/JSInt16Array.h | 6 +- Source/JavaScriptCore/runtime/JSInt32Array.h | 6 +- Source/JavaScriptCore/runtime/JSInt8Array.h | 6 +- .../JavaScriptCore/runtime/JSInternalPromise.cpp | 67 + Source/JavaScriptCore/runtime/JSInternalPromise.h | 57 + .../runtime/JSInternalPromiseConstructor.cpp | 86 + .../runtime/JSInternalPromiseConstructor.h | 51 + .../runtime/JSInternalPromiseDeferred.cpp | 78 + .../runtime/JSInternalPromiseDeferred.h | 56 + .../runtime/JSInternalPromisePrototype.cpp | 59 + .../runtime/JSInternalPromisePrototype.h | 46 + Source/JavaScriptCore/runtime/JSJob.cpp | 79 + Source/JavaScriptCore/runtime/JSJob.h | 38 + .../runtime/JSLexicalEnvironment.cpp | 116 + .../JavaScriptCore/runtime/JSLexicalEnvironment.h | 88 + Source/JavaScriptCore/runtime/JSLock.cpp | 336 ++- Source/JavaScriptCore/runtime/JSLock.h | 203 +- Source/JavaScriptCore/runtime/JSMap.cpp | 21 +- Source/JavaScriptCore/runtime/JSMap.h | 40 +- Source/JavaScriptCore/runtime/JSMapIterator.cpp | 27 +- Source/JavaScriptCore/runtime/JSMapIterator.h | 89 +- .../JavaScriptCore/runtime/JSModuleEnvironment.cpp | 139 + .../JavaScriptCore/runtime/JSModuleEnvironment.h | 100 + Source/JavaScriptCore/runtime/JSModuleLoader.cpp | 256 ++ Source/JavaScriptCore/runtime/JSModuleLoader.h | 88 + .../runtime/JSModuleNamespaceObject.cpp | 221 ++ .../runtime/JSModuleNamespaceObject.h | 113 + Source/JavaScriptCore/runtime/JSModuleRecord.cpp | 213 ++ Source/JavaScriptCore/runtime/JSModuleRecord.h | 71 + Source/JavaScriptCore/runtime/JSNameScope.cpp | 83 - Source/JavaScriptCore/runtime/JSNameScope.h | 90 - .../JavaScriptCore/runtime/JSNativeStdFunction.cpp | 77 + .../JavaScriptCore/runtime/JSNativeStdFunction.h | 66 + Source/JavaScriptCore/runtime/JSNotAnObject.cpp | 88 - Source/JavaScriptCore/runtime/JSNotAnObject.h | 85 - Source/JavaScriptCore/runtime/JSONObject.cpp | 464 ++-- Source/JavaScriptCore/runtime/JSONObject.h | 55 +- Source/JavaScriptCore/runtime/JSObject.cpp | 2780 +++++++++++++------- Source/JavaScriptCore/runtime/JSObject.h | 1196 ++++----- Source/JavaScriptCore/runtime/JSObjectInlines.h | 363 +++ Source/JavaScriptCore/runtime/JSPromise.cpp | 137 +- Source/JavaScriptCore/runtime/JSPromise.h | 68 +- .../runtime/JSPromiseConstructor.cpp | 518 +--- .../JavaScriptCore/runtime/JSPromiseConstructor.h | 25 +- .../JavaScriptCore/runtime/JSPromiseDeferred.cpp | 225 +- Source/JavaScriptCore/runtime/JSPromiseDeferred.h | 36 +- .../JavaScriptCore/runtime/JSPromiseFunctions.cpp | 274 -- Source/JavaScriptCore/runtime/JSPromiseFunctions.h | 47 - .../JavaScriptCore/runtime/JSPromisePrototype.cpp | 161 +- Source/JavaScriptCore/runtime/JSPromisePrototype.h | 17 +- .../JavaScriptCore/runtime/JSPromiseReaction.cpp | 158 -- Source/JavaScriptCore/runtime/JSPromiseReaction.h | 68 - .../runtime/JSPropertyNameEnumerator.cpp | 98 + .../runtime/JSPropertyNameEnumerator.h | 145 + .../runtime/JSPropertyNameIterator.cpp | 197 +- .../runtime/JSPropertyNameIterator.h | 152 +- Source/JavaScriptCore/runtime/JSProxy.cpp | 89 +- Source/JavaScriptCore/runtime/JSProxy.h | 36 +- Source/JavaScriptCore/runtime/JSScope.cpp | 294 ++- Source/JavaScriptCore/runtime/JSScope.h | 165 +- Source/JavaScriptCore/runtime/JSScriptFetcher.cpp | 40 + Source/JavaScriptCore/runtime/JSScriptFetcher.h | 77 + .../runtime/JSSegmentedVariableObject.cpp | 89 +- .../runtime/JSSegmentedVariableObject.h | 76 +- .../runtime/JSSegmentedVariableObjectSubspace.cpp | 66 + .../runtime/JSSegmentedVariableObjectSubspace.h | 42 + Source/JavaScriptCore/runtime/JSSet.cpp | 20 +- Source/JavaScriptCore/runtime/JSSet.h | 39 +- Source/JavaScriptCore/runtime/JSSetIterator.cpp | 27 +- Source/JavaScriptCore/runtime/JSSetIterator.h | 84 +- Source/JavaScriptCore/runtime/JSSourceCode.cpp | 40 + Source/JavaScriptCore/runtime/JSSourceCode.h | 77 + Source/JavaScriptCore/runtime/JSString.cpp | 379 ++- Source/JavaScriptCore/runtime/JSString.h | 1075 +++++--- Source/JavaScriptCore/runtime/JSStringBuilder.h | 158 +- Source/JavaScriptCore/runtime/JSStringInlines.h | 39 + Source/JavaScriptCore/runtime/JSStringIterator.cpp | 61 + Source/JavaScriptCore/runtime/JSStringIterator.h | 63 + Source/JavaScriptCore/runtime/JSStringJoiner.cpp | 148 +- Source/JavaScriptCore/runtime/JSStringJoiner.h | 131 +- Source/JavaScriptCore/runtime/JSStringSubspace.cpp | 66 + Source/JavaScriptCore/runtime/JSStringSubspace.h | 42 + .../JavaScriptCore/runtime/JSSymbolTableObject.cpp | 37 +- .../JavaScriptCore/runtime/JSSymbolTableObject.h | 172 +- .../runtime/JSTemplateRegistryKey.cpp | 56 + .../JavaScriptCore/runtime/JSTemplateRegistryKey.h | 58 + Source/JavaScriptCore/runtime/JSType.h | 72 +- Source/JavaScriptCore/runtime/JSTypeInfo.h | 172 +- .../runtime/JSTypedArrayConstructors.cpp | 4 +- .../runtime/JSTypedArrayConstructors.h | 5 +- .../runtime/JSTypedArrayPrototypes.cpp | 7 +- .../runtime/JSTypedArrayPrototypes.h | 6 +- .../runtime/JSTypedArrayViewConstructor.cpp | 85 + .../runtime/JSTypedArrayViewConstructor.h | 59 + .../runtime/JSTypedArrayViewPrototype.cpp | 356 +++ .../runtime/JSTypedArrayViewPrototype.h | 54 + Source/JavaScriptCore/runtime/JSTypedArrays.cpp | 11 +- Source/JavaScriptCore/runtime/JSTypedArrays.h | 8 +- Source/JavaScriptCore/runtime/JSUint16Array.h | 6 +- Source/JavaScriptCore/runtime/JSUint32Array.h | 6 +- Source/JavaScriptCore/runtime/JSUint8Array.h | 6 +- .../JavaScriptCore/runtime/JSUint8ClampedArray.h | 6 +- Source/JavaScriptCore/runtime/JSVariableObject.cpp | 38 - Source/JavaScriptCore/runtime/JSVariableObject.h | 76 - Source/JavaScriptCore/runtime/JSWeakMap.cpp | 14 +- Source/JavaScriptCore/runtime/JSWeakMap.h | 10 +- Source/JavaScriptCore/runtime/JSWeakSet.cpp | 54 + Source/JavaScriptCore/runtime/JSWeakSet.h | 79 + Source/JavaScriptCore/runtime/JSWithScope.cpp | 31 +- Source/JavaScriptCore/runtime/JSWithScope.h | 49 +- Source/JavaScriptCore/runtime/JSWrapperObject.cpp | 7 +- Source/JavaScriptCore/runtime/JSWrapperObject.h | 92 +- .../JavaScriptCore/runtime/LazyClassStructure.cpp | 102 + Source/JavaScriptCore/runtime/LazyClassStructure.h | 125 + .../runtime/LazyClassStructureInlines.h | 46 + Source/JavaScriptCore/runtime/LazyProperty.h | 118 + .../JavaScriptCore/runtime/LazyPropertyInlines.h | 104 + Source/JavaScriptCore/runtime/LiteralParser.cpp | 217 +- Source/JavaScriptCore/runtime/LiteralParser.h | 64 +- Source/JavaScriptCore/runtime/Lookup.cpp | 83 +- Source/JavaScriptCore/runtime/Lookup.h | 555 ++-- Source/JavaScriptCore/runtime/MapBase.cpp | 50 + Source/JavaScriptCore/runtime/MapBase.h | 94 + Source/JavaScriptCore/runtime/MapConstructor.cpp | 82 +- Source/JavaScriptCore/runtime/MapConstructor.h | 14 +- Source/JavaScriptCore/runtime/MapData.cpp | 256 -- Source/JavaScriptCore/runtime/MapData.h | 236 -- .../runtime/MapIteratorConstructor.cpp | 45 - .../runtime/MapIteratorConstructor.h | 63 - .../runtime/MapIteratorPrototype.cpp | 40 +- .../JavaScriptCore/runtime/MapIteratorPrototype.h | 7 +- Source/JavaScriptCore/runtime/MapPrototype.cpp | 204 +- Source/JavaScriptCore/runtime/MapPrototype.h | 10 +- Source/JavaScriptCore/runtime/MatchResult.cpp | 40 + Source/JavaScriptCore/runtime/MatchResult.h | 24 +- Source/JavaScriptCore/runtime/MathCommon.cpp | 524 ++++ Source/JavaScriptCore/runtime/MathCommon.h | 212 ++ Source/JavaScriptCore/runtime/MathObject.cpp | 633 +---- Source/JavaScriptCore/runtime/MathObject.h | 48 +- Source/JavaScriptCore/runtime/MemoryStatistics.cpp | 48 + Source/JavaScriptCore/runtime/MemoryStatistics.h | 10 +- Source/JavaScriptCore/runtime/Microtask.h | 5 +- .../runtime/ModuleLoaderPrototype.cpp | 248 ++ .../JavaScriptCore/runtime/ModuleLoaderPrototype.h | 57 + .../runtime/ModuleProgramExecutable.cpp | 100 + .../runtime/ModuleProgramExecutable.h | 78 + Source/JavaScriptCore/runtime/NameConstructor.cpp | 69 - Source/JavaScriptCore/runtime/NameConstructor.h | 65 - Source/JavaScriptCore/runtime/NameInstance.cpp | 47 - Source/JavaScriptCore/runtime/NameInstance.h | 77 - Source/JavaScriptCore/runtime/NamePrototype.cpp | 81 - Source/JavaScriptCore/runtime/NamePrototype.h | 64 - .../runtime/NativeErrorConstructor.cpp | 50 +- .../runtime/NativeErrorConstructor.h | 72 +- .../runtime/NativeErrorPrototype.cpp | 8 +- .../JavaScriptCore/runtime/NativeErrorPrototype.h | 46 +- Source/JavaScriptCore/runtime/NativeExecutable.cpp | 88 + Source/JavaScriptCore/runtime/NativeExecutable.h | 96 + .../runtime/NativeStdFunctionCell.cpp | 55 + .../JavaScriptCore/runtime/NativeStdFunctionCell.h | 58 + .../JavaScriptCore/runtime/NullGetterFunction.cpp | 52 + Source/JavaScriptCore/runtime/NullGetterFunction.h | 59 + .../JavaScriptCore/runtime/NullSetterFunction.cpp | 94 + Source/JavaScriptCore/runtime/NullSetterFunction.h | 59 + .../JavaScriptCore/runtime/NumberConstructor.cpp | 110 +- Source/JavaScriptCore/runtime/NumberConstructor.h | 57 +- Source/JavaScriptCore/runtime/NumberObject.cpp | 6 +- Source/JavaScriptCore/runtime/NumberObject.h | 43 +- Source/JavaScriptCore/runtime/NumberPrototype.cpp | 237 +- Source/JavaScriptCore/runtime/NumberPrototype.h | 61 +- Source/JavaScriptCore/runtime/NumericStrings.h | 109 +- .../JavaScriptCore/runtime/ObjectConstructor.cpp | 743 ++++-- Source/JavaScriptCore/runtime/ObjectConstructor.h | 138 +- Source/JavaScriptCore/runtime/ObjectPrototype.cpp | 255 +- Source/JavaScriptCore/runtime/ObjectPrototype.h | 36 +- Source/JavaScriptCore/runtime/Operations.cpp | 79 +- Source/JavaScriptCore/runtime/Operations.h | 200 +- Source/JavaScriptCore/runtime/Options.cpp | 755 +++++- Source/JavaScriptCore/runtime/Options.h | 678 ++++- Source/JavaScriptCore/runtime/ParseInt.h | 227 ++ Source/JavaScriptCore/runtime/PrivateName.h | 39 +- .../JavaScriptCore/runtime/ProgramExecutable.cpp | 214 ++ Source/JavaScriptCore/runtime/ProgramExecutable.h | 82 + .../JavaScriptCore/runtime/PropertyDescriptor.cpp | 55 +- Source/JavaScriptCore/runtime/PropertyDescriptor.h | 150 +- .../JavaScriptCore/runtime/PropertyMapHashTable.h | 165 +- Source/JavaScriptCore/runtime/PropertyName.h | 104 +- .../JavaScriptCore/runtime/PropertyNameArray.cpp | 55 - Source/JavaScriptCore/runtime/PropertyNameArray.h | 205 +- Source/JavaScriptCore/runtime/PropertyOffset.h | 6 +- Source/JavaScriptCore/runtime/PropertySlot.cpp | 33 + Source/JavaScriptCore/runtime/PropertySlot.h | 229 +- Source/JavaScriptCore/runtime/PropertyStorage.h | 6 +- Source/JavaScriptCore/runtime/PropertyTable.cpp | 50 +- Source/JavaScriptCore/runtime/Protect.h | 72 +- Source/JavaScriptCore/runtime/PrototypeMap.cpp | 41 +- Source/JavaScriptCore/runtime/PrototypeMap.h | 43 +- .../JavaScriptCore/runtime/PrototypeMapInlines.h | 46 + Source/JavaScriptCore/runtime/ProxyConstructor.cpp | 124 + Source/JavaScriptCore/runtime/ProxyConstructor.h | 56 + Source/JavaScriptCore/runtime/ProxyObject.cpp | 1164 ++++++++ Source/JavaScriptCore/runtime/ProxyObject.h | 116 + Source/JavaScriptCore/runtime/ProxyRevoke.cpp | 87 + Source/JavaScriptCore/runtime/ProxyRevoke.h | 60 + Source/JavaScriptCore/runtime/PureNaN.h | 95 + Source/JavaScriptCore/runtime/PutDirectIndexMode.h | 6 +- Source/JavaScriptCore/runtime/PutPropertySlot.h | 185 +- Source/JavaScriptCore/runtime/ReflectObject.cpp | 314 +++ Source/JavaScriptCore/runtime/ReflectObject.h | 58 + Source/JavaScriptCore/runtime/RegExp.cpp | 297 +-- Source/JavaScriptCore/runtime/RegExp.h | 153 +- Source/JavaScriptCore/runtime/RegExpCache.cpp | 7 +- Source/JavaScriptCore/runtime/RegExpCache.h | 18 +- .../JavaScriptCore/runtime/RegExpCachedResult.cpp | 52 +- Source/JavaScriptCore/runtime/RegExpCachedResult.h | 102 +- .../JavaScriptCore/runtime/RegExpConstructor.cpp | 284 +- Source/JavaScriptCore/runtime/RegExpConstructor.h | 178 +- Source/JavaScriptCore/runtime/RegExpInlines.h | 234 ++ Source/JavaScriptCore/runtime/RegExpKey.h | 13 +- .../JavaScriptCore/runtime/RegExpMatchesArray.cpp | 127 +- Source/JavaScriptCore/runtime/RegExpMatchesArray.h | 207 +- Source/JavaScriptCore/runtime/RegExpObject.cpp | 345 +-- Source/JavaScriptCore/runtime/RegExpObject.h | 150 +- .../JavaScriptCore/runtime/RegExpObjectInlines.h | 143 + Source/JavaScriptCore/runtime/RegExpPrototype.cpp | 693 ++++- Source/JavaScriptCore/runtime/RegExpPrototype.h | 62 +- Source/JavaScriptCore/runtime/Reject.h | 44 - Source/JavaScriptCore/runtime/RuntimeFlags.h | 97 + Source/JavaScriptCore/runtime/RuntimeType.cpp | 87 + Source/JavaScriptCore/runtime/RuntimeType.h | 59 + Source/JavaScriptCore/runtime/SamplingCounter.cpp | 2 +- Source/JavaScriptCore/runtime/SamplingCounter.h | 9 +- Source/JavaScriptCore/runtime/SamplingProfiler.cpp | 1096 ++++++++ Source/JavaScriptCore/runtime/SamplingProfiler.h | 216 ++ Source/JavaScriptCore/runtime/ScopeOffset.cpp | 42 + Source/JavaScriptCore/runtime/ScopeOffset.h | 47 + Source/JavaScriptCore/runtime/ScopedArguments.cpp | 156 ++ Source/JavaScriptCore/runtime/ScopedArguments.h | 168 ++ .../runtime/ScopedArgumentsTable.cpp | 109 + .../JavaScriptCore/runtime/ScopedArgumentsTable.h | 92 + Source/JavaScriptCore/runtime/ScriptExecutable.cpp | 334 +++ Source/JavaScriptCore/runtime/ScriptExecutable.h | 143 + Source/JavaScriptCore/runtime/ScriptFetcher.h | 37 + Source/JavaScriptCore/runtime/SetConstructor.cpp | 75 +- Source/JavaScriptCore/runtime/SetConstructor.h | 14 +- .../runtime/SetIteratorConstructor.cpp | 45 - .../runtime/SetIteratorConstructor.h | 63 - .../runtime/SetIteratorPrototype.cpp | 39 +- .../JavaScriptCore/runtime/SetIteratorPrototype.h | 7 +- Source/JavaScriptCore/runtime/SetPrototype.cpp | 177 +- Source/JavaScriptCore/runtime/SetPrototype.h | 10 +- .../runtime/SimpleTypedArrayController.cpp | 29 +- .../runtime/SimpleTypedArrayController.h | 24 +- Source/JavaScriptCore/runtime/SlowPathReturnType.h | 83 + Source/JavaScriptCore/runtime/SmallStrings.cpp | 46 +- Source/JavaScriptCore/runtime/SmallStrings.h | 124 +- Source/JavaScriptCore/runtime/SourceOrigin.h | 58 + .../JavaScriptCore/runtime/SparseArrayValueMap.cpp | 104 +- .../JavaScriptCore/runtime/SparseArrayValueMap.h | 24 +- Source/JavaScriptCore/runtime/StackAlignment.h | 26 +- Source/JavaScriptCore/runtime/StackFrame.cpp | 126 + Source/JavaScriptCore/runtime/StackFrame.h | 72 + .../runtime/StrictEvalActivation.cpp | 8 +- .../JavaScriptCore/runtime/StrictEvalActivation.h | 21 +- .../JavaScriptCore/runtime/StringConstructor.cpp | 81 +- Source/JavaScriptCore/runtime/StringConstructor.h | 57 +- .../runtime/StringIteratorPrototype.cpp | 55 + .../runtime/StringIteratorPrototype.h | 60 + Source/JavaScriptCore/runtime/StringObject.cpp | 121 +- Source/JavaScriptCore/runtime/StringObject.h | 138 +- Source/JavaScriptCore/runtime/StringPrototype.cpp | 1775 ++++++++----- Source/JavaScriptCore/runtime/StringPrototype.h | 60 +- .../runtime/StringRecursionChecker.cpp | 8 +- .../runtime/StringRecursionChecker.h | 31 +- Source/JavaScriptCore/runtime/Structure.cpp | 1321 +++++----- Source/JavaScriptCore/runtime/Structure.h | 617 +++-- Source/JavaScriptCore/runtime/StructureChain.cpp | 18 +- Source/JavaScriptCore/runtime/StructureChain.h | 103 +- Source/JavaScriptCore/runtime/StructureIDBlob.h | 92 + Source/JavaScriptCore/runtime/StructureIDTable.cpp | 121 + Source/JavaScriptCore/runtime/StructureIDTable.h | 135 + Source/JavaScriptCore/runtime/StructureInlines.h | 302 ++- .../JavaScriptCore/runtime/StructureRareData.cpp | 183 +- Source/JavaScriptCore/runtime/StructureRareData.h | 51 +- .../runtime/StructureRareDataInlines.h | 13 +- .../runtime/StructureTransitionTable.h | 122 +- Source/JavaScriptCore/runtime/Symbol.cpp | 132 + Source/JavaScriptCore/runtime/Symbol.h | 87 + .../JavaScriptCore/runtime/SymbolConstructor.cpp | 129 + Source/JavaScriptCore/runtime/SymbolConstructor.h | 65 + Source/JavaScriptCore/runtime/SymbolObject.cpp | 61 + Source/JavaScriptCore/runtime/SymbolObject.h | 66 + Source/JavaScriptCore/runtime/SymbolPrototype.cpp | 113 + Source/JavaScriptCore/runtime/SymbolPrototype.h | 60 + Source/JavaScriptCore/runtime/SymbolTable.cpp | 229 +- Source/JavaScriptCore/runtime/SymbolTable.h | 465 +++- Source/JavaScriptCore/runtime/TemplateRegistry.cpp | 90 + Source/JavaScriptCore/runtime/TemplateRegistry.h | 47 + .../JavaScriptCore/runtime/TemplateRegistryKey.cpp | 39 + .../JavaScriptCore/runtime/TemplateRegistryKey.h | 124 + .../runtime/TemplateRegistryKeyTable.cpp | 64 + .../runtime/TemplateRegistryKeyTable.h | 59 + Source/JavaScriptCore/runtime/TestRunnerUtils.cpp | 106 +- Source/JavaScriptCore/runtime/TestRunnerUtils.h | 26 +- Source/JavaScriptCore/runtime/ThrowScope.cpp | 113 + Source/JavaScriptCore/runtime/ThrowScope.h | 107 + Source/JavaScriptCore/runtime/ToNativeFromValue.h | 16 +- Source/JavaScriptCore/runtime/Tracing.h | 50 - Source/JavaScriptCore/runtime/TypeError.h | 40 + .../JavaScriptCore/runtime/TypeLocationCache.cpp | 61 + Source/JavaScriptCore/runtime/TypeLocationCache.h | 65 + Source/JavaScriptCore/runtime/TypeProfiler.cpp | 167 ++ Source/JavaScriptCore/runtime/TypeProfiler.h | 141 + Source/JavaScriptCore/runtime/TypeProfilerLog.cpp | 115 + Source/JavaScriptCore/runtime/TypeProfilerLog.h | 83 + Source/JavaScriptCore/runtime/TypeSet.cpp | 584 ++++ Source/JavaScriptCore/runtime/TypeSet.h | 110 + Source/JavaScriptCore/runtime/TypedArrayAdaptors.h | 106 +- Source/JavaScriptCore/runtime/TypedArrayBase.h | 153 -- .../JavaScriptCore/runtime/TypedArrayController.h | 8 +- Source/JavaScriptCore/runtime/TypedArrayInlines.h | 7 +- Source/JavaScriptCore/runtime/TypedArrayType.cpp | 35 +- Source/JavaScriptCore/runtime/TypedArrayType.h | 78 +- Source/JavaScriptCore/runtime/TypedArrays.h | 6 +- Source/JavaScriptCore/runtime/TypeofType.cpp | 63 + Source/JavaScriptCore/runtime/TypeofType.h | 48 + Source/JavaScriptCore/runtime/Uint16Array.h | 6 +- Source/JavaScriptCore/runtime/Uint16WithFraction.h | 8 +- Source/JavaScriptCore/runtime/Uint32Array.h | 6 +- Source/JavaScriptCore/runtime/Uint8Array.h | 6 +- Source/JavaScriptCore/runtime/Uint8ClampedArray.h | 6 +- Source/JavaScriptCore/runtime/VM.cpp | 894 ++++--- Source/JavaScriptCore/runtime/VM.h | 1041 +++++--- Source/JavaScriptCore/runtime/VMEntryScope.cpp | 71 +- Source/JavaScriptCore/runtime/VMEntryScope.h | 23 +- Source/JavaScriptCore/runtime/VMInlines.h | 70 + Source/JavaScriptCore/runtime/VarOffset.cpp | 76 + Source/JavaScriptCore/runtime/VarOffset.h | 243 ++ Source/JavaScriptCore/runtime/Watchdog.cpp | 226 +- Source/JavaScriptCore/runtime/Watchdog.h | 93 +- Source/JavaScriptCore/runtime/WatchdogNone.cpp | 50 - Source/JavaScriptCore/runtime/WeakGCMap.h | 85 +- Source/JavaScriptCore/runtime/WeakGCMapInlines.h | 79 + .../JavaScriptCore/runtime/WeakMapConstructor.cpp | 72 +- Source/JavaScriptCore/runtime/WeakMapConstructor.h | 10 +- Source/JavaScriptCore/runtime/WeakMapData.cpp | 41 +- Source/JavaScriptCore/runtime/WeakMapData.h | 27 +- Source/JavaScriptCore/runtime/WeakMapPrototype.cpp | 60 +- Source/JavaScriptCore/runtime/WeakMapPrototype.h | 7 +- Source/JavaScriptCore/runtime/WeakRandom.h | 94 - .../JavaScriptCore/runtime/WeakSetConstructor.cpp | 98 + Source/JavaScriptCore/runtime/WeakSetConstructor.h | 63 + Source/JavaScriptCore/runtime/WeakSetPrototype.cpp | 105 + Source/JavaScriptCore/runtime/WeakSetPrototype.h | 58 + Source/JavaScriptCore/runtime/WriteBarrier.h | 60 +- .../JavaScriptCore/runtime/WriteBarrierInlines.h | 64 + 652 files changed, 64192 insertions(+), 25988 deletions(-) create mode 100644 Source/JavaScriptCore/runtime/AbstractModuleRecord.cpp create mode 100644 Source/JavaScriptCore/runtime/AbstractModuleRecord.h delete mode 100644 Source/JavaScriptCore/runtime/Arguments.cpp delete mode 100644 Source/JavaScriptCore/runtime/Arguments.h delete mode 100644 Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.cpp delete mode 100644 Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.h delete mode 100644 Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.cpp delete mode 100644 Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.h create mode 100644 Source/JavaScriptCore/runtime/ArgumentsMode.h create mode 100644 Source/JavaScriptCore/runtime/ArityCheckMode.h create mode 100644 Source/JavaScriptCore/runtime/ArrayBufferSharingMode.h create mode 100644 Source/JavaScriptCore/runtime/ArrayConventions.cpp create mode 100644 Source/JavaScriptCore/runtime/ArrayIteratorAdaptiveWatchpoint.cpp create mode 100644 Source/JavaScriptCore/runtime/ArrayIteratorAdaptiveWatchpoint.h delete mode 100644 Source/JavaScriptCore/runtime/ArrayIteratorConstructor.cpp delete mode 100644 Source/JavaScriptCore/runtime/ArrayIteratorConstructor.h create mode 100644 Source/JavaScriptCore/runtime/AsyncFunctionConstructor.cpp create mode 100644 Source/JavaScriptCore/runtime/AsyncFunctionConstructor.h create mode 100644 Source/JavaScriptCore/runtime/AsyncFunctionPrototype.cpp create mode 100644 Source/JavaScriptCore/runtime/AsyncFunctionPrototype.h create mode 100644 Source/JavaScriptCore/runtime/AtomicsObject.cpp create mode 100644 Source/JavaScriptCore/runtime/AtomicsObject.h create mode 100644 Source/JavaScriptCore/runtime/AuxiliaryBarrier.h create mode 100644 Source/JavaScriptCore/runtime/AuxiliaryBarrierInlines.h create mode 100644 Source/JavaScriptCore/runtime/BasicBlockLocation.cpp create mode 100644 Source/JavaScriptCore/runtime/BasicBlockLocation.h create mode 100644 Source/JavaScriptCore/runtime/BundlePath.h create mode 100644 Source/JavaScriptCore/runtime/CatchScope.cpp create mode 100644 Source/JavaScriptCore/runtime/CatchScope.h create mode 100644 Source/JavaScriptCore/runtime/ClonedArguments.cpp create mode 100644 Source/JavaScriptCore/runtime/ClonedArguments.h delete mode 100644 Source/JavaScriptCore/runtime/ConcurrentJITLock.h create mode 100644 Source/JavaScriptCore/runtime/ConcurrentJSLock.h create mode 100644 Source/JavaScriptCore/runtime/ConsoleClient.cpp create mode 100644 Source/JavaScriptCore/runtime/ConsoleClient.h create mode 100644 Source/JavaScriptCore/runtime/ConsoleObject.cpp create mode 100644 Source/JavaScriptCore/runtime/ConsoleObject.h create mode 100644 Source/JavaScriptCore/runtime/ConsoleTypes.h create mode 100644 Source/JavaScriptCore/runtime/ConstantMode.cpp create mode 100644 Source/JavaScriptCore/runtime/ConstructAbility.h create mode 100644 Source/JavaScriptCore/runtime/ControlFlowProfiler.cpp create mode 100644 Source/JavaScriptCore/runtime/ControlFlowProfiler.h create mode 100644 Source/JavaScriptCore/runtime/CustomGetterSetter.cpp create mode 100644 Source/JavaScriptCore/runtime/CustomGetterSetter.h create mode 100644 Source/JavaScriptCore/runtime/DefinePropertyAttributes.h create mode 100644 Source/JavaScriptCore/runtime/DirectArguments.cpp create mode 100644 Source/JavaScriptCore/runtime/DirectArguments.h create mode 100644 Source/JavaScriptCore/runtime/DirectArgumentsOffset.cpp create mode 100644 Source/JavaScriptCore/runtime/DirectArgumentsOffset.h create mode 100644 Source/JavaScriptCore/runtime/DirectEvalExecutable.cpp create mode 100644 Source/JavaScriptCore/runtime/DirectEvalExecutable.h create mode 100644 Source/JavaScriptCore/runtime/ECMAScriptSpecInternalFunctions.cpp create mode 100644 Source/JavaScriptCore/runtime/ECMAScriptSpecInternalFunctions.h create mode 100644 Source/JavaScriptCore/runtime/EnumerationMode.h create mode 100644 Source/JavaScriptCore/runtime/ErrorHandlingScope.cpp create mode 100644 Source/JavaScriptCore/runtime/ErrorHandlingScope.h create mode 100644 Source/JavaScriptCore/runtime/EvalExecutable.cpp create mode 100644 Source/JavaScriptCore/runtime/EvalExecutable.h create mode 100644 Source/JavaScriptCore/runtime/Exception.cpp create mode 100644 Source/JavaScriptCore/runtime/Exception.h create mode 100644 Source/JavaScriptCore/runtime/ExceptionEventLocation.cpp create mode 100644 Source/JavaScriptCore/runtime/ExceptionEventLocation.h create mode 100644 Source/JavaScriptCore/runtime/ExceptionFuzz.cpp create mode 100644 Source/JavaScriptCore/runtime/ExceptionFuzz.h create mode 100644 Source/JavaScriptCore/runtime/ExceptionScope.cpp create mode 100644 Source/JavaScriptCore/runtime/ExceptionScope.h delete mode 100644 Source/JavaScriptCore/runtime/Executable.cpp delete mode 100644 Source/JavaScriptCore/runtime/Executable.h create mode 100644 Source/JavaScriptCore/runtime/ExecutableBase.cpp create mode 100644 Source/JavaScriptCore/runtime/ExecutableBase.h create mode 100644 Source/JavaScriptCore/runtime/FunctionExecutable.cpp create mode 100644 Source/JavaScriptCore/runtime/FunctionExecutable.h create mode 100644 Source/JavaScriptCore/runtime/FunctionHasExecutedCache.cpp create mode 100644 Source/JavaScriptCore/runtime/FunctionHasExecutedCache.h create mode 100644 Source/JavaScriptCore/runtime/FunctionRareData.cpp create mode 100644 Source/JavaScriptCore/runtime/FunctionRareData.h delete mode 100644 Source/JavaScriptCore/runtime/GCActivityCallback.cpp delete mode 100644 Source/JavaScriptCore/runtime/GCActivityCallback.h create mode 100644 Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.cpp create mode 100644 Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.h create mode 100644 Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.cpp create mode 100644 Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.h create mode 100644 Source/JavaScriptCore/runtime/GeneratorPrototype.cpp create mode 100644 Source/JavaScriptCore/runtime/GeneratorPrototype.h create mode 100644 Source/JavaScriptCore/runtime/GenericArguments.h create mode 100644 Source/JavaScriptCore/runtime/GenericArgumentsInlines.h create mode 100644 Source/JavaScriptCore/runtime/GenericOffset.h create mode 100644 Source/JavaScriptCore/runtime/GetPutInfo.h create mode 100644 Source/JavaScriptCore/runtime/HasOwnPropertyCache.h create mode 100644 Source/JavaScriptCore/runtime/HashMapImpl.cpp create mode 100644 Source/JavaScriptCore/runtime/HashMapImpl.h create mode 100644 Source/JavaScriptCore/runtime/IdentifierInlines.h create mode 100644 Source/JavaScriptCore/runtime/IndirectEvalExecutable.cpp create mode 100644 Source/JavaScriptCore/runtime/IndirectEvalExecutable.h create mode 100644 Source/JavaScriptCore/runtime/InferredType.cpp create mode 100644 Source/JavaScriptCore/runtime/InferredType.h create mode 100644 Source/JavaScriptCore/runtime/InferredTypeTable.cpp create mode 100644 Source/JavaScriptCore/runtime/InferredTypeTable.h create mode 100644 Source/JavaScriptCore/runtime/InferredValue.cpp create mode 100644 Source/JavaScriptCore/runtime/InferredValue.h create mode 100644 Source/JavaScriptCore/runtime/InspectorInstrumentationObject.cpp create mode 100644 Source/JavaScriptCore/runtime/InspectorInstrumentationObject.h delete mode 100644 Source/JavaScriptCore/runtime/IntegralTypedArrayBase.h delete mode 100644 Source/JavaScriptCore/runtime/IntendedStructureChain.cpp delete mode 100644 Source/JavaScriptCore/runtime/IntendedStructureChain.h create mode 100644 Source/JavaScriptCore/runtime/IntlCollator.cpp create mode 100644 Source/JavaScriptCore/runtime/IntlCollator.h create mode 100644 Source/JavaScriptCore/runtime/IntlCollatorConstructor.cpp create mode 100644 Source/JavaScriptCore/runtime/IntlCollatorConstructor.h create mode 100644 Source/JavaScriptCore/runtime/IntlCollatorPrototype.cpp create mode 100644 Source/JavaScriptCore/runtime/IntlCollatorPrototype.h create mode 100644 Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp create mode 100644 Source/JavaScriptCore/runtime/IntlDateTimeFormat.h create mode 100644 Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp create mode 100644 Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.h create mode 100644 Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp create mode 100644 Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.h create mode 100644 Source/JavaScriptCore/runtime/IntlNumberFormat.cpp create mode 100644 Source/JavaScriptCore/runtime/IntlNumberFormat.h create mode 100644 Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.cpp create mode 100644 Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.h create mode 100644 Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp create mode 100644 Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.h create mode 100644 Source/JavaScriptCore/runtime/IntlObject.cpp create mode 100644 Source/JavaScriptCore/runtime/IntlObject.h create mode 100644 Source/JavaScriptCore/runtime/IntlObjectInlines.h create mode 100644 Source/JavaScriptCore/runtime/IterationKind.h create mode 100644 Source/JavaScriptCore/runtime/IterationStatus.h create mode 100644 Source/JavaScriptCore/runtime/IteratorOperations.cpp create mode 100644 Source/JavaScriptCore/runtime/IteratorOperations.h create mode 100644 Source/JavaScriptCore/runtime/IteratorPrototype.cpp create mode 100644 Source/JavaScriptCore/runtime/IteratorPrototype.h delete mode 100644 Source/JavaScriptCore/runtime/JSActivation.cpp delete mode 100644 Source/JavaScriptCore/runtime/JSActivation.h delete mode 100644 Source/JavaScriptCore/runtime/JSArgumentsIterator.cpp delete mode 100644 Source/JavaScriptCore/runtime/JSArgumentsIterator.h create mode 100644 Source/JavaScriptCore/runtime/JSArrayInlines.h delete mode 100644 Source/JavaScriptCore/runtime/JSArrayIterator.cpp delete mode 100644 Source/JavaScriptCore/runtime/JSArrayIterator.h create mode 100644 Source/JavaScriptCore/runtime/JSAsyncFunction.cpp create mode 100644 Source/JavaScriptCore/runtime/JSAsyncFunction.h create mode 100644 Source/JavaScriptCore/runtime/JSCInlines.h create mode 100644 Source/JavaScriptCore/runtime/JSCallee.cpp create mode 100644 Source/JavaScriptCore/runtime/JSCallee.h create mode 100644 Source/JavaScriptCore/runtime/JSCustomGetterSetterFunction.cpp create mode 100644 Source/JavaScriptCore/runtime/JSCustomGetterSetterFunction.h create mode 100644 Source/JavaScriptCore/runtime/JSDestructibleObjectSubspace.cpp create mode 100644 Source/JavaScriptCore/runtime/JSDestructibleObjectSubspace.h create mode 100644 Source/JavaScriptCore/runtime/JSEnvironmentRecord.cpp create mode 100644 Source/JavaScriptCore/runtime/JSEnvironmentRecord.h create mode 100644 Source/JavaScriptCore/runtime/JSFixedArray.cpp create mode 100644 Source/JavaScriptCore/runtime/JSFixedArray.h create mode 100644 Source/JavaScriptCore/runtime/JSGeneratorFunction.cpp create mode 100644 Source/JavaScriptCore/runtime/JSGeneratorFunction.h create mode 100644 Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeFunctions.h create mode 100644 Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.cpp create mode 100644 Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.h create mode 100644 Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.cpp create mode 100644 Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.h create mode 100644 Source/JavaScriptCore/runtime/JSGlobalObjectInlines.h create mode 100644 Source/JavaScriptCore/runtime/JSInternalPromise.cpp create mode 100644 Source/JavaScriptCore/runtime/JSInternalPromise.h create mode 100644 Source/JavaScriptCore/runtime/JSInternalPromiseConstructor.cpp create mode 100644 Source/JavaScriptCore/runtime/JSInternalPromiseConstructor.h create mode 100644 Source/JavaScriptCore/runtime/JSInternalPromiseDeferred.cpp create mode 100644 Source/JavaScriptCore/runtime/JSInternalPromiseDeferred.h create mode 100644 Source/JavaScriptCore/runtime/JSInternalPromisePrototype.cpp create mode 100644 Source/JavaScriptCore/runtime/JSInternalPromisePrototype.h create mode 100644 Source/JavaScriptCore/runtime/JSJob.cpp create mode 100644 Source/JavaScriptCore/runtime/JSJob.h create mode 100644 Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp create mode 100644 Source/JavaScriptCore/runtime/JSLexicalEnvironment.h create mode 100644 Source/JavaScriptCore/runtime/JSModuleEnvironment.cpp create mode 100644 Source/JavaScriptCore/runtime/JSModuleEnvironment.h create mode 100644 Source/JavaScriptCore/runtime/JSModuleLoader.cpp create mode 100644 Source/JavaScriptCore/runtime/JSModuleLoader.h create mode 100644 Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp create mode 100644 Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h create mode 100644 Source/JavaScriptCore/runtime/JSModuleRecord.cpp create mode 100644 Source/JavaScriptCore/runtime/JSModuleRecord.h delete mode 100644 Source/JavaScriptCore/runtime/JSNameScope.cpp delete mode 100644 Source/JavaScriptCore/runtime/JSNameScope.h create mode 100644 Source/JavaScriptCore/runtime/JSNativeStdFunction.cpp create mode 100644 Source/JavaScriptCore/runtime/JSNativeStdFunction.h delete mode 100644 Source/JavaScriptCore/runtime/JSNotAnObject.cpp delete mode 100644 Source/JavaScriptCore/runtime/JSNotAnObject.h create mode 100644 Source/JavaScriptCore/runtime/JSObjectInlines.h delete mode 100644 Source/JavaScriptCore/runtime/JSPromiseFunctions.cpp delete mode 100644 Source/JavaScriptCore/runtime/JSPromiseFunctions.h delete mode 100644 Source/JavaScriptCore/runtime/JSPromiseReaction.cpp delete mode 100644 Source/JavaScriptCore/runtime/JSPromiseReaction.h create mode 100644 Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp create mode 100644 Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h create mode 100644 Source/JavaScriptCore/runtime/JSScriptFetcher.cpp create mode 100644 Source/JavaScriptCore/runtime/JSScriptFetcher.h create mode 100644 Source/JavaScriptCore/runtime/JSSegmentedVariableObjectSubspace.cpp create mode 100644 Source/JavaScriptCore/runtime/JSSegmentedVariableObjectSubspace.h create mode 100644 Source/JavaScriptCore/runtime/JSSourceCode.cpp create mode 100644 Source/JavaScriptCore/runtime/JSSourceCode.h create mode 100644 Source/JavaScriptCore/runtime/JSStringInlines.h create mode 100644 Source/JavaScriptCore/runtime/JSStringIterator.cpp create mode 100644 Source/JavaScriptCore/runtime/JSStringIterator.h create mode 100644 Source/JavaScriptCore/runtime/JSStringSubspace.cpp create mode 100644 Source/JavaScriptCore/runtime/JSStringSubspace.h create mode 100644 Source/JavaScriptCore/runtime/JSTemplateRegistryKey.cpp create mode 100644 Source/JavaScriptCore/runtime/JSTemplateRegistryKey.h create mode 100644 Source/JavaScriptCore/runtime/JSTypedArrayViewConstructor.cpp create mode 100644 Source/JavaScriptCore/runtime/JSTypedArrayViewConstructor.h create mode 100644 Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.cpp create mode 100644 Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.h delete mode 100644 Source/JavaScriptCore/runtime/JSVariableObject.cpp delete mode 100644 Source/JavaScriptCore/runtime/JSVariableObject.h create mode 100644 Source/JavaScriptCore/runtime/JSWeakSet.cpp create mode 100644 Source/JavaScriptCore/runtime/JSWeakSet.h create mode 100644 Source/JavaScriptCore/runtime/LazyClassStructure.cpp create mode 100644 Source/JavaScriptCore/runtime/LazyClassStructure.h create mode 100644 Source/JavaScriptCore/runtime/LazyClassStructureInlines.h create mode 100644 Source/JavaScriptCore/runtime/LazyProperty.h create mode 100644 Source/JavaScriptCore/runtime/LazyPropertyInlines.h create mode 100644 Source/JavaScriptCore/runtime/MapBase.cpp create mode 100644 Source/JavaScriptCore/runtime/MapBase.h delete mode 100644 Source/JavaScriptCore/runtime/MapData.cpp delete mode 100644 Source/JavaScriptCore/runtime/MapData.h delete mode 100644 Source/JavaScriptCore/runtime/MapIteratorConstructor.cpp delete mode 100644 Source/JavaScriptCore/runtime/MapIteratorConstructor.h create mode 100644 Source/JavaScriptCore/runtime/MatchResult.cpp create mode 100644 Source/JavaScriptCore/runtime/MathCommon.cpp create mode 100644 Source/JavaScriptCore/runtime/MathCommon.h create mode 100644 Source/JavaScriptCore/runtime/MemoryStatistics.cpp create mode 100644 Source/JavaScriptCore/runtime/ModuleLoaderPrototype.cpp create mode 100644 Source/JavaScriptCore/runtime/ModuleLoaderPrototype.h create mode 100644 Source/JavaScriptCore/runtime/ModuleProgramExecutable.cpp create mode 100644 Source/JavaScriptCore/runtime/ModuleProgramExecutable.h delete mode 100644 Source/JavaScriptCore/runtime/NameConstructor.cpp delete mode 100644 Source/JavaScriptCore/runtime/NameConstructor.h delete mode 100644 Source/JavaScriptCore/runtime/NameInstance.cpp delete mode 100644 Source/JavaScriptCore/runtime/NameInstance.h delete mode 100644 Source/JavaScriptCore/runtime/NamePrototype.cpp delete mode 100644 Source/JavaScriptCore/runtime/NamePrototype.h create mode 100644 Source/JavaScriptCore/runtime/NativeExecutable.cpp create mode 100644 Source/JavaScriptCore/runtime/NativeExecutable.h create mode 100644 Source/JavaScriptCore/runtime/NativeStdFunctionCell.cpp create mode 100644 Source/JavaScriptCore/runtime/NativeStdFunctionCell.h create mode 100644 Source/JavaScriptCore/runtime/NullGetterFunction.cpp create mode 100644 Source/JavaScriptCore/runtime/NullGetterFunction.h create mode 100644 Source/JavaScriptCore/runtime/NullSetterFunction.cpp create mode 100644 Source/JavaScriptCore/runtime/NullSetterFunction.h create mode 100644 Source/JavaScriptCore/runtime/ParseInt.h create mode 100644 Source/JavaScriptCore/runtime/ProgramExecutable.cpp create mode 100644 Source/JavaScriptCore/runtime/ProgramExecutable.h delete mode 100644 Source/JavaScriptCore/runtime/PropertyNameArray.cpp create mode 100644 Source/JavaScriptCore/runtime/PrototypeMapInlines.h create mode 100644 Source/JavaScriptCore/runtime/ProxyConstructor.cpp create mode 100644 Source/JavaScriptCore/runtime/ProxyConstructor.h create mode 100644 Source/JavaScriptCore/runtime/ProxyObject.cpp create mode 100644 Source/JavaScriptCore/runtime/ProxyObject.h create mode 100644 Source/JavaScriptCore/runtime/ProxyRevoke.cpp create mode 100644 Source/JavaScriptCore/runtime/ProxyRevoke.h create mode 100644 Source/JavaScriptCore/runtime/PureNaN.h create mode 100644 Source/JavaScriptCore/runtime/ReflectObject.cpp create mode 100644 Source/JavaScriptCore/runtime/ReflectObject.h create mode 100644 Source/JavaScriptCore/runtime/RegExpInlines.h create mode 100644 Source/JavaScriptCore/runtime/RegExpObjectInlines.h delete mode 100644 Source/JavaScriptCore/runtime/Reject.h create mode 100644 Source/JavaScriptCore/runtime/RuntimeFlags.h create mode 100644 Source/JavaScriptCore/runtime/RuntimeType.cpp create mode 100644 Source/JavaScriptCore/runtime/RuntimeType.h create mode 100644 Source/JavaScriptCore/runtime/SamplingProfiler.cpp create mode 100644 Source/JavaScriptCore/runtime/SamplingProfiler.h create mode 100644 Source/JavaScriptCore/runtime/ScopeOffset.cpp create mode 100644 Source/JavaScriptCore/runtime/ScopeOffset.h create mode 100644 Source/JavaScriptCore/runtime/ScopedArguments.cpp create mode 100644 Source/JavaScriptCore/runtime/ScopedArguments.h create mode 100644 Source/JavaScriptCore/runtime/ScopedArgumentsTable.cpp create mode 100644 Source/JavaScriptCore/runtime/ScopedArgumentsTable.h create mode 100644 Source/JavaScriptCore/runtime/ScriptExecutable.cpp create mode 100644 Source/JavaScriptCore/runtime/ScriptExecutable.h create mode 100644 Source/JavaScriptCore/runtime/ScriptFetcher.h delete mode 100644 Source/JavaScriptCore/runtime/SetIteratorConstructor.cpp delete mode 100644 Source/JavaScriptCore/runtime/SetIteratorConstructor.h create mode 100644 Source/JavaScriptCore/runtime/SlowPathReturnType.h create mode 100644 Source/JavaScriptCore/runtime/SourceOrigin.h create mode 100644 Source/JavaScriptCore/runtime/StackFrame.cpp create mode 100644 Source/JavaScriptCore/runtime/StackFrame.h create mode 100644 Source/JavaScriptCore/runtime/StringIteratorPrototype.cpp create mode 100644 Source/JavaScriptCore/runtime/StringIteratorPrototype.h create mode 100644 Source/JavaScriptCore/runtime/StructureIDBlob.h create mode 100644 Source/JavaScriptCore/runtime/StructureIDTable.cpp create mode 100644 Source/JavaScriptCore/runtime/StructureIDTable.h create mode 100644 Source/JavaScriptCore/runtime/Symbol.cpp create mode 100644 Source/JavaScriptCore/runtime/Symbol.h create mode 100644 Source/JavaScriptCore/runtime/SymbolConstructor.cpp create mode 100644 Source/JavaScriptCore/runtime/SymbolConstructor.h create mode 100644 Source/JavaScriptCore/runtime/SymbolObject.cpp create mode 100644 Source/JavaScriptCore/runtime/SymbolObject.h create mode 100644 Source/JavaScriptCore/runtime/SymbolPrototype.cpp create mode 100644 Source/JavaScriptCore/runtime/SymbolPrototype.h create mode 100644 Source/JavaScriptCore/runtime/TemplateRegistry.cpp create mode 100644 Source/JavaScriptCore/runtime/TemplateRegistry.h create mode 100644 Source/JavaScriptCore/runtime/TemplateRegistryKey.cpp create mode 100644 Source/JavaScriptCore/runtime/TemplateRegistryKey.h create mode 100644 Source/JavaScriptCore/runtime/TemplateRegistryKeyTable.cpp create mode 100644 Source/JavaScriptCore/runtime/TemplateRegistryKeyTable.h create mode 100644 Source/JavaScriptCore/runtime/ThrowScope.cpp create mode 100644 Source/JavaScriptCore/runtime/ThrowScope.h delete mode 100644 Source/JavaScriptCore/runtime/Tracing.h create mode 100644 Source/JavaScriptCore/runtime/TypeError.h create mode 100644 Source/JavaScriptCore/runtime/TypeLocationCache.cpp create mode 100644 Source/JavaScriptCore/runtime/TypeLocationCache.h create mode 100644 Source/JavaScriptCore/runtime/TypeProfiler.cpp create mode 100644 Source/JavaScriptCore/runtime/TypeProfiler.h create mode 100644 Source/JavaScriptCore/runtime/TypeProfilerLog.cpp create mode 100644 Source/JavaScriptCore/runtime/TypeProfilerLog.h create mode 100644 Source/JavaScriptCore/runtime/TypeSet.cpp create mode 100644 Source/JavaScriptCore/runtime/TypeSet.h delete mode 100644 Source/JavaScriptCore/runtime/TypedArrayBase.h create mode 100644 Source/JavaScriptCore/runtime/TypeofType.cpp create mode 100644 Source/JavaScriptCore/runtime/TypeofType.h create mode 100644 Source/JavaScriptCore/runtime/VMInlines.h create mode 100644 Source/JavaScriptCore/runtime/VarOffset.cpp create mode 100644 Source/JavaScriptCore/runtime/VarOffset.h delete mode 100644 Source/JavaScriptCore/runtime/WatchdogNone.cpp create mode 100644 Source/JavaScriptCore/runtime/WeakGCMapInlines.h delete mode 100644 Source/JavaScriptCore/runtime/WeakRandom.h create mode 100644 Source/JavaScriptCore/runtime/WeakSetConstructor.cpp create mode 100644 Source/JavaScriptCore/runtime/WeakSetConstructor.h create mode 100644 Source/JavaScriptCore/runtime/WeakSetPrototype.cpp create mode 100644 Source/JavaScriptCore/runtime/WeakSetPrototype.h create mode 100644 Source/JavaScriptCore/runtime/WriteBarrierInlines.h (limited to 'Source/JavaScriptCore/runtime') diff --git a/Source/JavaScriptCore/runtime/AbstractModuleRecord.cpp b/Source/JavaScriptCore/runtime/AbstractModuleRecord.cpp new file mode 100644 index 000000000..f8854e2c2 --- /dev/null +++ b/Source/JavaScriptCore/runtime/AbstractModuleRecord.cpp @@ -0,0 +1,769 @@ +/* + * Copyright (C) 2015-2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AbstractModuleRecord.h" + +#include "Error.h" +#include "Interpreter.h" +#include "JSCInlines.h" +#include "JSMap.h" +#include "JSModuleEnvironment.h" +#include "JSModuleNamespaceObject.h" +#include "UnlinkedModuleProgramCodeBlock.h" + +namespace JSC { + +const ClassInfo AbstractModuleRecord::s_info = { "AbstractModuleRecord", &Base::s_info, 0, CREATE_METHOD_TABLE(AbstractModuleRecord) }; + +AbstractModuleRecord::AbstractModuleRecord(VM& vm, Structure* structure, const Identifier& moduleKey) + : Base(vm, structure) + , m_moduleKey(moduleKey) +{ +} + +void AbstractModuleRecord::destroy(JSCell* cell) +{ + AbstractModuleRecord* thisObject = static_cast(cell); + thisObject->AbstractModuleRecord::~AbstractModuleRecord(); +} + +void AbstractModuleRecord::finishCreation(ExecState* exec, VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(vm, info())); + putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("registryEntry")), jsUndefined()); + putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("evaluated")), jsBoolean(false)); + + auto scope = DECLARE_THROW_SCOPE(vm); + JSMap* map = JSMap::create(exec, vm, globalObject()->mapStructure()); + RELEASE_ASSERT(!scope.exception()); + m_dependenciesMap.set(vm, this, map); + putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("dependenciesMap")), m_dependenciesMap.get()); +} + +void AbstractModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + AbstractModuleRecord* thisObject = jsCast(cell); + Base::visitChildren(thisObject, visitor); + visitor.append(thisObject->m_moduleEnvironment); + visitor.append(thisObject->m_moduleNamespaceObject); + visitor.append(thisObject->m_dependenciesMap); +} + +void AbstractModuleRecord::appendRequestedModule(const Identifier& moduleName) +{ + m_requestedModules.add(moduleName.impl()); +} + +void AbstractModuleRecord::addStarExportEntry(const Identifier& moduleName) +{ + m_starExportEntries.add(moduleName.impl()); +} + +void AbstractModuleRecord::addImportEntry(const ImportEntry& entry) +{ + bool isNewEntry = m_importEntries.add(entry.localName.impl(), entry).isNewEntry; + ASSERT_UNUSED(isNewEntry, isNewEntry); // This is guaranteed by the parser. +} + +void AbstractModuleRecord::addExportEntry(const ExportEntry& entry) +{ + bool isNewEntry = m_exportEntries.add(entry.exportName.impl(), entry).isNewEntry; + ASSERT_UNUSED(isNewEntry, isNewEntry); // This is guaranteed by the parser. +} + +auto AbstractModuleRecord::tryGetImportEntry(UniquedStringImpl* localName) -> std::optional +{ + const auto iterator = m_importEntries.find(localName); + if (iterator == m_importEntries.end()) + return std::nullopt; + return std::optional(iterator->value); +} + +auto AbstractModuleRecord::tryGetExportEntry(UniquedStringImpl* exportName) -> std::optional +{ + const auto iterator = m_exportEntries.find(exportName); + if (iterator == m_exportEntries.end()) + return std::nullopt; + return std::optional(iterator->value); +} + +auto AbstractModuleRecord::ExportEntry::createLocal(const Identifier& exportName, const Identifier& localName) -> ExportEntry +{ + return ExportEntry { Type::Local, exportName, Identifier(), Identifier(), localName }; +} + +auto AbstractModuleRecord::ExportEntry::createIndirect(const Identifier& exportName, const Identifier& importName, const Identifier& moduleName) -> ExportEntry +{ + return ExportEntry { Type::Indirect, exportName, moduleName, importName, Identifier() }; +} + +auto AbstractModuleRecord::Resolution::notFound() -> Resolution +{ + return Resolution { Type::NotFound, nullptr, Identifier() }; +} + +auto AbstractModuleRecord::Resolution::error() -> Resolution +{ + return Resolution { Type::Error, nullptr, Identifier() }; +} + +auto AbstractModuleRecord::Resolution::ambiguous() -> Resolution +{ + return Resolution { Type::Ambiguous, nullptr, Identifier() }; +} + +static JSValue identifierToJSValue(ExecState* exec, const Identifier& identifier) +{ + if (identifier.isSymbol()) + return Symbol::create(exec->vm(), static_cast(*identifier.impl())); + return jsString(&exec->vm(), identifier.impl()); +} + +AbstractModuleRecord* AbstractModuleRecord::hostResolveImportedModule(ExecState* exec, const Identifier& moduleName) +{ + JSValue moduleNameValue = identifierToJSValue(exec, moduleName); + JSValue pair = m_dependenciesMap->JSMap::get(exec, moduleNameValue); + return jsCast(pair.get(exec, Identifier::fromString(exec, "value"))); +} + +auto AbstractModuleRecord::resolveImport(ExecState* exec, const Identifier& localName) -> Resolution +{ + std::optional optionalImportEntry = tryGetImportEntry(localName.impl()); + if (!optionalImportEntry) + return Resolution::notFound(); + + const ImportEntry& importEntry = *optionalImportEntry; + if (importEntry.isNamespace(exec->vm())) + return Resolution::notFound(); + + AbstractModuleRecord* importedModule = hostResolveImportedModule(exec, importEntry.moduleRequest); + return importedModule->resolveExport(exec, importEntry.importName); +} + +struct AbstractModuleRecord::ResolveQuery { + struct Hash { + static unsigned hash(const ResolveQuery&); + static bool equal(const ResolveQuery&, const ResolveQuery&); + static const bool safeToCompareToEmptyOrDeleted = true; + }; + + ResolveQuery(AbstractModuleRecord* moduleRecord, UniquedStringImpl* exportName) + : moduleRecord(moduleRecord) + , exportName(exportName) + { + } + + ResolveQuery(AbstractModuleRecord* moduleRecord, const Identifier& exportName) + : ResolveQuery(moduleRecord, exportName.impl()) + { + } + + enum EmptyValueTag { EmptyValue }; + ResolveQuery(EmptyValueTag) + { + } + + enum DeletedValueTag { DeletedValue }; + ResolveQuery(DeletedValueTag) + : moduleRecord(nullptr) + , exportName(WTF::HashTableDeletedValue) + { + } + + bool isEmptyValue() const + { + return !exportName; + } + + bool isDeletedValue() const + { + return exportName.isHashTableDeletedValue(); + } + + // The module record is not marked from the GC. But these records are reachable from the JSGlobalObject. + // So we don't care the reachability to this record. + AbstractModuleRecord* moduleRecord; + RefPtr exportName; +}; + +inline unsigned AbstractModuleRecord::ResolveQuery::Hash::hash(const ResolveQuery& query) +{ + return WTF::PtrHash::hash(query.moduleRecord) + IdentifierRepHash::hash(query.exportName); +} + +inline bool AbstractModuleRecord::ResolveQuery::Hash::equal(const ResolveQuery& lhs, const ResolveQuery& rhs) +{ + return lhs.moduleRecord == rhs.moduleRecord && lhs.exportName == rhs.exportName; +} + +auto AbstractModuleRecord::tryGetCachedResolution(UniquedStringImpl* exportName) -> std::optional +{ + const auto iterator = m_resolutionCache.find(exportName); + if (iterator == m_resolutionCache.end()) + return std::nullopt; + return std::optional(iterator->value); +} + +void AbstractModuleRecord::cacheResolution(UniquedStringImpl* exportName, const Resolution& resolution) +{ + m_resolutionCache.add(exportName, resolution); +} + +auto AbstractModuleRecord::resolveExportImpl(ExecState* exec, const ResolveQuery& root) -> Resolution +{ + // http://www.ecma-international.org/ecma-262/6.0/#sec-resolveexport + + // How to avoid C++ recursion in this function: + // This function avoids C++ recursion of the naive ResolveExport implementation. + // Flatten the recursion to the loop with the task queue and frames. + // + // 1. pendingTasks + // We enqueue the recursive resolveExport call to this queue to avoid recursive calls in C++. + // The task has 3 types. (1) Query, (2) IndirectFallback and (3) GatherStars. + // (1) Query + // Querying the resolution to the current module. + // (2) IndirectFallback + // Examine the result of the indirect export resolution. Only when the indirect export resolution fails, + // we look into the star exports. (step 5-a-vi). + // (3) GatherStars + // Examine the result of the star export resolutions. + // + // 2. frames + // When the spec calls the resolveExport recursively, instead we append the frame + // (that holds the result resolution) to the frames and enqueue the task to the pendingTasks. + // The entry in the frames means the *local* resolution result of the specific recursive resolveExport. + // + // We should maintain the local resolution result instead of holding the global resolution result only. + // For example, + // + // star + // (1) ---> (2) "Resolve" + // | + // | + // +-> (3) "NotFound" + // | + // | star + // +-> (4) ---> (5) "Resolve" [here] + // | + // | + // +-> (6) "Error" + // + // Consider the above graph. The numbers represents the modules. Now we are [here]. + // If we only hold the global resolution result during the resolveExport operation, [here], + // we decide the entire result of resolveExport is "Ambiguous", because there are multiple + // "Resolve" (in module (2) and (5)). However, this should become "Error" because (6) will + // propagate "Error" state to the (4), (4) will become "Error" and then, (1) will become + // "Error". We should aggregate the results at the star exports point ((4) and (1)). + // + // Usually, both "Error" and "Ambiguous" states will throw the syntax error. So except for the content of the + // error message, there are no difference. (And if we fix the (6) that raises "Error", next, it will produce + // the "Ambiguous" error due to (5). Anyway, user need to fix the both. So which error should be raised at first + // doesn't matter so much. + // + // However, this may become the problem under the module namespace creation. + // http://www.ecma-international.org/ecma-262/6.0/#sec-getmodulenamespace + // section 15.2.1.18, step 3-d-ii + // Here, we distinguish "Ambiguous" and "Error". When "Error" state is produced, we need to throw the propagated error. + // But if "Ambiguous" state comes, we just ignore the result. + // To follow the requirement strictly, in this implementation, we keep the local resolution result to produce the + // correct result under the above complex cases. + + // Caching strategy: + // The resolveExport operation is frequently called. So caching results is important. + // We observe the following aspects and based on them construct the caching strategy. + // Here, we attempt to cache the resolution by constructing the map in module records. + // That means Module -> ExportName -> Maybe. + // Technically, all the AbstractModuleRecords have the Map for caching. + // + // The important observations are that, + // + // - *cacheable* means that traversing to this node from a path will produce the same results as starting from this node. + // + // Here, we define the resovling route. We represent [?] as the module that has the local binding. + // And (?) as the module without the local binding. + // + // @ -> (A) -> (B) -> [C] + // + // We list the resolving route for each node. + // + // (A): (A) -> (B) -> [C] + // (B): (B) -> [C] + // [C]: [C] + // + // In this case, if we start the tracing from (B), the resolving route becomes (B) -> [C]. + // So this is the same. At that time, we can say (B) is cacheable in the first tracing. + // + // - The cache ability of a node depends on the resolving route from this node. + // + // 1. The starting point is always cacheable. + // + // 2. A module that has resolved a local binding is always cacheable. + // + // @ -> (A) -> [B] + // + // In the above case, we can see the [B] as cacheable. + // This is because when starting from [B] node, we immediately resolve with the local binding. + // So the resolving route from [B] does not depend on the starting point. + // + // 3. If we don't follow any star links during the resolution, we can see all the traced nodes are cacheable. + // + // If there are non star links, it means that there is *no branch* in the module dependency graph. + // This *no branch* feature makes all the modules cachable. + // + // I.e, if we traverse one star link (even if we successfully resolve that star link), + // we must still traverse all other star links. I would also explain we don't run into + // this when resolving a local/indirect link. When resolving a local/indirect link, + // we won't traverse any star links. + // And since the module can hold only one local/indirect link for the specific export name (if there + // are multiple local/indirect links that has the same export name, it should be syntax error in the + // parsing phase.), there is no multiple outgoing links from a module. + // + // @ -> (A) --> (B) -> [C] -> (D) -> (E) -+ + // ^ | + // | | + // +------------------------+ + // + // When starting from @, [C] will be found as the module resolving the given binding. + // In this case, (B) can cache this resolution. Since the resolving route is the same to the one when + // starting from (B). After caching the above result, we attempt to resolve the same binding from (D). + // + // @ + // | + // v + // @ -> (A) --> (B) -> [C] -> (D) -> (E) -+ + // ^ | + // | | + // +------------------------+ + // + // In this case, we can use the (B)'s cached result. And (E) can be cached. + // + // (E): The resolving route is now (E) -> (B) -> [C]. That is the same when starting from (E). + // + // No branching makes that the problematic *once-visited* node cannot be seen. + // The *once-visited* node makes the resolving route changed since when we see the *once-visited* node, + // we stop tracing this. + // + // If there is no star links and if we look *once-visited* node under no branching graph, *once-visited* + // node cannot resolve the requested binding. If the *once-visited* node can resolve the binding, we + // should have already finished the resolution before reaching this *once-visited* node. + // + // 4. Once we follow star links, we should not retrieve the result from the cache and should not cache. + // + // Star links are only the way to introduce branch. + // Once we follow the star links during the resolution, we cannot cache naively. + // This is because the cacheability depends on the resolving route. And branching produces the problematic *once-visited* + // nodes. Since we don't follow the *once-visited* node, the resolving route from the node becomes different from + // the resolving route when starting from this node. + // + // The following example explains when we should not retrieve the cache and cache the result. + // + // +----> (D) ------+ + // | | + // | v + // (A) *----+----> (B) ---> [C] + // ^ + // | + // @ + // + // When starting from (B), we find [C]. In this resolving route, we don't find any star link. + // And by definition, (B) and [C] are cachable. (B) is the starting point. And [C] has the local binding. + // + // +----> (D) ------+ + // | | + // | v + // @-> (A) *----+----> (B) ---> [C] + // + // But when starting from (A), we should not get the value from the cache. Because, + // + // 1. When looking (D), we reach [C] and make both resolved. + // 2. When looking (B), if we retrieved the last cache from (B), (B) becomes resolved. + // 3. But actually, (B) is not-found in this trial because (C) is already *once-visited*. + // 4. If we accidentally make (B) resolved, (A) becomes ambiguous. But the correct answer is resolved. + // + // Why is this problem caused? This is because the *once-visited* node makes the result not-found. + // In the second trial, (B) -> [C] result is changed from resolved to not-found. + // + // When does this become a problem? If the status of the *once-visited* node group is resolved, + // changing the result to not-found makes the result changed. + // + // This problem does not happen when we don't see any star link yet. Now, consider the minimum case. + // + // @-> (A) -> [ some graph ] + // ^ | + // | | + // +------------+ + // + // In (A), we don't see any star link yet. So we can say that all the visited nodes does not have any local + // resolution. Because if they had a local/indirect resolution, we should have already finished the tracing. + // + // And even if the some graph will see the *once-visited* node (in this case, (A)), that does not affect the + // result of the resolution. Because even if we follow the link to (A) or not follow the link to (A), the status + // of the link is always not-found since (A) does not have any local resolution. + // In the above case, we can use the result of the [some graph]. + // + // 5. Once we see star links, even if we have not yet traversed that star link path, we should disable caching. + // + // Here is the reason why: + // + // +-------------+ + // | | + // v | + // (A) -> (B) -> (C) *-> [E] + // * ^ + // | | + // v @ + // [D] + // + // In the above case, (C) will be resolved with [D]. + // (C) will see (A) and (A) gives up in (A) -> (B) -> (C) route. So, (A) will fallback to [D]. + // + // +-------------+ + // | | + // v | + // @-> (A) -> (B) -> (C) *-> [E] + // * + // | + // v + // [D] + // + // But in this case, (A) will be resolved with [E] (not [D]). + // (C) will attempt to follow the link to (A), but it fails. + // So (C) will fallback to the star link and found [E]. In this senario, + // (C) is now resolved with [E]'s result. + // + // The cause of this problem is also the same to 4. + // In the latter case, when looking (C), we cannot use the cached result in (C). + // Because the cached result of (C) depends on the *once-visited* node (A) and + // (A) has the fallback system with the star link. + // In the latter trial, we now assume that (A)'s status is not-found. + // But, actually, in the former trial, (A)'s status becomes resolved due to the fallback to the [D]. + // + // To summarize the observations. + // + // 1. The starting point is always cacheable. + // 2. A module that has resolved a local binding is always cacheable. + // 3. If we don't follow any star links during the resolution, we can see all the traced nodes are cacheable. + // 4. Once we follow star links, we should not retrieve the result from the cache and should not cache the result. + // 5. Once we see star links, even if we have not yet traversed that star link path, we should disable caching. + + typedef WTF::HashSet> ResolveSet; + enum class Type { Query, IndirectFallback, GatherStars }; + struct Task { + ResolveQuery query; + Type type; + }; + + Vector pendingTasks; + ResolveSet resolveSet; + HashSet starSet; + + Vector frames; + + bool foundStarLinks = false; + + frames.append(Resolution::notFound()); + + // Call when the query is not resolved in the current module. + // It will enqueue the star resolution requests. Return "false" if the error occurs. + auto resolveNonLocal = [&](const ResolveQuery& query) -> bool { + // http://www.ecma-international.org/ecma-262/6.0/#sec-resolveexport + // section 15.2.1.16.3, step 6 + // If the "default" name is not resolved in the current module, we need to throw an error and stop resolution immediately, + // Rationale to this error: A default export cannot be provided by an export *. + if (query.exportName == exec->propertyNames().defaultKeyword.impl()) + return false; + + // step 7, If exportStarSet contains module, then return null. + if (!starSet.add(query.moduleRecord).isNewEntry) + return true; + + // Enqueue the task to gather the results of the stars. + // And append the new Resolution frame to gather the local result of the stars. + pendingTasks.append(Task { query, Type::GatherStars }); + foundStarLinks = true; + frames.append(Resolution::notFound()); + + + // Enqueue the tasks in reverse order. + for (auto iterator = query.moduleRecord->starExportEntries().rbegin(), end = query.moduleRecord->starExportEntries().rend(); iterator != end; ++iterator) { + const RefPtr& starModuleName = *iterator; + AbstractModuleRecord* importedModuleRecord = query.moduleRecord->hostResolveImportedModule(exec, Identifier::fromUid(exec, starModuleName.get())); + pendingTasks.append(Task { ResolveQuery(importedModuleRecord, query.exportName.get()), Type::Query }); + } + return true; + }; + + // Return the current resolution value of the top frame. + auto currentTop = [&] () -> Resolution& { + ASSERT(!frames.isEmpty()); + return frames.last(); + }; + + // Merge the given resolution to the current resolution value of the top frame. + // If there is ambiguity, return "false". When the "false" is returned, we should make the result "ambiguous". + auto mergeToCurrentTop = [&] (const Resolution& resolution) -> bool { + if (resolution.type == Resolution::Type::NotFound) + return true; + + if (currentTop().type == Resolution::Type::NotFound) { + currentTop() = resolution; + return true; + } + + if (currentTop().moduleRecord != resolution.moduleRecord || currentTop().localName != resolution.localName) + return false; + + return true; + }; + + auto cacheResolutionForQuery = [] (const ResolveQuery& query, const Resolution& resolution) { + ASSERT(resolution.type == Resolution::Type::Resolved); + query.moduleRecord->cacheResolution(query.exportName.get(), resolution); + }; + + pendingTasks.append(Task { root, Type::Query }); + while (!pendingTasks.isEmpty()) { + const Task task = pendingTasks.takeLast(); + const ResolveQuery& query = task.query; + + switch (task.type) { + case Type::Query: { + AbstractModuleRecord* moduleRecord = query.moduleRecord; + + if (!resolveSet.add(task.query).isNewEntry) + continue; + + // 5. Once we see star links, even if we have not yet traversed that star link path, we should disable caching. + if (!moduleRecord->starExportEntries().isEmpty()) + foundStarLinks = true; + + // 4. Once we follow star links, we should not retrieve the result from the cache and should not cache the result. + if (!foundStarLinks) { + if (std::optional cachedResolution = moduleRecord->tryGetCachedResolution(query.exportName.get())) { + if (!mergeToCurrentTop(*cachedResolution)) + return Resolution::ambiguous(); + continue; + } + } + + const std::optional optionalExportEntry = moduleRecord->tryGetExportEntry(query.exportName.get()); + if (!optionalExportEntry) { + // If there is no matched exported binding in the current module, + // we need to look into the stars. + if (!resolveNonLocal(task.query)) + return Resolution::error(); + continue; + } + + const ExportEntry& exportEntry = *optionalExportEntry; + switch (exportEntry.type) { + case ExportEntry::Type::Local: { + ASSERT(!exportEntry.localName.isNull()); + Resolution resolution { Resolution::Type::Resolved, moduleRecord, exportEntry.localName }; + // 2. A module that has resolved a local binding is always cacheable. + cacheResolutionForQuery(query, resolution); + if (!mergeToCurrentTop(resolution)) + return Resolution::ambiguous(); + continue; + } + + case ExportEntry::Type::Indirect: { + AbstractModuleRecord* importedModuleRecord = moduleRecord->hostResolveImportedModule(exec, exportEntry.moduleName); + + // When the imported module does not produce any resolved binding, we need to look into the stars in the *current* + // module. To do this, we append the `IndirectFallback` task to the task queue. + pendingTasks.append(Task { query, Type::IndirectFallback }); + // And append the new Resolution frame to check the indirect export will be resolved or not. + frames.append(Resolution::notFound()); + pendingTasks.append(Task { ResolveQuery(importedModuleRecord, exportEntry.importName), Type::Query }); + continue; + } + } + break; + } + + case Type::IndirectFallback: { + Resolution resolution = frames.takeLast(); + + if (resolution.type == Resolution::Type::NotFound) { + // Indirect export entry does not produce any resolved binding. + // So we will investigate the stars. + if (!resolveNonLocal(task.query)) + return Resolution::error(); + continue; + } + + ASSERT_WITH_MESSAGE(resolution.type == Resolution::Type::Resolved, "When we see Error and Ambiguous, we immediately return from this loop. So here, only Resolved comes."); + + // 3. If we don't follow any star links during the resolution, we can see all the traced nodes are cacheable. + // 4. Once we follow star links, we should not retrieve the result from the cache and should not cache the result. + if (!foundStarLinks) + cacheResolutionForQuery(query, resolution); + + // If indirect export entry produces Resolved, we should merge it to the upper frame. + // And do not investigate the stars of the current module. + if (!mergeToCurrentTop(resolution)) + return Resolution::ambiguous(); + break; + } + + case Type::GatherStars: { + Resolution resolution = frames.takeLast(); + ASSERT_WITH_MESSAGE(resolution.type == Resolution::Type::Resolved || resolution.type == Resolution::Type::NotFound, "When we see Error and Ambiguous, we immediately return from this loop. So here, only Resolved and NotFound comes."); + + // Merge the star resolution to the upper frame. + if (!mergeToCurrentTop(resolution)) + return Resolution::ambiguous(); + break; + } + } + } + + ASSERT(frames.size() == 1); + // 1. The starting point is always cacheable. + if (frames[0].type == Resolution::Type::Resolved) + cacheResolutionForQuery(root, frames[0]); + return frames[0]; +} + +auto AbstractModuleRecord::resolveExport(ExecState* exec, const Identifier& exportName) -> Resolution +{ + // Look up the cached resolution first before entering the resolving loop, since the loop setup takes some cost. + if (std::optional cachedResolution = tryGetCachedResolution(exportName.impl())) + return *cachedResolution; + return resolveExportImpl(exec, ResolveQuery(this, exportName.impl())); +} + +static void getExportedNames(ExecState* exec, AbstractModuleRecord* root, IdentifierSet& exportedNames) +{ + HashSet exportStarSet; + Vector pendingModules; + + pendingModules.append(root); + + while (!pendingModules.isEmpty()) { + AbstractModuleRecord* moduleRecord = pendingModules.takeLast(); + if (exportStarSet.contains(moduleRecord)) + continue; + exportStarSet.add(moduleRecord); + + for (const auto& pair : moduleRecord->exportEntries()) { + const AbstractModuleRecord::ExportEntry& exportEntry = pair.value; + if (moduleRecord == root || exec->propertyNames().defaultKeyword != exportEntry.exportName) + exportedNames.add(exportEntry.exportName.impl()); + } + + for (const auto& starModuleName : moduleRecord->starExportEntries()) { + AbstractModuleRecord* requestedModuleRecord = moduleRecord->hostResolveImportedModule(exec, Identifier::fromUid(exec, starModuleName.get())); + pendingModules.append(requestedModuleRecord); + } + } +} + +JSModuleNamespaceObject* AbstractModuleRecord::getModuleNamespace(ExecState* exec) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + // http://www.ecma-international.org/ecma-262/6.0/#sec-getmodulenamespace + if (m_moduleNamespaceObject) + return m_moduleNamespaceObject.get(); + + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + IdentifierSet exportedNames; + getExportedNames(exec, this, exportedNames); + + Vector> resolutions; + for (auto& name : exportedNames) { + Identifier ident = Identifier::fromUid(exec, name.get()); + const Resolution resolution = resolveExport(exec, ident); + switch (resolution.type) { + case Resolution::Type::NotFound: + throwSyntaxError(exec, scope, makeString("Exported binding name '", String(name.get()), "' is not found.")); + return nullptr; + + case Resolution::Type::Error: + throwSyntaxError(exec, scope, makeString("Exported binding name 'default' cannot be resolved by star export entries.")); + return nullptr; + + case Resolution::Type::Ambiguous: + break; + + case Resolution::Type::Resolved: + resolutions.append({ WTFMove(ident), resolution }); + break; + } + } + + m_moduleNamespaceObject.set(vm, this, JSModuleNamespaceObject::create(exec, globalObject, globalObject->moduleNamespaceObjectStructure(), this, WTFMove(resolutions))); + return m_moduleNamespaceObject.get(); +} + +static String printableName(const RefPtr& uid) +{ + if (uid->isSymbol()) + return uid.get(); + return WTF::makeString("'", String(uid.get()), "'"); +} + +static String printableName(const Identifier& ident) +{ + return printableName(ident.impl()); +} + +void AbstractModuleRecord::dump() +{ + dataLog("\nAnalyzing ModuleRecord key(", printableName(m_moduleKey), ")\n"); + + dataLog(" Dependencies: ", m_requestedModules.size(), " modules\n"); + for (const auto& moduleName : m_requestedModules) + dataLog(" module(", printableName(moduleName), ")\n"); + + dataLog(" Import: ", m_importEntries.size(), " entries\n"); + for (const auto& pair : m_importEntries) { + const ImportEntry& importEntry = pair.value; + dataLog(" import(", printableName(importEntry.importName), "), local(", printableName(importEntry.localName), "), module(", printableName(importEntry.moduleRequest), ")\n"); + } + + dataLog(" Export: ", m_exportEntries.size(), " entries\n"); + for (const auto& pair : m_exportEntries) { + const ExportEntry& exportEntry = pair.value; + switch (exportEntry.type) { + case ExportEntry::Type::Local: + dataLog(" [Local] ", "export(", printableName(exportEntry.exportName), "), local(", printableName(exportEntry.localName), ")\n"); + break; + + case ExportEntry::Type::Indirect: + dataLog(" [Indirect] ", "export(", printableName(exportEntry.exportName), "), import(", printableName(exportEntry.importName), "), module(", printableName(exportEntry.moduleName), ")\n"); + break; + } + } + for (const auto& moduleName : m_starExportEntries) + dataLog(" [Star] module(", printableName(moduleName.get()), ")\n"); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/AbstractModuleRecord.h b/Source/JavaScriptCore/runtime/AbstractModuleRecord.h new file mode 100644 index 000000000..04af1261a --- /dev/null +++ b/Source/JavaScriptCore/runtime/AbstractModuleRecord.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "Identifier.h" +#include "JSDestructibleObject.h" +#include "SourceCode.h" +#include "VariableEnvironment.h" +#include +#include +#include + +namespace JSC { + +class JSModuleEnvironment; +class JSModuleNamespaceObject; +class JSMap; + +// Based on the Source Text Module Record +// http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records +class AbstractModuleRecord : public JSDestructibleObject { + friend class LLIntOffsetsExtractor; +public: + typedef JSDestructibleObject Base; + + // https://tc39.github.io/ecma262/#sec-source-text-module-records + struct ExportEntry { + enum class Type { + Local, + Indirect + }; + + static ExportEntry createLocal(const Identifier& exportName, const Identifier& localName); + static ExportEntry createIndirect(const Identifier& exportName, const Identifier& importName, const Identifier& moduleName); + + Type type; + Identifier exportName; + Identifier moduleName; + Identifier importName; + Identifier localName; + }; + + struct ImportEntry { + Identifier moduleRequest; + Identifier importName; + Identifier localName; + + bool isNamespace(VM& vm) const + { + return importName == vm.propertyNames->timesIdentifier; + } + }; + + typedef WTF::ListHashSet, IdentifierRepHash> OrderedIdentifierSet; + typedef HashMap, ImportEntry, IdentifierRepHash, HashTraits>> ImportEntries; + typedef HashMap, ExportEntry, IdentifierRepHash, HashTraits>> ExportEntries; + + DECLARE_EXPORT_INFO; + + void appendRequestedModule(const Identifier&); + void addStarExportEntry(const Identifier&); + void addImportEntry(const ImportEntry&); + void addExportEntry(const ExportEntry&); + + std::optional tryGetImportEntry(UniquedStringImpl* localName); + std::optional tryGetExportEntry(UniquedStringImpl* exportName); + + const Identifier& moduleKey() const { return m_moduleKey; } + const OrderedIdentifierSet& requestedModules() const { return m_requestedModules; } + const ExportEntries& exportEntries() const { return m_exportEntries; } + const ImportEntries& importEntries() const { return m_importEntries; } + const OrderedIdentifierSet& starExportEntries() const { return m_starExportEntries; } + + void dump(); + + struct Resolution { + enum class Type { Resolved, NotFound, Ambiguous, Error }; + + static Resolution notFound(); + static Resolution error(); + static Resolution ambiguous(); + + Type type; + AbstractModuleRecord* moduleRecord; + Identifier localName; + }; + + Resolution resolveExport(ExecState*, const Identifier& exportName); + Resolution resolveImport(ExecState*, const Identifier& localName); + + AbstractModuleRecord* hostResolveImportedModule(ExecState*, const Identifier& moduleName); + + JSModuleNamespaceObject* getModuleNamespace(ExecState*); + + JSModuleEnvironment* moduleEnvironment() + { + ASSERT(m_moduleEnvironment); + return m_moduleEnvironment.get(); + } + +protected: + AbstractModuleRecord(VM&, Structure*, const Identifier&); + void finishCreation(ExecState*, VM&); + + static void visitChildren(JSCell*, SlotVisitor&); + static void destroy(JSCell*); + + WriteBarrier m_moduleEnvironment; + +private: + struct ResolveQuery; + static Resolution resolveExportImpl(ExecState*, const ResolveQuery&); + std::optional tryGetCachedResolution(UniquedStringImpl* exportName); + void cacheResolution(UniquedStringImpl* exportName, const Resolution&); + + // The loader resolves the given module name to the module key. The module key is the unique value to represent this module. + Identifier m_moduleKey; + + // Currently, we don't keep the occurrence order of the import / export entries. + // So, we does not guarantee the order of the errors. + // e.g. The import declaration that occurr later than the another import declaration may + // throw the error even if the former import declaration also has the invalid content. + // + // import ... // (1) this has some invalid content. + // import ... // (2) this also has some invalid content. + // + // In the above case, (2) may throw the error earlier than (1) + // + // But, in all the cases, we will throw the syntax error. So except for the content of the syntax error, + // there are no difference. + + // Map localName -> ImportEntry. + ImportEntries m_importEntries; + + // Map exportName -> ExportEntry. + ExportEntries m_exportEntries; + + // Save the occurrence order since resolveExport requires it. + OrderedIdentifierSet m_starExportEntries; + + // Save the occurrence order since the module loader loads and runs the modules in this order. + // http://www.ecma-international.org/ecma-262/6.0/#sec-moduleevaluation + OrderedIdentifierSet m_requestedModules; + + WriteBarrier m_dependenciesMap; + + WriteBarrier m_moduleNamespaceObject; + + // We assume that all the AbstractModuleRecord are retained by JSModuleLoader's registry. + // So here, we don't visit each object for GC. The resolution cache map caches the once + // looked up correctly resolved resolution, since (1) we rarely looked up the non-resolved one, + // and (2) if we cache all the attempts the size of the map becomes infinitely large. + typedef HashMap, Resolution, IdentifierRepHash, HashTraits>> Resolutions; + Resolutions m_resolutionCache; +}; + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArgList.cpp b/Source/JavaScriptCore/runtime/ArgList.cpp index e13104df5..6fbbc5d53 100644 --- a/Source/JavaScriptCore/runtime/ArgList.cpp +++ b/Source/JavaScriptCore/runtime/ArgList.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003-2017 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -21,15 +21,27 @@ #include "config.h" #include "ArgList.h" -#include "HeapRootVisitor.h" #include "JSCJSValue.h" #include "JSObject.h" -#include "Operations.h" +#include "JSCInlines.h" using std::min; namespace JSC { +void MarkedArgumentBuffer::addMarkSet(JSValue v) +{ + if (m_markSet) + return; + + Heap* heap = Heap::heap(v); + if (!heap) + return; + + m_markSet = &heap->markListSet(); + m_markSet->add(this); +} + void ArgList::getSlice(int startIndex, ArgList& result) const { if (startIndex <= 0 || startIndex >= m_argCount) { @@ -41,49 +53,54 @@ void ArgList::getSlice(int startIndex, ArgList& result) const result.m_argCount = m_argCount - startIndex; } -void MarkedArgumentBuffer::markLists(HeapRootVisitor& heapRootVisitor, ListSet& markSet) +void MarkedArgumentBuffer::markLists(SlotVisitor& visitor, ListSet& markSet) { ListSet::iterator end = markSet.end(); for (ListSet::iterator it = markSet.begin(); it != end; ++it) { MarkedArgumentBuffer* list = *it; for (int i = 0; i < list->m_size; ++i) - heapRootVisitor.visit(reinterpret_cast(&list->slotFor(i))); + visitor.appendUnbarriered(JSValue::decode(list->slotFor(i))); } } -void MarkedArgumentBuffer::slowAppend(JSValue v) +void MarkedArgumentBuffer::slowEnsureCapacity(size_t requestedCapacity) +{ + int newCapacity = Checked(requestedCapacity).unsafeGet(); + expandCapacity(newCapacity); +} + +void MarkedArgumentBuffer::expandCapacity() +{ + int newCapacity = (Checked(m_capacity) * 2).unsafeGet(); + expandCapacity(newCapacity); +} + +void MarkedArgumentBuffer::expandCapacity(int newCapacity) { - int newCapacity = m_capacity * 4; - EncodedJSValue* newBuffer = new EncodedJSValue[newCapacity]; - for (int i = 0; i < m_capacity; ++i) + ASSERT(m_capacity < newCapacity); + size_t size = (Checked(newCapacity) * sizeof(EncodedJSValue)).unsafeGet(); + EncodedJSValue* newBuffer = static_cast(fastMalloc(size)); + for (int i = 0; i < m_size; ++i) { newBuffer[i] = m_buffer[i]; + addMarkSet(JSValue::decode(m_buffer[i])); + } if (EncodedJSValue* base = mallocBase()) - delete [] base; + fastFree(base); m_buffer = newBuffer; m_capacity = newCapacity; +} + +void MarkedArgumentBuffer::slowAppend(JSValue v) +{ + ASSERT(m_size <= m_capacity); + if (m_size == m_capacity) + expandCapacity(); slotFor(m_size) = JSValue::encode(v); ++m_size; - - if (m_markSet) - return; - - // As long as our size stays within our Vector's inline - // capacity, all our values are allocated on the stack, and - // therefore don't need explicit marking. Once our size exceeds - // our Vector's inline capacity, though, our values move to the - // heap, where they do need explicit marking. - for (int i = 0; i < m_size; ++i) { - Heap* heap = Heap::heap(JSValue::decode(slotFor(i))); - if (!heap) - continue; - - m_markSet = &heap->markListSet(); - m_markSet->add(this); - break; - } + addMarkSet(v); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArgList.h b/Source/JavaScriptCore/runtime/ArgList.h index 9aafc9070..0b4601473 100644 --- a/Source/JavaScriptCore/runtime/ArgList.h +++ b/Source/JavaScriptCore/runtime/ArgList.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003-2017 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,20 +19,17 @@ * */ -#ifndef ArgList_h -#define ArgList_h +#pragma once #include "CallFrame.h" -#include "Register.h" +#include #include -#include namespace JSC { -class SlotVisitor; - class MarkedArgumentBuffer { WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer); + WTF_FORBID_HEAP_ALLOCATION; friend class VM; friend class ArgList; @@ -57,7 +54,7 @@ public: m_markSet->remove(this); if (EncodedJSValue* base = mallocBase()) - delete [] base; + fastFree(base); } size_t size() const { return m_size; } @@ -78,7 +75,8 @@ public: void append(JSValue v) { - if (m_size >= m_capacity) + ASSERT(m_size <= m_capacity); + if (m_size == m_capacity || mallocBase()) return slowAppend(v); slotFor(m_size) = JSValue::encode(v); @@ -97,9 +95,21 @@ public: return JSValue::decode(slotFor(m_size - 1)); } - static void markLists(HeapRootVisitor&, ListSet&); + static void markLists(SlotVisitor&, ListSet&); + + void ensureCapacity(size_t requestedCapacity) + { + if (requestedCapacity > static_cast(m_capacity)) + slowEnsureCapacity(requestedCapacity); + } private: + void expandCapacity(); + void expandCapacity(int newCapacity); + void slowEnsureCapacity(size_t requestedCapacity); + + void addMarkSet(JSValue); + JS_EXPORT_PRIVATE void slowAppend(JSValue); EncodedJSValue& slotFor(int item) const @@ -109,7 +119,7 @@ private: EncodedJSValue* mallocBase() { - if (m_capacity == static_cast(inlineCapacity)) + if (m_buffer == m_inlineBuffer) return 0; return &slotFor(0); } @@ -119,23 +129,6 @@ private: EncodedJSValue m_inlineBuffer[inlineCapacity]; EncodedJSValue* m_buffer; ListSet* m_markSet; - -private: - // Prohibits new / delete, which would break GC. - void* operator new(size_t size) - { - return fastMalloc(size); - } - void operator delete(void* p) - { - fastFree(p); - } - - void* operator new[](size_t); - void operator delete[](void*); - - void* operator new(size_t, void*); - void operator delete(void*, size_t); }; class ArgList { @@ -172,13 +165,15 @@ public: JS_EXPORT_PRIVATE void getSlice(int startIndex, ArgList& result) const; -private: + // FIXME: This is only made public as a work around for jsc's test helper function, + // callWasmFunction() to use. Make this a private method again once we can remove + // callWasmFunction(). + // https://bugs.webkit.org/show_bug.cgi?id=168582 JSValue* data() const { return m_args; } +private: JSValue* m_args; int m_argCount; }; } // namespace JSC - -#endif // ArgList_h diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp deleted file mode 100644 index 8fd195cb9..000000000 --- a/Source/JavaScriptCore/runtime/Arguments.cpp +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) - * Copyright (C) 2007 Maks Orlovich - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "Arguments.h" - -#include "CallFrameInlines.h" -#include "JSActivation.h" -#include "JSArgumentsIterator.h" -#include "JSFunction.h" -#include "JSGlobalObject.h" -#include "Operations.h" - -using namespace std; - -namespace JSC { - -const ClassInfo Arguments::s_info = { "Arguments", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) }; - -void Arguments::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - Arguments* thisObject = jsCast(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - JSObject::visitChildren(thisObject, visitor); - - if (thisObject->m_registerArray) - visitor.appendValues(thisObject->m_registerArray.get(), thisObject->m_numArguments); - visitor.append(&thisObject->m_callee); - visitor.append(&thisObject->m_activation); -} - -static EncodedJSValue JSC_HOST_CALL argumentsFuncIterator(ExecState*); - -void Arguments::destroy(JSCell* cell) -{ - static_cast(cell)->Arguments::~Arguments(); -} - -void Arguments::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length) -{ - if (UNLIKELY(m_overrodeLength)) { - length = min(get(exec, exec->propertyNames().length).toUInt32(exec), length); - for (unsigned i = 0; i < length; i++) - callFrame->setArgument(i, get(exec, i)); - return; - } - ASSERT(length == this->length(exec)); - for (size_t i = 0; i < length; ++i) { - if (JSValue value = tryGetArgument(i)) - callFrame->setArgument(i, value); - else - callFrame->setArgument(i, get(exec, i)); - } -} - -void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) -{ - if (UNLIKELY(m_overrodeLength)) { - unsigned length = get(exec, exec->propertyNames().length).toUInt32(exec); - for (unsigned i = 0; i < length; i++) - args.append(get(exec, i)); - return; - } - uint32_t length = this->length(exec); - for (size_t i = 0; i < length; ++i) { - if (JSValue value = tryGetArgument(i)) - args.append(value); - else - args.append(get(exec, i)); - } -} - -bool Arguments::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned i, PropertySlot& slot) -{ - Arguments* thisObject = jsCast(object); - if (JSValue value = thisObject->tryGetArgument(i)) { - slot.setValue(thisObject, None, value); - return true; - } - - return JSObject::getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot); -} - -void Arguments::createStrictModeCallerIfNecessary(ExecState* exec) -{ - if (m_overrodeCaller) - return; - - VM& vm = exec->vm(); - m_overrodeCaller = true; - PropertyDescriptor descriptor; - descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(vm), DontEnum | DontDelete | Accessor); - methodTable()->defineOwnProperty(this, exec, vm.propertyNames->caller, descriptor, false); -} - -void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec) -{ - if (m_overrodeCallee) - return; - - VM& vm = exec->vm(); - m_overrodeCallee = true; - PropertyDescriptor descriptor; - descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(vm), DontEnum | DontDelete | Accessor); - methodTable()->defineOwnProperty(this, exec, vm.propertyNames->callee, descriptor, false); -} - -bool Arguments::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - Arguments* thisObject = jsCast(object); - unsigned i = propertyName.asIndex(); - if (JSValue value = thisObject->tryGetArgument(i)) { - RELEASE_ASSERT(i < PropertyName::NotAnIndex); - slot.setValue(thisObject, None, value); - return true; - } - - if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->m_overrodeLength)) { - slot.setValue(thisObject, DontEnum, jsNumber(thisObject->m_numArguments)); - return true; - } - - if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->m_overrodeCallee)) { - if (!thisObject->m_isStrictMode) { - slot.setValue(thisObject, DontEnum, thisObject->m_callee.get()); - return true; - } - thisObject->createStrictModeCalleeIfNecessary(exec); - } - - if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode) - thisObject->createStrictModeCallerIfNecessary(exec); - - if (JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot)) - return true; - if (propertyName == exec->propertyNames().iteratorPrivateName) { - VM& vm = exec->vm(); - JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - thisObject->JSC_NATIVE_FUNCTION(exec->propertyNames().iteratorPrivateName, argumentsFuncIterator, DontEnum, 0); - if (JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot)) - return true; - } - return false; -} - -void Arguments::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) -{ - Arguments* thisObject = jsCast(object); - for (unsigned i = 0; i < thisObject->m_numArguments; ++i) { - if (!thisObject->isArgument(i)) - continue; - propertyNames.add(Identifier::from(exec, i)); - } - if (mode == IncludeDontEnumProperties) { - propertyNames.add(exec->propertyNames().callee); - propertyNames.add(exec->propertyNames().length); - } - JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode); -} - -void Arguments::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue value, bool shouldThrow) -{ - Arguments* thisObject = jsCast(cell); - if (thisObject->trySetArgument(exec->vm(), i, value)) - return; - - PutPropertySlot slot(thisObject, shouldThrow); - JSObject::put(thisObject, exec, Identifier::from(exec, i), value, slot); -} - -void Arguments::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) -{ - Arguments* thisObject = jsCast(cell); - unsigned i = propertyName.asIndex(); - if (thisObject->trySetArgument(exec->vm(), i, value)) - return; - - if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) { - thisObject->m_overrodeLength = true; - thisObject->putDirect(exec->vm(), propertyName, value, DontEnum); - return; - } - - if (propertyName == exec->propertyNames().callee && !thisObject->m_overrodeCallee) { - if (!thisObject->m_isStrictMode) { - thisObject->m_overrodeCallee = true; - thisObject->putDirect(exec->vm(), propertyName, value, DontEnum); - return; - } - thisObject->createStrictModeCalleeIfNecessary(exec); - } - - if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode) - thisObject->createStrictModeCallerIfNecessary(exec); - - JSObject::put(thisObject, exec, propertyName, value, slot); -} - -bool Arguments::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) -{ - Arguments* thisObject = jsCast(cell); - if (i < thisObject->m_numArguments) { - if (!Base::deletePropertyByIndex(cell, exec, i)) - return false; - if (thisObject->tryDeleteArgument(i)) - return true; - } - return JSObject::deletePropertyByIndex(thisObject, exec, i); -} - -bool Arguments::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) -{ - if (exec->vm().isInDefineOwnProperty()) - return Base::deleteProperty(cell, exec, propertyName); - - Arguments* thisObject = jsCast(cell); - unsigned i = propertyName.asIndex(); - if (i < thisObject->m_numArguments) { - RELEASE_ASSERT(i < PropertyName::NotAnIndex); - if (!Base::deleteProperty(cell, exec, propertyName)) - return false; - if (thisObject->tryDeleteArgument(i)) - return true; - } - - if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) { - thisObject->m_overrodeLength = true; - return true; - } - - if (propertyName == exec->propertyNames().callee && !thisObject->m_overrodeCallee) { - if (!thisObject->m_isStrictMode) { - thisObject->m_overrodeCallee = true; - return true; - } - thisObject->createStrictModeCalleeIfNecessary(exec); - } - - if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode) - thisObject->createStrictModeCallerIfNecessary(exec); - - return JSObject::deleteProperty(thisObject, exec, propertyName); -} - -bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow) -{ - Arguments* thisObject = jsCast(object); - unsigned i = propertyName.asIndex(); - if (i < thisObject->m_numArguments) { - RELEASE_ASSERT(i < PropertyName::NotAnIndex); - // If the property is not yet present on the object, and is not yet marked as deleted, then add it now. - PropertySlot slot(thisObject); - if (!thisObject->isDeletedArgument(i) && !JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot)) { - JSValue value = thisObject->tryGetArgument(i); - ASSERT(value); - object->putDirectMayBeIndex(exec, propertyName, value); - } - if (!Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow)) - return false; - - // From ES 5.1, 10.6 Arguments Object - // 5. If the value of isMapped is not undefined, then - if (thisObject->isArgument(i)) { - // a. If IsAccessorDescriptor(Desc) is true, then - if (descriptor.isAccessorDescriptor()) { - // i. Call the [[Delete]] internal method of map passing P, and false as the arguments. - thisObject->tryDeleteArgument(i); - } else { // b. Else - // i. If Desc.[[Value]] is present, then - // 1. Call the [[Put]] internal method of map passing P, Desc.[[Value]], and Throw as the arguments. - if (descriptor.value()) - thisObject->trySetArgument(exec->vm(), i, descriptor.value()); - // ii. If Desc.[[Writable]] is present and its value is false, then - // 1. Call the [[Delete]] internal method of map passing P and false as arguments. - if (descriptor.writablePresent() && !descriptor.writable()) - thisObject->tryDeleteArgument(i); - } - } - return true; - } - - if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) { - thisObject->putDirect(exec->vm(), propertyName, jsNumber(thisObject->m_numArguments), DontEnum); - thisObject->m_overrodeLength = true; - } else if (propertyName == exec->propertyNames().callee && !thisObject->m_overrodeCallee) { - thisObject->putDirect(exec->vm(), propertyName, thisObject->m_callee.get(), DontEnum); - thisObject->m_overrodeCallee = true; - } else if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode) - thisObject->createStrictModeCallerIfNecessary(exec); - - return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow); -} - -void Arguments::tearOff(CallFrame* callFrame) -{ - if (isTornOff()) - return; - - if (!m_numArguments) - return; - - // Must be called for the same call frame from which it was created. - ASSERT(bitwise_cast*>(callFrame) == m_registers); - - m_registerArray = std::make_unique[]>(m_numArguments); - m_registers = m_registerArray.get() - CallFrame::offsetFor(1) - 1; - - // If we have a captured argument that logically aliases activation storage, - // but we optimize away the activation, the argument needs to tear off into - // our storage. The simplest way to do this is to revert it to Normal status. - if (m_slowArgumentData && !m_activation) { - for (size_t i = 0; i < m_numArguments; ++i) { - if (m_slowArgumentData->slowArguments[i].status != SlowArgument::Captured) - continue; - m_slowArgumentData->slowArguments[i].status = SlowArgument::Normal; - m_slowArgumentData->slowArguments[i].index = CallFrame::argumentOffset(i); - } - } - - for (size_t i = 0; i < m_numArguments; ++i) - trySetArgument(callFrame->vm(), i, callFrame->argumentAfterCapture(i)); -} - -void Arguments::didTearOffActivation(ExecState* exec, JSActivation* activation) -{ - RELEASE_ASSERT(activation); - if (isTornOff()) - return; - - if (!m_numArguments) - return; - - m_activation.set(exec->vm(), this, activation); - tearOff(exec); -} - -void Arguments::tearOff(CallFrame* callFrame, InlineCallFrame* inlineCallFrame) -{ - if (isTornOff()) - return; - - if (!m_numArguments) - return; - - m_registerArray = std::make_unique[]>(m_numArguments); - m_registers = m_registerArray.get() - CallFrame::offsetFor(1) - 1; - - for (size_t i = 0; i < m_numArguments; ++i) { - ValueRecovery& recovery = inlineCallFrame->arguments[i + 1]; - trySetArgument(callFrame->vm(), i, recovery.recover(callFrame)); - } -} - -EncodedJSValue JSC_HOST_CALL argumentsFuncIterator(ExecState* exec) -{ - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - Arguments* arguments = jsDynamicCast(thisObj); - if (!arguments) - return JSValue::encode(throwTypeError(exec, "Attempted to use Arguments iterator on non-Arguments object")); - return JSValue::encode(JSArgumentsIterator::create(exec->vm(), exec->callee()->globalObject()->argumentsIteratorStructure(), arguments)); -} - - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h deleted file mode 100644 index 18f389171..000000000 --- a/Source/JavaScriptCore/runtime/Arguments.h +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) - * Copyright (C) 2007 Maks Orlovich - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#ifndef Arguments_h -#define Arguments_h - -#include "CodeOrigin.h" -#include "JSActivation.h" -#include "JSDestructibleObject.h" -#include "JSFunction.h" -#include "JSGlobalObject.h" -#include "Interpreter.h" -#include "ObjectConstructor.h" -#include - -namespace JSC { - -class Arguments : public JSDestructibleObject { - friend class JIT; - friend class JSArgumentsIterator; -public: - typedef JSDestructibleObject Base; - - static Arguments* create(VM& vm, CallFrame* callFrame) - { - Arguments* arguments = new (NotNull, allocateCell(vm.heap)) Arguments(callFrame); - arguments->finishCreation(callFrame); - return arguments; - } - - static Arguments* create(VM& vm, CallFrame* callFrame, InlineCallFrame* inlineCallFrame) - { - Arguments* arguments = new (NotNull, allocateCell(vm.heap)) Arguments(callFrame); - arguments->finishCreation(callFrame, inlineCallFrame); - return arguments; - } - - enum { MaxArguments = 0x10000 }; - -private: - enum NoParametersType { NoParameters }; - - Arguments(CallFrame*); - Arguments(CallFrame*, NoParametersType); - -public: - DECLARE_INFO; - - static void visitChildren(JSCell*, SlotVisitor&); - - void fillArgList(ExecState*, MarkedArgumentBuffer&); - - uint32_t length(ExecState* exec) const - { - if (UNLIKELY(m_overrodeLength)) - return get(exec, exec->propertyNames().length).toUInt32(exec); - return m_numArguments; - } - - void copyToArguments(ExecState*, CallFrame*, uint32_t length); - void tearOff(CallFrame*); - void tearOff(CallFrame*, InlineCallFrame*); - bool isTornOff() const { return m_registerArray.get(); } - void didTearOffActivation(ExecState*, JSActivation*); - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - - static ptrdiff_t offsetOfNumArguments() { return OBJECT_OFFSETOF(Arguments, m_numArguments); } - static ptrdiff_t offsetOfRegisters() { return OBJECT_OFFSETOF(Arguments, m_registers); } - static ptrdiff_t offsetOfSlowArgumentData() { return OBJECT_OFFSETOF(Arguments, m_slowArgumentData); } - static ptrdiff_t offsetOfOverrodeLength() { return OBJECT_OFFSETOF(Arguments, m_overrodeLength); } - -protected: - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags; - - void finishCreation(CallFrame*); - void finishCreation(CallFrame*, InlineCallFrame*); - -private: - static void destroy(JSCell*); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&); - static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); - static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); - static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); - static bool deleteProperty(JSCell*, ExecState*, PropertyName); - static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); - static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); - void createStrictModeCallerIfNecessary(ExecState*); - void createStrictModeCalleeIfNecessary(ExecState*); - - bool isArgument(size_t); - bool trySetArgument(VM&, size_t argument, JSValue); - JSValue tryGetArgument(size_t argument); - bool isDeletedArgument(size_t); - bool tryDeleteArgument(size_t); - WriteBarrierBase& argument(size_t); - void allocateSlowArguments(); - - void init(CallFrame*); - - WriteBarrier m_activation; - - unsigned m_numArguments; - - // We make these full byte booleans to make them easy to test from the JIT, - // and because even if they were single-bit booleans we still wouldn't save - // any space. - bool m_overrodeLength; - bool m_overrodeCallee; - bool m_overrodeCaller; - bool m_isStrictMode; - - WriteBarrierBase* m_registers; - std::unique_ptr[]> m_registerArray; - - struct SlowArgumentData { - std::unique_ptr slowArguments; - int bytecodeToMachineCaptureOffset; // Add this if you have a bytecode offset into captured registers and you want the machine offset instead. Subtract if you want to do the opposite. - }; - - std::unique_ptr m_slowArgumentData; - - WriteBarrier m_callee; -}; - -Arguments* asArguments(JSValue); - -inline Arguments* asArguments(JSValue value) -{ - ASSERT(asObject(value)->inherits(Arguments::info())); - return static_cast(asObject(value)); -} - -inline Arguments::Arguments(CallFrame* callFrame) - : JSDestructibleObject(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure()) -{ -} - -inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) - : JSDestructibleObject(callFrame->vm(), callFrame->lexicalGlobalObject()->argumentsStructure()) -{ -} - -inline void Arguments::allocateSlowArguments() -{ - if (m_slowArgumentData) - return; - m_slowArgumentData = std::make_unique(); - m_slowArgumentData->bytecodeToMachineCaptureOffset = 0; - m_slowArgumentData->slowArguments = std::make_unique(m_numArguments); - for (size_t i = 0; i < m_numArguments; ++i) { - ASSERT(m_slowArgumentData->slowArguments[i].status == SlowArgument::Normal); - m_slowArgumentData->slowArguments[i].index = CallFrame::argumentOffset(i); - } -} - -inline bool Arguments::tryDeleteArgument(size_t argument) -{ - if (!isArgument(argument)) - return false; - allocateSlowArguments(); - m_slowArgumentData->slowArguments[argument].status = SlowArgument::Deleted; - return true; -} - -inline bool Arguments::trySetArgument(VM& vm, size_t argument, JSValue value) -{ - if (!isArgument(argument)) - return false; - this->argument(argument).set(vm, this, value); - return true; -} - -inline JSValue Arguments::tryGetArgument(size_t argument) -{ - if (!isArgument(argument)) - return JSValue(); - return this->argument(argument).get(); -} - -inline bool Arguments::isDeletedArgument(size_t argument) -{ - if (argument >= m_numArguments) - return false; - if (!m_slowArgumentData) - return false; - if (m_slowArgumentData->slowArguments[argument].status != SlowArgument::Deleted) - return false; - return true; -} - -inline bool Arguments::isArgument(size_t argument) -{ - if (argument >= m_numArguments) - return false; - if (m_slowArgumentData && m_slowArgumentData->slowArguments[argument].status == SlowArgument::Deleted) - return false; - return true; -} - -inline WriteBarrierBase& Arguments::argument(size_t argument) -{ - ASSERT(isArgument(argument)); - if (!m_slowArgumentData) - return m_registers[CallFrame::argumentOffset(argument)]; - - int index = m_slowArgumentData->slowArguments[argument].index; - if (!m_activation || m_slowArgumentData->slowArguments[argument].status != SlowArgument::Captured) - return m_registers[index]; - - return m_activation->registerAt(index - m_slowArgumentData->bytecodeToMachineCaptureOffset); -} - -inline void Arguments::finishCreation(CallFrame* callFrame) -{ - Base::finishCreation(callFrame->vm()); - ASSERT(inherits(info())); - - JSFunction* callee = jsCast(callFrame->callee()); - m_numArguments = callFrame->argumentCount(); - m_registers = reinterpret_cast*>(callFrame->registers()); - m_callee.set(callFrame->vm(), this, callee); - m_overrodeLength = false; - m_overrodeCallee = false; - m_overrodeCaller = false; - m_isStrictMode = callFrame->codeBlock()->isStrictMode(); - - CodeBlock* codeBlock = callFrame->codeBlock(); - if (codeBlock->hasSlowArguments()) { - SymbolTable* symbolTable = codeBlock->symbolTable(); - const SlowArgument* slowArguments = codeBlock->machineSlowArguments(); - allocateSlowArguments(); - size_t count = std::min(m_numArguments, symbolTable->parameterCount()); - for (size_t i = 0; i < count; ++i) - m_slowArgumentData->slowArguments[i] = slowArguments[i]; - m_slowArgumentData->bytecodeToMachineCaptureOffset = - codeBlock->framePointerOffsetToGetActivationRegisters(); - } - - // The bytecode generator omits op_tear_off_activation in cases of no - // declared parameters, so we need to tear off immediately. - if (m_isStrictMode || !callee->jsExecutable()->parameterCount()) - tearOff(callFrame); -} - -inline void Arguments::finishCreation(CallFrame* callFrame, InlineCallFrame* inlineCallFrame) -{ - Base::finishCreation(callFrame->vm()); - ASSERT(inherits(info())); - - JSFunction* callee = inlineCallFrame->calleeForCallFrame(callFrame); - m_numArguments = inlineCallFrame->arguments.size() - 1; - - if (m_numArguments) { - int offsetForArgumentOne = inlineCallFrame->arguments[1].virtualRegister().offset(); - m_registers = reinterpret_cast*>(callFrame->registers()) + offsetForArgumentOne - virtualRegisterForArgument(1).offset(); - } else - m_registers = 0; - m_callee.set(callFrame->vm(), this, callee); - m_overrodeLength = false; - m_overrodeCallee = false; - m_overrodeCaller = false; - m_isStrictMode = jsCast(inlineCallFrame->executable.get())->isStrictMode(); - ASSERT(!jsCast(inlineCallFrame->executable.get())->symbolTable(inlineCallFrame->isCall ? CodeForCall : CodeForConstruct)->slowArguments()); - - // The bytecode generator omits op_tear_off_activation in cases of no - // declared parameters, so we need to tear off immediately. - if (m_isStrictMode || !callee->jsExecutable()->parameterCount()) - tearOff(callFrame, inlineCallFrame); -} - -} // namespace JSC - -#endif // Arguments_h diff --git a/Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.cpp b/Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.cpp deleted file mode 100644 index afb59790c..000000000 --- a/Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2013 Apple, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "ArgumentsIteratorConstructor.h" - -#include "ArgumentsIteratorPrototype.h" -#include "JSArgumentsIterator.h" -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "JSGlobalObject.h" - -namespace JSC { - -const ClassInfo ArgumentsIteratorConstructor::s_info = { "ArgumentsIterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ArgumentsIteratorConstructor) }; - -void ArgumentsIteratorConstructor::finishCreation(VM& vm, ArgumentsIteratorPrototype* prototype) -{ - Base::finishCreation(vm); - putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly); -} - -} diff --git a/Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.h b/Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.h deleted file mode 100644 index 8360c59b2..000000000 --- a/Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2013 Apple, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ArgumentsIteratorConstructor_h -#define ArgumentsIteratorConstructor_h - -#include "InternalFunction.h" - -namespace JSC { - -class ArgumentsIteratorPrototype; - -class ArgumentsIteratorConstructor : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; - - static ArgumentsIteratorConstructor* create(VM& vm, Structure* structure, ArgumentsIteratorPrototype* prototype) - { - ArgumentsIteratorConstructor* constructor = new (NotNull, allocateCell(vm.heap)) ArgumentsIteratorConstructor(vm, structure); - constructor->finishCreation(vm, prototype); - return constructor; - } - - DECLARE_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - -private: - ArgumentsIteratorConstructor(VM& vm, Structure* structure) - : Base(vm, structure) - { - } - void finishCreation(VM&, ArgumentsIteratorPrototype*); -}; - -} - -#endif // !defined(ArgumentsIteratorConstructor_h) diff --git a/Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.cpp b/Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.cpp deleted file mode 100644 index dd0894f14..000000000 --- a/Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2013 Apple, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "ArgumentsIteratorPrototype.h" - -#include "JSArgumentsIterator.h" - -namespace JSC { - -const ClassInfo ArgumentsIteratorPrototype::s_info = { "ArgumentsIterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ArgumentsIteratorPrototype) }; - -static EncodedJSValue JSC_HOST_CALL argumentsIteratorPrototypeFuncIterator(ExecState*); -static EncodedJSValue JSC_HOST_CALL argumentsIteratorPrototypeFuncNext(ExecState*); - -void ArgumentsIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); - vm.prototypeMap.addPrototype(this); - - JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, argumentsIteratorPrototypeFuncIterator, DontEnum, 0); - JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorNextPrivateName, argumentsIteratorPrototypeFuncNext, DontEnum, 0); -} - -EncodedJSValue JSC_HOST_CALL argumentsIteratorPrototypeFuncIterator(CallFrame* callFrame) -{ - return JSValue::encode(callFrame->thisValue()); -} - -EncodedJSValue JSC_HOST_CALL argumentsIteratorPrototypeFuncNext(CallFrame* callFrame) -{ - JSValue result; - if (jsCast(callFrame->thisValue())->next(callFrame, result)) - return JSValue::encode(result); - return JSValue::encode(callFrame->vm().iterationTerminator.get()); -} - -} diff --git a/Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.h b/Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.h deleted file mode 100644 index 21839bfa1..000000000 --- a/Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2013 Apple, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ArgumentsIteratorPrototype_h -#define ArgumentsIteratorPrototype_h - -#include "JSObject.h" - -namespace JSC { - -class ArgumentsIteratorPrototype : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; - - static ArgumentsIteratorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) - { - ArgumentsIteratorPrototype* prototype = new (NotNull, allocateCell(vm.heap)) ArgumentsIteratorPrototype(vm, structure); - prototype->finishCreation(vm, globalObject); - return prototype; - } - - DECLARE_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - -private: - ArgumentsIteratorPrototype(VM& vm, Structure* structure) - : Base(vm, structure) - { - } - void finishCreation(VM&, JSGlobalObject*); -}; - -} - -#endif // !defined(ArgumentsIteratorPrototype_h) diff --git a/Source/JavaScriptCore/runtime/ArgumentsMode.h b/Source/JavaScriptCore/runtime/ArgumentsMode.h new file mode 100644 index 000000000..e7a12911b --- /dev/null +++ b/Source/JavaScriptCore/runtime/ArgumentsMode.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +namespace JSC { + +enum class ArgumentsMode { + Cloned, + FakeValues +}; + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArityCheckMode.h b/Source/JavaScriptCore/runtime/ArityCheckMode.h new file mode 100644 index 000000000..dae719ad2 --- /dev/null +++ b/Source/JavaScriptCore/runtime/ArityCheckMode.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +namespace JSC { + +enum ArityCheckMode { + ArityCheckNotRequired, + MustCheckArity +}; + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayBuffer.cpp b/Source/JavaScriptCore/runtime/ArrayBuffer.cpp index 2c49b6976..bb9cfc42b 100644 --- a/Source/JavaScriptCore/runtime/ArrayBuffer.cpp +++ b/Source/JavaScriptCore/runtime/ArrayBuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2013, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,12 +28,274 @@ #include "ArrayBufferNeuteringWatchpoint.h" #include "JSArrayBufferView.h" -#include "Operations.h" -#include +#include "JSCInlines.h" namespace JSC { -bool ArrayBuffer::transfer(ArrayBufferContents& result) +SharedArrayBufferContents::SharedArrayBufferContents(void* data, ArrayBufferDestructorFunction&& destructor) + : m_data(data) + , m_destructor(WTFMove(destructor)) +{ +} + +SharedArrayBufferContents::~SharedArrayBufferContents() +{ + m_destructor(m_data); +} + +ArrayBufferContents::ArrayBufferContents() +{ + reset(); +} + +ArrayBufferContents::ArrayBufferContents(ArrayBufferContents&& other) +{ + reset(); + other.transferTo(*this); +} + +ArrayBufferContents::ArrayBufferContents(void* data, unsigned sizeInBytes, ArrayBufferDestructorFunction&& destructor) + : m_data(data) + , m_sizeInBytes(sizeInBytes) +{ + m_destructor = WTFMove(destructor); +} + +ArrayBufferContents& ArrayBufferContents::operator=(ArrayBufferContents&& other) +{ + other.transferTo(*this); + return *this; +} + +ArrayBufferContents::~ArrayBufferContents() +{ + destroy(); +} + +void ArrayBufferContents::clear() +{ + destroy(); + reset(); +} + +void ArrayBufferContents::destroy() +{ + m_destructor(m_data); +} + +void ArrayBufferContents::reset() +{ + m_destructor = [] (void*) { }; + m_shared = nullptr; + m_data = nullptr; + m_sizeInBytes = 0; +} + +void ArrayBufferContents::tryAllocate(unsigned numElements, unsigned elementByteSize, InitializationPolicy policy) +{ + // Do not allow 31-bit overflow of the total size. + if (numElements) { + unsigned totalSize = numElements * elementByteSize; + if (totalSize / numElements != elementByteSize + || totalSize > static_cast(std::numeric_limits::max())) { + reset(); + return; + } + } + bool allocationSucceeded = false; + if (policy == ZeroInitialize) + allocationSucceeded = WTF::tryFastCalloc(numElements, elementByteSize).getValue(m_data); + else { + ASSERT(policy == DontInitialize); + allocationSucceeded = WTF::tryFastMalloc(numElements * elementByteSize).getValue(m_data); + } + + if (allocationSucceeded) { + m_sizeInBytes = numElements * elementByteSize; + m_destructor = [] (void* p) { fastFree(p); }; + return; + } + reset(); +} + +void ArrayBufferContents::makeShared() +{ + m_shared = adoptRef(new SharedArrayBufferContents(m_data, WTFMove(m_destructor))); + m_destructor = [] (void*) { }; +} + +void ArrayBufferContents::transferTo(ArrayBufferContents& other) +{ + other.clear(); + other.m_data = m_data; + other.m_sizeInBytes = m_sizeInBytes; + other.m_destructor = WTFMove(m_destructor); + other.m_shared = m_shared; + clear(); +} + +void ArrayBufferContents::copyTo(ArrayBufferContents& other) +{ + ASSERT(!other.m_data); + other.tryAllocate(m_sizeInBytes, sizeof(char), ArrayBufferContents::DontInitialize); + if (!other.m_data) + return; + memcpy(other.m_data, m_data, m_sizeInBytes); + other.m_sizeInBytes = m_sizeInBytes; +} + +void ArrayBufferContents::shareWith(ArrayBufferContents& other) +{ + ASSERT(!other.m_data); + ASSERT(m_shared); + other.m_destructor = [] (void*) { }; + other.m_shared = m_shared; + other.m_data = m_data; + other.m_sizeInBytes = m_sizeInBytes; +} + +Ref ArrayBuffer::create(unsigned numElements, unsigned elementByteSize) +{ + auto buffer = tryCreate(numElements, elementByteSize); + if (!buffer) + CRASH(); + return buffer.releaseNonNull(); +} + +Ref ArrayBuffer::create(ArrayBuffer& other) +{ + return ArrayBuffer::create(other.data(), other.byteLength()); +} + +Ref ArrayBuffer::create(const void* source, unsigned byteLength) +{ + auto buffer = tryCreate(source, byteLength); + if (!buffer) + CRASH(); + return buffer.releaseNonNull(); +} + +Ref ArrayBuffer::create(ArrayBufferContents&& contents) +{ + return adoptRef(*new ArrayBuffer(WTFMove(contents))); +} + +Ref ArrayBuffer::createAdopted(const void* data, unsigned byteLength) +{ + return createFromBytes(data, byteLength, [] (void* p) { fastFree(p); }); +} + +Ref ArrayBuffer::createFromBytes(const void* data, unsigned byteLength, ArrayBufferDestructorFunction&& destructor) +{ + ArrayBufferContents contents(const_cast(data), byteLength, WTFMove(destructor)); + return create(WTFMove(contents)); +} + +RefPtr ArrayBuffer::tryCreate(unsigned numElements, unsigned elementByteSize) +{ + return tryCreate(numElements, elementByteSize, ArrayBufferContents::ZeroInitialize); +} + +RefPtr ArrayBuffer::tryCreate(ArrayBuffer& other) +{ + return tryCreate(other.data(), other.byteLength()); +} + +RefPtr ArrayBuffer::tryCreate(const void* source, unsigned byteLength) +{ + ArrayBufferContents contents; + contents.tryAllocate(byteLength, 1, ArrayBufferContents::ZeroInitialize); + if (!contents.m_data) + return nullptr; + return createInternal(WTFMove(contents), source, byteLength); +} + +Ref ArrayBuffer::createUninitialized(unsigned numElements, unsigned elementByteSize) +{ + return create(numElements, elementByteSize, ArrayBufferContents::DontInitialize); +} + +RefPtr ArrayBuffer::tryCreateUninitialized(unsigned numElements, unsigned elementByteSize) +{ + return tryCreate(numElements, elementByteSize, ArrayBufferContents::DontInitialize); +} + +Ref ArrayBuffer::create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy) +{ + auto buffer = tryCreate(numElements, elementByteSize, policy); + if (!buffer) + CRASH(); + return buffer.releaseNonNull(); +} + +Ref ArrayBuffer::createInternal(ArrayBufferContents&& contents, const void* source, unsigned byteLength) +{ + ASSERT(!byteLength || source); + auto buffer = adoptRef(*new ArrayBuffer(WTFMove(contents))); + memcpy(buffer->data(), source, byteLength); + return buffer; +} + +RefPtr ArrayBuffer::tryCreate(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy) +{ + ArrayBufferContents contents; + contents.tryAllocate(numElements, elementByteSize, policy); + if (!contents.m_data) + return nullptr; + return adoptRef(*new ArrayBuffer(WTFMove(contents))); +} + +ArrayBuffer::ArrayBuffer(ArrayBufferContents&& contents) + : m_contents(WTFMove(contents)) + , m_pinCount(0) + , m_locked(false) +{ +} + +RefPtr ArrayBuffer::slice(int begin, int end) const +{ + return sliceImpl(clampIndex(begin), clampIndex(end)); +} + +RefPtr ArrayBuffer::slice(int begin) const +{ + return sliceImpl(clampIndex(begin), byteLength()); +} + +RefPtr ArrayBuffer::sliceImpl(unsigned begin, unsigned end) const +{ + unsigned size = begin <= end ? end - begin : 0; + RefPtr result = ArrayBuffer::create(static_cast(data()) + begin, size); + result->setSharingMode(sharingMode()); + return result; +} + +void ArrayBuffer::makeShared() +{ + m_contents.makeShared(); +} + +void ArrayBuffer::setSharingMode(ArrayBufferSharingMode newSharingMode) +{ + if (newSharingMode == sharingMode()) + return; + RELEASE_ASSERT(!isShared()); // Cannot revert sharing. + RELEASE_ASSERT(newSharingMode == ArrayBufferSharingMode::Shared); + makeShared(); +} + +bool ArrayBuffer::shareWith(ArrayBufferContents& result) +{ + if (!m_contents.m_data || !isShared()) { + result.m_data = nullptr; + return false; + } + + m_contents.shareWith(result); + return true; +} + +bool ArrayBuffer::transferTo(VM& vm, ArrayBufferContents& result) { Ref protect(*this); @@ -41,23 +303,28 @@ bool ArrayBuffer::transfer(ArrayBufferContents& result) result.m_data = 0; return false; } + + if (isShared()) { + m_contents.shareWith(result); + return true; + } - bool isNeuterable = !m_pinCount; + bool isNeuterable = !m_pinCount && !m_locked; - if (isNeuterable) - m_contents.transfer(result); - else { + if (!isNeuterable) { m_contents.copyTo(result); if (!result.m_data) return false; + return true; } + m_contents.transferTo(result); for (size_t i = numberOfIncomingReferences(); i--;) { JSCell* cell = incomingReferenceAt(i); - if (JSArrayBufferView* view = jsDynamicCast(cell)) + if (JSArrayBufferView* view = jsDynamicCast(vm, cell)) view->neuter(); - else if (ArrayBufferNeuteringWatchpoint* watchpoint = jsDynamicCast(cell)) - watchpoint->set()->fireAll(); + else if (ArrayBufferNeuteringWatchpoint* watchpoint = jsDynamicCast(vm, cell)) + watchpoint->fireAll(); } return true; } diff --git a/Source/JavaScriptCore/runtime/ArrayBuffer.h b/Source/JavaScriptCore/runtime/ArrayBuffer.h index f0d7d2719..46ffdb5ca 100644 --- a/Source/JavaScriptCore/runtime/ArrayBuffer.h +++ b/Source/JavaScriptCore/runtime/ArrayBuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2013, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,39 +23,60 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ArrayBuffer_h -#define ArrayBuffer_h +#pragma once +#include "ArrayBufferSharingMode.h" #include "GCIncomingRefCounted.h" #include "Weak.h" -#include +#include #include -#include +#include namespace JSC { +class VM; class ArrayBuffer; class ArrayBufferView; class JSArrayBuffer; +typedef Function ArrayBufferDestructorFunction; + +class SharedArrayBufferContents : public ThreadSafeRefCounted { +public: + SharedArrayBufferContents(void* data, ArrayBufferDestructorFunction&&); + ~SharedArrayBufferContents(); + + void* data() const { return m_data; } + +private: + void* m_data; + ArrayBufferDestructorFunction m_destructor; +}; + class ArrayBufferContents { WTF_MAKE_NONCOPYABLE(ArrayBufferContents); public: - ArrayBufferContents() - : m_data(0) - , m_sizeInBytes(0) - { } + JS_EXPORT_PRIVATE ArrayBufferContents(); + + JS_EXPORT_PRIVATE ArrayBufferContents(ArrayBufferContents&&); + JS_EXPORT_PRIVATE ArrayBufferContents& operator=(ArrayBufferContents&&); - inline ~ArrayBufferContents(); + JS_EXPORT_PRIVATE ~ArrayBufferContents(); + + JS_EXPORT_PRIVATE void clear(); + + explicit operator bool() { return !!m_data; } - void* data() { return m_data; } - unsigned sizeInBytes() { return m_sizeInBytes; } + void* data() const { return m_data; } + unsigned sizeInBytes() const { return m_sizeInBytes; } + + bool isShared() const { return m_shared; } private: - ArrayBufferContents(void* data, unsigned sizeInBytes) - : m_data(data) - , m_sizeInBytes(sizeInBytes) - { } + ArrayBufferContents(void* data, unsigned sizeInBytes, ArrayBufferDestructorFunction&&); + + void destroy(); + void reset(); friend class ArrayBuffer; @@ -64,54 +85,55 @@ private: DontInitialize }; - static inline void tryAllocate(unsigned numElements, unsigned elementByteSize, InitializationPolicy, ArrayBufferContents&); - void transfer(ArrayBufferContents& other) - { - ASSERT(!other.m_data); - other.m_data = m_data; - other.m_sizeInBytes = m_sizeInBytes; - m_data = 0; - m_sizeInBytes = 0; - } - - void copyTo(ArrayBufferContents& other) - { - ASSERT(!other.m_data); - ArrayBufferContents::tryAllocate(m_sizeInBytes, sizeof(char), ArrayBufferContents::DontInitialize, other); - if (!other.m_data) - return; - memcpy(other.m_data, m_data, m_sizeInBytes); - other.m_sizeInBytes = m_sizeInBytes; - } + void tryAllocate(unsigned numElements, unsigned elementByteSize, InitializationPolicy); + + void makeShared(); + void transferTo(ArrayBufferContents&); + void copyTo(ArrayBufferContents&); + void shareWith(ArrayBufferContents&); + ArrayBufferDestructorFunction m_destructor; + RefPtr m_shared; void* m_data; unsigned m_sizeInBytes; }; class ArrayBuffer : public GCIncomingRefCounted { public: - static inline PassRefPtr create(unsigned numElements, unsigned elementByteSize); - static inline PassRefPtr create(ArrayBuffer*); - static inline PassRefPtr create(const void* source, unsigned byteLength); - static inline PassRefPtr create(ArrayBufferContents&); - static inline PassRefPtr createAdopted(const void* data, unsigned byteLength); - - // Only for use by Uint8ClampedArray::createUninitialized. - static inline PassRefPtr createUninitialized(unsigned numElements, unsigned elementByteSize); + JS_EXPORT_PRIVATE static Ref create(unsigned numElements, unsigned elementByteSize); + JS_EXPORT_PRIVATE static Ref create(ArrayBuffer&); + JS_EXPORT_PRIVATE static Ref create(const void* source, unsigned byteLength); + JS_EXPORT_PRIVATE static Ref create(ArrayBufferContents&&); + JS_EXPORT_PRIVATE static Ref createAdopted(const void* data, unsigned byteLength); + JS_EXPORT_PRIVATE static Ref createFromBytes(const void* data, unsigned byteLength, ArrayBufferDestructorFunction&&); + JS_EXPORT_PRIVATE static RefPtr tryCreate(unsigned numElements, unsigned elementByteSize); + JS_EXPORT_PRIVATE static RefPtr tryCreate(ArrayBuffer&); + JS_EXPORT_PRIVATE static RefPtr tryCreate(const void* source, unsigned byteLength); + + // Only for use by Uint8ClampedArray::createUninitialized and SharedBuffer::createArrayBuffer. + JS_EXPORT_PRIVATE static Ref createUninitialized(unsigned numElements, unsigned elementByteSize); + JS_EXPORT_PRIVATE static RefPtr tryCreateUninitialized(unsigned numElements, unsigned elementByteSize); inline void* data(); inline const void* data() const; inline unsigned byteLength() const; + void makeShared(); + void setSharingMode(ArrayBufferSharingMode); + inline bool isShared() const; + inline ArrayBufferSharingMode sharingMode() const { return isShared() ? ArrayBufferSharingMode::Shared : ArrayBufferSharingMode::Default; } + inline size_t gcSizeEstimateInBytes() const; - inline PassRefPtr slice(int begin, int end) const; - inline PassRefPtr slice(int begin) const; + JS_EXPORT_PRIVATE RefPtr slice(int begin, int end) const; + JS_EXPORT_PRIVATE RefPtr slice(int begin) const; inline void pin(); inline void unpin(); + inline void pinAndLock(); - JS_EXPORT_PRIVATE bool transfer(ArrayBufferContents&); + JS_EXPORT_PRIVATE bool transferTo(VM&, ArrayBufferContents&); + JS_EXPORT_PRIVATE bool shareWith(ArrayBufferContents&); bool isNeutered() { return !m_contents.m_data; } static ptrdiff_t offsetOfData() { return OBJECT_OFFSETOF(ArrayBuffer, m_contents) + OBJECT_OFFSETOF(ArrayBufferContents, m_data); } @@ -119,15 +141,17 @@ public: ~ArrayBuffer() { } private: - static inline PassRefPtr create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy); - - inline ArrayBuffer(ArrayBufferContents&); - inline PassRefPtr sliceImpl(unsigned begin, unsigned end) const; + static Ref create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy); + static Ref createInternal(ArrayBufferContents&&, const void*, unsigned); + static RefPtr tryCreate(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy); + ArrayBuffer(ArrayBufferContents&&); + RefPtr sliceImpl(unsigned begin, unsigned end) const; inline unsigned clampIndex(int index) const; static inline int clampValue(int x, int left, int right); - unsigned m_pinCount; ArrayBufferContents m_contents; + unsigned m_pinCount : 31; + bool m_locked : 1; // m_locked == true means that some API user fetched m_contents directly from a TypedArray object. public: Weak m_wrapper; @@ -143,59 +167,6 @@ int ArrayBuffer::clampValue(int x, int left, int right) return x; } -PassRefPtr ArrayBuffer::create(unsigned numElements, unsigned elementByteSize) -{ - return create(numElements, elementByteSize, ArrayBufferContents::ZeroInitialize); -} - -PassRefPtr ArrayBuffer::create(ArrayBuffer* other) -{ - return ArrayBuffer::create(other->data(), other->byteLength()); -} - -PassRefPtr ArrayBuffer::create(const void* source, unsigned byteLength) -{ - ArrayBufferContents contents; - ArrayBufferContents::tryAllocate(byteLength, 1, ArrayBufferContents::ZeroInitialize, contents); - if (!contents.m_data) - return 0; - RefPtr buffer = adoptRef(new ArrayBuffer(contents)); - ASSERT(!byteLength || source); - memcpy(buffer->data(), source, byteLength); - return buffer.release(); -} - -PassRefPtr ArrayBuffer::create(ArrayBufferContents& contents) -{ - return adoptRef(new ArrayBuffer(contents)); -} - -PassRefPtr ArrayBuffer::createAdopted(const void* data, unsigned byteLength) -{ - ArrayBufferContents contents(const_cast(data), byteLength); - return create(contents); -} - -PassRefPtr ArrayBuffer::createUninitialized(unsigned numElements, unsigned elementByteSize) -{ - return create(numElements, elementByteSize, ArrayBufferContents::DontInitialize); -} - -PassRefPtr ArrayBuffer::create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy) -{ - ArrayBufferContents contents; - ArrayBufferContents::tryAllocate(numElements, elementByteSize, policy, contents); - if (!contents.m_data) - return 0; - return adoptRef(new ArrayBuffer(contents)); -} - -ArrayBuffer::ArrayBuffer(ArrayBufferContents& contents) - : m_pinCount(0) -{ - contents.transfer(m_contents); -} - void* ArrayBuffer::data() { return m_contents.m_data; @@ -211,25 +182,15 @@ unsigned ArrayBuffer::byteLength() const return m_contents.m_sizeInBytes; } -size_t ArrayBuffer::gcSizeEstimateInBytes() const -{ - return sizeof(ArrayBuffer) + static_cast(byteLength()); -} - -PassRefPtr ArrayBuffer::slice(int begin, int end) const -{ - return sliceImpl(clampIndex(begin), clampIndex(end)); -} - -PassRefPtr ArrayBuffer::slice(int begin) const +bool ArrayBuffer::isShared() const { - return sliceImpl(clampIndex(begin), byteLength()); + return m_contents.isShared(); } -PassRefPtr ArrayBuffer::sliceImpl(unsigned begin, unsigned end) const +size_t ArrayBuffer::gcSizeEstimateInBytes() const { - unsigned size = begin <= end ? end - begin : 0; - return ArrayBuffer::create(static_cast(data()) + begin, size); + // FIXME: We probably want to scale this by the shared ref count or something. + return sizeof(ArrayBuffer) + static_cast(byteLength()); } unsigned ArrayBuffer::clampIndex(int index) const @@ -250,40 +211,11 @@ void ArrayBuffer::unpin() m_pinCount--; } -void ArrayBufferContents::tryAllocate(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy, ArrayBufferContents& result) +void ArrayBuffer::pinAndLock() { - // Do not allow 31-bit overflow of the total size. - if (numElements) { - unsigned totalSize = numElements * elementByteSize; - if (totalSize / numElements != elementByteSize - || totalSize > static_cast(std::numeric_limits::max())) { - result.m_data = 0; - return; - } - } - bool allocationSucceeded = false; - if (policy == ZeroInitialize) - allocationSucceeded = WTF::tryFastCalloc(numElements, elementByteSize).getValue(result.m_data); - else { - ASSERT(policy == DontInitialize); - allocationSucceeded = WTF::tryFastMalloc(numElements * elementByteSize).getValue(result.m_data); - } - - if (allocationSucceeded) { - result.m_sizeInBytes = numElements * elementByteSize; - return; - } - result.m_data = 0; -} - -ArrayBufferContents::~ArrayBufferContents() -{ - WTF::fastFree(m_data); + m_locked = true; } } // namespace JSC using JSC::ArrayBuffer; - -#endif // ArrayBuffer_h - diff --git a/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp index b11a0ad3a..11279f561 100644 --- a/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp +++ b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp @@ -26,12 +26,12 @@ #include "config.h" #include "ArrayBufferNeuteringWatchpoint.h" -#include "Operations.h" +#include "JSCInlines.h" namespace JSC { const ClassInfo ArrayBufferNeuteringWatchpoint::s_info = { - "ArrayBufferNeuteringWatchpoint", 0, 0, 0, + "ArrayBufferNeuteringWatchpoint", 0, 0, CREATE_METHOD_TABLE(ArrayBufferNeuteringWatchpoint) }; @@ -57,7 +57,12 @@ ArrayBufferNeuteringWatchpoint* ArrayBufferNeuteringWatchpoint::create(VM& vm) Structure* ArrayBufferNeuteringWatchpoint::createStructure(VM& vm) { - return Structure::create(vm, 0, jsNull(), TypeInfo(CompoundType, StructureFlags), info()); + return Structure::create(vm, 0, jsNull(), TypeInfo(CellType, StructureFlags), info()); +} + +void ArrayBufferNeuteringWatchpoint::fireAll() +{ + set()->fireAll(*vm(), "Array buffer was neutered"); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h index 96dbd69c7..263ac772e 100644 --- a/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h +++ b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h @@ -23,38 +23,35 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ArrayBufferNeuteringWatchpoint_h -#define ArrayBufferNeuteringWatchpoint_h +#pragma once #include "JSCell.h" #include "Watchpoint.h" namespace JSC { -class ArrayBufferNeuteringWatchpoint : public JSCell { +class ArrayBufferNeuteringWatchpoint final : public JSCell { public: typedef JSCell Base; - -private: - ArrayBufferNeuteringWatchpoint(VM&); - -public: + static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; + DECLARE_INFO; static ArrayBufferNeuteringWatchpoint* create(VM&); static const bool needsDestruction = true; - static const bool hasImmortalStructure = true; static void destroy(JSCell*); static Structure* createStructure(VM&); WatchpointSet* set() { return m_set.get(); } + + void fireAll(); private: + explicit ArrayBufferNeuteringWatchpoint(VM&); + RefPtr m_set; }; } // namespace JSC - -#endif // ArrayBufferNeuteringWatchpoint_h diff --git a/Source/JavaScriptCore/runtime/ArrayBufferSharingMode.h b/Source/JavaScriptCore/runtime/ArrayBufferSharingMode.h new file mode 100644 index 000000000..0dd14c29b --- /dev/null +++ b/Source/JavaScriptCore/runtime/ArrayBufferSharingMode.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +namespace JSC { + +enum class ArrayBufferSharingMode { + Default, + Shared +}; + +inline const char* arrayBufferSharingModeName(ArrayBufferSharingMode sharingMode) +{ + switch (sharingMode) { + case ArrayBufferSharingMode::Default: + return "ArrayBuffer"; + case ArrayBufferSharingMode::Shared: + return "SharedArrayBuffer"; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; +} + +} // namespace JSC + +namespace WTF { + +inline void printInternal(PrintStream& out, JSC::ArrayBufferSharingMode mode) +{ + out.print(JSC::arrayBufferSharingModeName(mode)); +} + +} // namespace WTF + diff --git a/Source/JavaScriptCore/runtime/ArrayBufferView.cpp b/Source/JavaScriptCore/runtime/ArrayBufferView.cpp index 2332e2663..9fed7c786 100644 --- a/Source/JavaScriptCore/runtime/ArrayBufferView.cpp +++ b/Source/JavaScriptCore/runtime/ArrayBufferView.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,16 +26,14 @@ #include "config.h" #include "ArrayBufferView.h" -#include "ArrayBuffer.h" - namespace JSC { ArrayBufferView::ArrayBufferView( - PassRefPtr buffer, + RefPtr&& buffer, unsigned byteOffset) : m_byteOffset(byteOffset) , m_isNeuterable(true) - , m_buffer(buffer) + , m_buffer(WTFMove(buffer)) { m_baseAddress = m_buffer ? (static_cast(m_buffer->data()) + m_byteOffset) : 0; } diff --git a/Source/JavaScriptCore/runtime/ArrayBufferView.h b/Source/JavaScriptCore/runtime/ArrayBufferView.h index 2b8f70d8b..e76e6e265 100644 --- a/Source/JavaScriptCore/runtime/ArrayBufferView.h +++ b/Source/JavaScriptCore/runtime/ArrayBufferView.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2013, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,14 +23,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ArrayBufferView_h -#define ArrayBufferView_h +#pragma once #include "ArrayBuffer.h" #include "TypedArrayType.h" #include #include -#include #include #include @@ -49,12 +47,26 @@ public: return !m_buffer || m_buffer->isNeutered(); } - PassRefPtr buffer() const + RefPtr possiblySharedBuffer() const { if (isNeutered()) - return 0; + return nullptr; return m_buffer; } + + RefPtr unsharedBuffer() const + { + RefPtr result = possiblySharedBuffer(); + RELEASE_ASSERT(!result->isShared()); + return result; + } + + bool isShared() const + { + if (isNeutered()) + return false; + return m_buffer->isShared(); + } void* baseAddress() const { @@ -63,6 +75,8 @@ public: return m_baseAddress; } + void* data() const { return baseAddress(); } + unsigned byteOffset() const { if (isNeutered()) @@ -77,22 +91,20 @@ public: JS_EXPORT_PRIVATE virtual ~ArrayBufferView(); + // Helper to verify byte offset is size aligned. + static bool verifyByteOffsetAlignment(unsigned byteOffset, size_t size) + { + return !(byteOffset & (size - 1)); + } + // Helper to verify that a given sub-range of an ArrayBuffer is // within range. - // FIXME: This should distinguish between alignment errors and bounds errors. - // https://bugs.webkit.org/show_bug.cgi?id=125391 - template - static bool verifySubRange( - PassRefPtr buffer, - unsigned byteOffset, - unsigned numElements) + static bool verifySubRangeLength(const ArrayBuffer& buffer, unsigned byteOffset, unsigned numElements, size_t size) { - unsigned byteLength = buffer->byteLength(); - if (sizeof(T) > 1 && byteOffset % sizeof(T)) - return false; + unsigned byteLength = buffer.byteLength(); if (byteOffset > byteLength) return false; - unsigned remainingElements = (byteLength - byteOffset) / sizeof(T); + unsigned remainingElements = (byteLength - byteOffset) / size; if (numElements > remainingElements) return false; return true; @@ -101,7 +113,7 @@ public: virtual JSArrayBufferView* wrap(ExecState*, JSGlobalObject*) = 0; protected: - JS_EXPORT_PRIVATE ArrayBufferView(PassRefPtr, unsigned byteOffset); + JS_EXPORT_PRIVATE ArrayBufferView(RefPtr&&, unsigned byteOffset); inline bool setImpl(ArrayBufferView*, unsigned byteOffset); @@ -117,20 +129,20 @@ protected: // output offset is in number of bytes from the underlying buffer's view. template static void clampOffsetAndNumElements( - PassRefPtr buffer, + const ArrayBuffer& buffer, unsigned arrayByteOffset, unsigned *offset, unsigned *numElements) { unsigned maxOffset = (UINT_MAX - arrayByteOffset) / sizeof(T); if (*offset > maxOffset) { - *offset = buffer->byteLength(); + *offset = buffer.byteLength(); *numElements = 0; return; } *offset = arrayByteOffset + *offset * sizeof(T); - *offset = std::min(buffer->byteLength(), *offset); - unsigned remainingElements = (buffer->byteLength() - *offset) / sizeof(T); + *offset = std::min(buffer.byteLength(), *offset); + unsigned remainingElements = (buffer.byteLength() - *offset) / sizeof(T); *numElements = std::min(remainingElements, *numElements); } @@ -209,5 +221,3 @@ void ArrayBufferView::calculateOffsetAndLength( } // namespace JSC using JSC::ArrayBufferView; - -#endif // ArrayBufferView_h diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp index 72fc5619f..0bb86794a 100644 --- a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2007, 2008, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2007-2008, 2011, 2016 Apple Inc. All rights reserved. * Copyright (C) 2003 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) * @@ -26,19 +26,14 @@ #include "ArrayPrototype.h" #include "ButterflyInlines.h" -#include "CopiedSpaceInlines.h" #include "Error.h" #include "ExceptionHelpers.h" +#include "GetterSetter.h" #include "JSArray.h" #include "JSFunction.h" #include "Lookup.h" -#include "Operations.h" - -namespace JSC { - -static EncodedJSValue JSC_HOST_CALL arrayConstructorIsArray(ExecState*); - -} +#include "ProxyObject.h" +#include "JSCInlines.h" #include "ArrayConstructor.lut.h" @@ -46,11 +41,12 @@ namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ArrayConstructor); -const ClassInfo ArrayConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::arrayConstructorTable, CREATE_METHOD_TABLE(ArrayConstructor) }; +const ClassInfo ArrayConstructor::s_info = { "Function", &InternalFunction::s_info, &arrayConstructorTable, CREATE_METHOD_TABLE(ArrayConstructor) }; /* Source for ArrayConstructor.lut.h @begin arrayConstructorTable - isArray arrayConstructorIsArray DontEnum|Function 1 + of JSBuiltin DontEnum|Function 0 + from JSBuiltin DontEnum|Function 0 @end */ @@ -59,71 +55,111 @@ ArrayConstructor::ArrayConstructor(VM& vm, Structure* structure) { } -void ArrayConstructor::finishCreation(VM& vm, ArrayPrototype* arrayPrototype) +void ArrayConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, ArrayPrototype* arrayPrototype, GetterSetter* speciesSymbol) { - Base::finishCreation(vm, arrayPrototype->classInfo()->className); + Base::finishCreation(vm, arrayPrototype->classInfo(vm)->className); putDirectWithoutTransition(vm, vm.propertyNames->prototype, arrayPrototype, DontEnum | DontDelete | ReadOnly); putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum | DontDelete); -} - -bool ArrayConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) -{ - return getStaticFunctionSlot(exec, ExecState::arrayConstructorTable(exec->vm()), jsCast(object), propertyName, slot); + putDirectNonIndexAccessor(vm, vm.propertyNames->speciesSymbol, speciesSymbol, Accessor | ReadOnly | DontEnum); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->isArray, arrayConstructorIsArrayCodeGenerator, DontEnum); } // ------------------------------ Functions --------------------------- -JSObject* constructArrayWithSizeQuirk(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, JSValue length) +JSValue constructArrayWithSizeQuirk(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, JSValue length, JSValue newTarget) { - if (!length.isNumber()) - return constructArrayNegativeIndexed(exec, profile, globalObject, &length, 1); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + if (!length.isNumber()) { + scope.release(); + return constructArrayNegativeIndexed(exec, profile, globalObject, &length, 1, newTarget); + } uint32_t n = length.toUInt32(exec); if (n != length.toNumber(exec)) - return exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer."))); - return constructEmptyArray(exec, profile, globalObject, n); + return throwException(exec, scope, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer."))); + scope.release(); + return constructEmptyArray(exec, profile, globalObject, n, newTarget); } -static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args) +static inline JSValue constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args, JSValue newTarget) { - JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); + JSGlobalObject* globalObject = asInternalFunction(exec->jsCallee())->globalObject(); // a single numeric argument denotes the array size (!) if (args.size() == 1) - return constructArrayWithSizeQuirk(exec, 0, globalObject, args.at(0)); + return constructArrayWithSizeQuirk(exec, nullptr, globalObject, args.at(0), newTarget); // otherwise the array is constructed with the arguments in it - return constructArray(exec, 0, globalObject, args); + return constructArray(exec, nullptr, globalObject, args, newTarget); } static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(ExecState* exec) { ArgList args(exec); - return JSValue::encode(constructArrayWithSizeQuirk(exec, args)); + return JSValue::encode(constructArrayWithSizeQuirk(exec, args, exec->newTarget())); } ConstructType ArrayConstructor::getConstructData(JSCell*, ConstructData& constructData) { constructData.native.function = constructWithArrayConstructor; - return ConstructTypeHost; + return ConstructType::Host; } static EncodedJSValue JSC_HOST_CALL callArrayConstructor(ExecState* exec) { ArgList args(exec); - return JSValue::encode(constructArrayWithSizeQuirk(exec, args)); + return JSValue::encode(constructArrayWithSizeQuirk(exec, args, JSValue())); } CallType ArrayConstructor::getCallData(JSCell*, CallData& callData) { // equivalent to 'new Array(....)' callData.native.function = callArrayConstructor; - return CallTypeHost; + return CallType::Host; +} + +static ALWAYS_INLINE bool isArraySlowInline(ExecState* exec, ProxyObject* proxy) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + while (true) { + if (proxy->isRevoked()) { + throwTypeError(exec, scope, ASCIILiteral("Array.isArray cannot be called on a Proxy that has been revoked")); + return false; + } + JSObject* argument = proxy->target(); + + if (argument->type() == ArrayType || argument->type() == DerivedArrayType) + return true; + + if (argument->type() != ProxyObjectType) + return false; + + proxy = jsCast(argument); + } + + ASSERT_NOT_REACHED(); +} + +bool isArraySlow(ExecState* exec, ProxyObject* argument) +{ + return isArraySlowInline(exec, argument); +} + +// ES6 7.2.2 +// https://tc39.github.io/ecma262/#sec-isarray +EncodedJSValue JSC_HOST_CALL arrayConstructorPrivateFuncIsArraySlow(ExecState* exec) +{ + ASSERT(jsDynamicCast(exec->vm(), exec->argument(0))); + return JSValue::encode(jsBoolean(isArraySlowInline(exec, jsCast(exec->uncheckedArgument(0))))); } -EncodedJSValue JSC_HOST_CALL arrayConstructorIsArray(ExecState* exec) +EncodedJSValue JSC_HOST_CALL arrayConstructorPrivateFuncIsArrayConstructor(ExecState* exec) { - return JSValue::encode(jsBoolean(exec->argument(0).inherits(JSArray::info()))); + VM& vm = exec->vm(); + return JSValue::encode(jsBoolean(jsDynamicCast(vm, exec->uncheckedArgument(0)))); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.h b/Source/JavaScriptCore/runtime/ArrayConstructor.h index a6ac76ea4..6d6d45c8e 100644 --- a/Source/JavaScriptCore/runtime/ArrayConstructor.h +++ b/Source/JavaScriptCore/runtime/ArrayConstructor.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2007-2008, 2011, 2016 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,25 +18,28 @@ * */ -#ifndef ArrayConstructor_h -#define ArrayConstructor_h +#pragma once #include "InternalFunction.h" +#include "ProxyObject.h" +#include "ThrowScope.h" namespace JSC { class ArrayAllocationProfile; class ArrayPrototype; class JSArray; +class GetterSetter; class ArrayConstructor : public InternalFunction { public: typedef InternalFunction Base; + static const unsigned StructureFlags = HasStaticPropertyTable | InternalFunction::StructureFlags; - static ArrayConstructor* create(VM& vm, Structure* structure, ArrayPrototype* arrayPrototype) + static ArrayConstructor* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, ArrayPrototype* arrayPrototype, GetterSetter* speciesSymbol) { ArrayConstructor* constructor = new (NotNull, allocateCell(vm.heap)) ArrayConstructor(vm, structure); - constructor->finishCreation(vm, arrayPrototype); + constructor->finishCreation(vm, globalObject, arrayPrototype, speciesSymbol); return constructor; } @@ -48,19 +51,35 @@ public: } protected: - void finishCreation(VM&, ArrayPrototype*); - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags; + void finishCreation(VM&, JSGlobalObject*, ArrayPrototype*, GetterSetter* speciesSymbol); private: ArrayConstructor(VM&, Structure*); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); static ConstructType getConstructData(JSCell*, ConstructData&); static CallType getCallData(JSCell*, CallData&); }; -JSObject* constructArrayWithSizeQuirk(ExecState*, ArrayAllocationProfile*, JSGlobalObject*, JSValue); +JSValue constructArrayWithSizeQuirk(ExecState*, ArrayAllocationProfile*, JSGlobalObject*, JSValue length, JSValue prototype = JSValue()); -} // namespace JSC +EncodedJSValue JSC_HOST_CALL arrayConstructorPrivateFuncIsArrayConstructor(ExecState*); +EncodedJSValue JSC_HOST_CALL arrayConstructorPrivateFuncIsArraySlow(ExecState*); +bool isArraySlow(ExecState*, ProxyObject* argument); + +// ES6 7.2.2 +// https://tc39.github.io/ecma262/#sec-isarray +inline bool isArray(ExecState* exec, JSValue argumentValue) +{ + if (!argumentValue.isObject()) + return false; + + JSObject* argument = jsCast(argumentValue); + if (argument->type() == ArrayType || argument->type() == DerivedArrayType) + return true; -#endif // ArrayConstructor_h + if (argument->type() != ProxyObjectType) + return false; + return isArraySlow(exec, jsCast(argument)); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayConventions.cpp b/Source/JavaScriptCore/runtime/ArrayConventions.cpp new file mode 100644 index 000000000..69a478902 --- /dev/null +++ b/Source/JavaScriptCore/runtime/ArrayConventions.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ArrayConventions.h" + +#include "JSCInlines.h" + +namespace JSC { + +#if USE(JSVALUE64) +void clearArrayMemset(WriteBarrier* base, unsigned count) +{ +#if CPU(X86_64) && COMPILER(GCC_OR_CLANG) + uint64_t zero = 0; + asm volatile ( + "rep stosq\n\t" + : "+D"(base), "+c"(count) + : "a"(zero) + : "memory" + ); +#else // not CPU(X86_64) + memset(base, 0, count * sizeof(WriteBarrier)); +#endif // generic CPU +} + +void clearArrayMemset(double* base, unsigned count) +{ +#if CPU(X86_64) && COMPILER(GCC_OR_CLANG) + uint64_t pnan = bitwise_cast(PNaN); + asm volatile ( + "rep stosq\n\t" + : "+D"(base), "+c"(count) + : "a"(pnan) + : "memory" + ); +#else // not CPU(X86_64) + // Oh no, we can't actually do any better than this! + for (unsigned i = count; i--;) + base[i] = PNaN; +#endif // generic CPU +} +#endif // USE(JSVALUE64) + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/ArrayConventions.h b/Source/JavaScriptCore/runtime/ArrayConventions.h index e5ef96336..6aacb978c 100644 --- a/Source/JavaScriptCore/runtime/ArrayConventions.h +++ b/Source/JavaScriptCore/runtime/ArrayConventions.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2007, 2008, 2009, 2012, 2016 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,8 +18,7 @@ * */ -#ifndef ArrayConventions_h -#define ArrayConventions_h +#pragma once #include "IndexingHeader.h" #include "WriteBarrier.h" @@ -38,7 +37,7 @@ namespace JSC { // (specifically, this is only one property - the value 0xFFFFFFFFU as an unsigned 32-bit // integer) are not considered array indices and will be stored in the JSObject property map. // -// All properties with a numeric identifer, representable as an unsigned integer i, +// All properties with a numeric identifier, representable as an unsigned integer i, // where (i <= MAX_ARRAY_INDEX), are an array index and will be stored in either the // storage vector or the sparse map. An array index i will be handled in the following // fashion: @@ -58,18 +57,27 @@ namespace JSC { // These values have to be macros to be used in max() and min() without introducing // a PIC branch in Mach-O binaries, see . + +// If you grow an ArrayStorage array by more than this, then the array will go sparse. Note that we +// could probably make this smaller (it's large because it used to be conflated with +// MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH). #define MIN_SPARSE_ARRAY_INDEX 100000U +// If you try to allocate a contiguous array larger than this, then we will allocate an ArrayStorage +// array instead. We allow for an array that occupies 1GB of VM. +#define MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH 1024 * 1024 * 1024 / 8 #define MAX_STORAGE_VECTOR_INDEX (MAX_STORAGE_VECTOR_LENGTH - 1) // 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer. #define MAX_ARRAY_INDEX 0xFFFFFFFEU -// The value BASE_VECTOR_LEN is the maximum number of vector elements we'll allocate +// The value BASE_XXX_VECTOR_LEN is the maximum number of vector elements we'll allocate // for an array that was created with a sepcified length (e.g. a = new Array(123)) -#define BASE_VECTOR_LEN 4U - +#define BASE_CONTIGUOUS_VECTOR_LEN 3U +#define BASE_CONTIGUOUS_VECTOR_LEN_EMPTY 5U +#define BASE_ARRAY_STORAGE_VECTOR_LEN 4U + // The upper bound to the size we'll grow a zero length array when the first element // is added. -#define FIRST_VECTOR_GROW 4U +#define FIRST_ARRAY_STORAGE_VECTOR_GROW 4U #define MIN_BEYOND_LENGTH_SPARSE_INDEX 1000 @@ -89,7 +97,7 @@ inline bool indexIsSufficientlyBeyondLengthForSparseMap(unsigned i, unsigned len return i >= MIN_BEYOND_LENGTH_SPARSE_INDEX && i > length; } -inline IndexingHeader indexingHeaderForArray(unsigned length, unsigned vectorLength) +inline IndexingHeader indexingHeaderForArrayStorage(unsigned length, unsigned vectorLength) { IndexingHeader result; result.setPublicLength(length); @@ -97,12 +105,42 @@ inline IndexingHeader indexingHeaderForArray(unsigned length, unsigned vectorLen return result; } -inline IndexingHeader baseIndexingHeaderForArray(unsigned length) +inline IndexingHeader baseIndexingHeaderForArrayStorage(unsigned length) { - return indexingHeaderForArray(length, BASE_VECTOR_LEN); + return indexingHeaderForArrayStorage(length, BASE_ARRAY_STORAGE_VECTOR_LEN); } -} // namespace JSC +#if USE(JSVALUE64) +JS_EXPORT_PRIVATE void clearArrayMemset(WriteBarrier* base, unsigned count); +JS_EXPORT_PRIVATE void clearArrayMemset(double* base, unsigned count); +#endif // USE(JSVALUE64) + +ALWAYS_INLINE void clearArray(WriteBarrier* base, unsigned count) +{ +#if USE(JSVALUE64) + const unsigned minCountForMemset = 100; + if (count >= minCountForMemset) { + clearArrayMemset(base, count); + return; + } +#endif + + for (unsigned i = count; i--;) + base[i].clear(); +} -#endif // ArrayConventions_h +ALWAYS_INLINE void clearArray(double* base, unsigned count) +{ +#if USE(JSVALUE64) + const unsigned minCountForMemset = 100; + if (count >= minCountForMemset) { + clearArrayMemset(base, count); + return; + } +#endif + + for (unsigned i = count; i--;) + base[i] = PNaN; +} +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayIteratorAdaptiveWatchpoint.cpp b/Source/JavaScriptCore/runtime/ArrayIteratorAdaptiveWatchpoint.cpp new file mode 100644 index 000000000..1fc8a7a6f --- /dev/null +++ b/Source/JavaScriptCore/runtime/ArrayIteratorAdaptiveWatchpoint.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ArrayIteratorAdaptiveWatchpoint.h" + +#include "JSGlobalObject.h" + +namespace JSC { + +ArrayIteratorAdaptiveWatchpoint::ArrayIteratorAdaptiveWatchpoint(const ObjectPropertyCondition& condition, JSGlobalObject* globalObject) + : Base(condition) + , m_globalObject(globalObject) +{ + RELEASE_ASSERT(m_globalObject->arrayIteratorProtocolWatchpoint().stateOnJSThread() == IsWatched); +} + +void ArrayIteratorAdaptiveWatchpoint::handleFire(const FireDetail&) +{ + m_globalObject->arrayIteratorProtocolWatchpoint().fireAll(m_globalObject->vm(), StringFireDetail("Array iterator protocol changed.")); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayIteratorAdaptiveWatchpoint.h b/Source/JavaScriptCore/runtime/ArrayIteratorAdaptiveWatchpoint.h new file mode 100644 index 000000000..a45cce2c4 --- /dev/null +++ b/Source/JavaScriptCore/runtime/ArrayIteratorAdaptiveWatchpoint.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "AdaptiveInferredPropertyValueWatchpointBase.h" + +namespace JSC { + +class JSGlobalObject; + +class ArrayIteratorAdaptiveWatchpoint : public AdaptiveInferredPropertyValueWatchpointBase { +public: + typedef AdaptiveInferredPropertyValueWatchpointBase Base; + ArrayIteratorAdaptiveWatchpoint(const ObjectPropertyCondition&, JSGlobalObject*); + +private: + void handleFire(const FireDetail&) override; + + JSGlobalObject* m_globalObject; +}; + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayIteratorConstructor.cpp b/Source/JavaScriptCore/runtime/ArrayIteratorConstructor.cpp deleted file mode 100644 index 0916eeef2..000000000 --- a/Source/JavaScriptCore/runtime/ArrayIteratorConstructor.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2013 Apple, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "ArrayIteratorConstructor.h" - -#include "JSCJSValueInlines.h" -#include "JSCellInlines.h" -#include "JSGlobalObject.h" - -namespace JSC { - -const ClassInfo ArrayIteratorConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ArrayIteratorConstructor) }; - -void ArrayIteratorConstructor::finishCreation(VM& vm) -{ - Base::finishCreation(vm); -} - -} diff --git a/Source/JavaScriptCore/runtime/ArrayIteratorConstructor.h b/Source/JavaScriptCore/runtime/ArrayIteratorConstructor.h deleted file mode 100644 index 489d5d9e9..000000000 --- a/Source/JavaScriptCore/runtime/ArrayIteratorConstructor.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2013 Apple, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ArrayIteratorConstructor_h -#define ArrayIteratorConstructor_h - -#include "InternalFunction.h" - -namespace JSC { - -class ArrayIteratorPrototype; - -class ArrayIteratorConstructor : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; - - static ArrayIteratorConstructor* create(VM& vm, Structure* structure, ArrayIteratorPrototype*) - { - ArrayIteratorConstructor* constructor = new (NotNull, allocateCell(vm.heap)) ArrayIteratorConstructor(vm, structure); - constructor->finishCreation(vm); - return constructor; - } - - DECLARE_INFO; - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); - } - -private: - ArrayIteratorConstructor(VM& vm, Structure* structure) - : Base(vm, structure) - { - } - void finishCreation(VM&); -}; - -} - -#endif // !defined(ArrayIteratorConstructor_h) diff --git a/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp index 1ccb791b7..87807ff19 100644 --- a/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp @@ -20,36 +20,39 @@ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "ArrayIteratorPrototype.h" -#include "JSArrayIterator.h" +#include "ArrayIteratorPrototype.lut.h" +#include "IteratorOperations.h" +#include "JSCInlines.h" #include "JSCJSValueInlines.h" #include "JSCellInlines.h" #include "JSGlobalObject.h" #include "ObjectConstructor.h" +#include "StructureInlines.h" namespace JSC { -const ClassInfo ArrayIteratorPrototype::s_info = { "Array Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ArrayIteratorPrototype) }; +const ClassInfo ArrayIteratorPrototype::s_info = { "Array Iterator", &Base::s_info, &arrayIteratorPrototypeTable, CREATE_METHOD_TABLE(ArrayIteratorPrototype) }; -static EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeIterate(ExecState*); +/* Source for ArrayIteratorPrototype.lut.h +@begin arrayIteratorPrototypeTable + next JSBuiltin DontEnum|Function 0 +@end +*/ -void ArrayIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) +void ArrayIteratorPrototype::finishCreation(VM& vm, JSGlobalObject*) { Base::finishCreation(vm); - ASSERT(inherits(info())); + ASSERT(inherits(vm, info())); + putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Array Iterator"), DontEnum | ReadOnly); vm.prototypeMap.addPrototype(this); - - JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, arrayIteratorPrototypeIterate, DontEnum, 0); } -EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeIterate(CallFrame* callFrame) -{ - return JSValue::encode(callFrame->thisValue()); -} +// ------------------------------ Array Functions ---------------------------- -} +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.h b/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.h index 10ee9a6a2..b0f0f66e2 100644 --- a/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.h +++ b/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.h @@ -23,9 +23,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ArrayIteratorPrototype_h -#define ArrayIteratorPrototype_h +#pragma once +#include "IterationKind.h" #include "JSObject.h" namespace JSC { @@ -33,6 +33,7 @@ namespace JSC { class ArrayIteratorPrototype : public JSNonFinalObject { public: typedef JSNonFinalObject Base; + static const unsigned StructureFlags = HasStaticPropertyTable | Base::StructureFlags; static ArrayIteratorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) { @@ -53,9 +54,8 @@ private: : Base(vm, structure) { } + void finishCreation(VM&, JSGlobalObject*); }; -} - -#endif // !defined(ArrayIteratorPrototype_h) +} // namespcae JSc diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp index c8659eee2..8bae0a60a 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2007, 2008, 2009, 2011, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2003-2017 Apple Inc. All rights reserved. * Copyright (C) 2003 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) * @@ -24,107 +24,51 @@ #include "config.h" #include "ArrayPrototype.h" +#include "AdaptiveInferredPropertyValueWatchpointBase.h" +#include "ArrayConstructor.h" +#include "BuiltinNames.h" #include "ButterflyInlines.h" -#include "CachedCall.h" #include "CodeBlock.h" -#include "CopiedSpaceInlines.h" #include "Error.h" +#include "GetterSetter.h" #include "Interpreter.h" #include "JIT.h" -#include "JSArrayIterator.h" +#include "JSArrayInlines.h" +#include "JSCBuiltins.h" +#include "JSCInlines.h" #include "JSStringBuilder.h" #include "JSStringJoiner.h" #include "Lookup.h" +#include "ObjectConstructor.h" #include "ObjectPrototype.h" #include "Operations.h" #include "StringRecursionChecker.h" #include #include -#include namespace JSC { -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncValues(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncKeys(ExecState*); -static EncodedJSValue JSC_HOST_CALL arrayProtoFuncEntries(ExecState*); - -} - -#include "ArrayPrototype.lut.h" - -namespace JSC { - -static inline bool isNumericCompareFunction(ExecState* exec, CallType callType, const CallData& callData) -{ - if (callType != CallTypeJS) - return false; - - FunctionExecutable* executable = callData.js.functionExecutable; - - JSObject* error = executable->prepareForExecution(exec, callData.js.scope, CodeForCall); - if (error) - return false; - - return executable->codeBlockForCall()->isNumericCompareFunction(); -} +EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState*); +EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState*); +EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState*); +EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState*); +EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState*); +EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState*); +EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState*); +EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState*); +EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState*); +EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState*); +EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState*); // ------------------------------ ArrayPrototype ---------------------------- -const ClassInfo ArrayPrototype::s_info = {"Array", &JSArray::s_info, 0, ExecState::arrayPrototypeTable, CREATE_METHOD_TABLE(ArrayPrototype)}; - -/* Source for ArrayPrototype.lut.h -@begin arrayPrototypeTable 16 - toString arrayProtoFuncToString DontEnum|Function 0 - toLocaleString arrayProtoFuncToLocaleString DontEnum|Function 0 - concat arrayProtoFuncConcat DontEnum|Function 1 - join arrayProtoFuncJoin DontEnum|Function 1 - pop arrayProtoFuncPop DontEnum|Function 0 - push arrayProtoFuncPush DontEnum|Function 1 - reverse arrayProtoFuncReverse DontEnum|Function 0 - shift arrayProtoFuncShift DontEnum|Function 0 - slice arrayProtoFuncSlice DontEnum|Function 2 - sort arrayProtoFuncSort DontEnum|Function 1 - splice arrayProtoFuncSplice DontEnum|Function 2 - unshift arrayProtoFuncUnShift DontEnum|Function 1 - every arrayProtoFuncEvery DontEnum|Function 1 - forEach arrayProtoFuncForEach DontEnum|Function 1 - some arrayProtoFuncSome DontEnum|Function 1 - indexOf arrayProtoFuncIndexOf DontEnum|Function 1 - lastIndexOf arrayProtoFuncLastIndexOf DontEnum|Function 1 - filter arrayProtoFuncFilter DontEnum|Function 1 - reduce arrayProtoFuncReduce DontEnum|Function 1 - reduceRight arrayProtoFuncReduceRight DontEnum|Function 1 - map arrayProtoFuncMap DontEnum|Function 1 - entries arrayProtoFuncEntries DontEnum|Function 0 - keys arrayProtoFuncKeys DontEnum|Function 0 -@end -*/ +const ClassInfo ArrayPrototype::s_info = {"Array", &JSArray::s_info, nullptr, CREATE_METHOD_TABLE(ArrayPrototype)}; ArrayPrototype* ArrayPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure) { ArrayPrototype* prototype = new (NotNull, allocateCell(vm.heap)) ArrayPrototype(vm, structure); prototype->finishCreation(vm, globalObject); + vm.heap.addFinalizer(prototype, destroy); return prototype; } @@ -137,34 +81,184 @@ ArrayPrototype::ArrayPrototype(VM& vm, Structure* structure) void ArrayPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) { Base::finishCreation(vm); - ASSERT(inherits(info())); + ASSERT(inherits(vm, info())); vm.prototypeMap.addPrototype(this); - JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, arrayProtoFuncValues, DontEnum, 0); + + putDirectWithoutTransition(vm, vm.propertyNames->toString, globalObject->arrayProtoToStringFunction(), DontEnum); + putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().valuesPublicName(), globalObject->arrayProtoValuesFunction(), DontEnum); + putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, globalObject->arrayProtoValuesFunction(), DontEnum); + + JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toLocaleString, arrayProtoFuncToLocaleString, DontEnum, 0); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("concat", arrayPrototypeConcatCodeGenerator, DontEnum); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("fill", arrayPrototypeFillCodeGenerator, DontEnum); + JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->join, arrayProtoFuncJoin, DontEnum, 1); + JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("pop", arrayProtoFuncPop, DontEnum, 0, ArrayPopIntrinsic); + JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().pushPublicName(), arrayProtoFuncPush, DontEnum, 1, ArrayPushIntrinsic); + JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().pushPrivateName(), arrayProtoFuncPush, DontEnum | DontDelete | ReadOnly, 1, ArrayPushIntrinsic); + JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("reverse", arrayProtoFuncReverse, DontEnum, 0); + JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().shiftPublicName(), arrayProtoFuncShift, DontEnum, 0); + JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().shiftPrivateName(), arrayProtoFuncShift, DontEnum | DontDelete | ReadOnly, 0); + JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->slice, arrayProtoFuncSlice, DontEnum, 2, ArraySliceIntrinsic); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("sort", arrayPrototypeSortCodeGenerator, DontEnum); + JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("splice", arrayProtoFuncSplice, DontEnum, 2); + JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("unshift", arrayProtoFuncUnShift, DontEnum, 1); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("every", arrayPrototypeEveryCodeGenerator, DontEnum); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("forEach", arrayPrototypeForEachCodeGenerator, DontEnum); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("some", arrayPrototypeSomeCodeGenerator, DontEnum); + JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("indexOf", arrayProtoFuncIndexOf, DontEnum, 1); + JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("lastIndexOf", arrayProtoFuncLastIndexOf, DontEnum, 1); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("filter", arrayPrototypeFilterCodeGenerator, DontEnum); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("reduce", arrayPrototypeReduceCodeGenerator, DontEnum); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("reduceRight", arrayPrototypeReduceRightCodeGenerator, DontEnum); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("map", arrayPrototypeMapCodeGenerator, DontEnum); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().entriesPublicName(), arrayPrototypeEntriesCodeGenerator, DontEnum); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().keysPublicName(), arrayPrototypeKeysCodeGenerator, DontEnum); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("find", arrayPrototypeFindCodeGenerator, DontEnum); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("findIndex", arrayPrototypeFindIndexCodeGenerator, DontEnum); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("includes", arrayPrototypeIncludesCodeGenerator, DontEnum); + JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("copyWithin", arrayPrototypeCopyWithinCodeGenerator, DontEnum); + + putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().entriesPrivateName(), getDirect(vm, vm.propertyNames->builtinNames().entriesPublicName()), ReadOnly); + putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().forEachPrivateName(), getDirect(vm, vm.propertyNames->builtinNames().forEachPublicName()), ReadOnly); + putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().keysPrivateName(), getDirect(vm, vm.propertyNames->builtinNames().keysPublicName()), ReadOnly); + putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().valuesPrivateName(), globalObject->arrayProtoValuesFunction(), ReadOnly); + + JSObject* unscopables = constructEmptyObject(globalObject->globalExec(), globalObject->nullPrototypeObjectStructure()); + const char* unscopableNames[] = { + "copyWithin", + "entries", + "fill", + "find", + "findIndex", + "includes", + "keys", + "values" + }; + for (const char* unscopableName : unscopableNames) + unscopables->putDirect(vm, Identifier::fromString(&vm, unscopableName), jsBoolean(true)); + putDirectWithoutTransition(vm, vm.propertyNames->unscopablesSymbol, unscopables, DontEnum | ReadOnly); } -bool ArrayPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) +void ArrayPrototype::destroy(JSC::JSCell* cell) { - return getStaticFunctionSlot(exec, ExecState::arrayPrototypeTable(exec->vm()), jsCast(object), propertyName, slot); + ArrayPrototype* thisObject = static_cast(cell); + thisObject->ArrayPrototype::~ArrayPrototype(); } // ------------------------------ Array Functions ---------------------------- -// Helper function -static JSValue getProperty(ExecState* exec, JSObject* obj, unsigned index) +static ALWAYS_INLINE JSValue getProperty(ExecState* exec, JSObject* object, unsigned index) { - PropertySlot slot(obj); - if (!obj->getPropertySlot(exec, index, slot)) - return JSValue(); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (JSValue result = object->tryGetIndexQuickly(index)) + return result; + // We want to perform get and has in the same operation. + // We can only do so when this behavior is not observable. The + // only time it is observable is when we encounter an opaque objects (ProxyObject and JSModuleNamespaceObject) + // somewhere in the prototype chain. + PropertySlot slot(object, PropertySlot::InternalMethodType::HasProperty); + bool hasProperty = object->getPropertySlot(exec, index, slot); + ASSERT(!scope.exception() || !hasProperty); + if (!hasProperty) + return { }; + if (UNLIKELY(slot.isTaintedByOpaqueObject())) { + scope.release(); + return object->get(exec, index); + } + scope.release(); return slot.getValue(exec, index); } -static void putProperty(ExecState* exec, JSObject* obj, PropertyName propertyName, JSValue value) +static ALWAYS_INLINE bool putLength(ExecState* exec, VM& vm, JSObject* obj, JSValue value) { PutPropertySlot slot(obj); - obj->methodTable()->put(obj, exec, propertyName, value, slot); + return obj->methodTable(vm)->put(obj, exec, vm.propertyNames->length, value, slot); +} + +static ALWAYS_INLINE void setLength(ExecState* exec, VM& vm, JSObject* obj, unsigned value) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + static const bool throwException = true; + if (isJSArray(obj)) { + jsCast(obj)->setLength(exec, value, throwException); + RETURN_IF_EXCEPTION(scope, void()); + } + bool success = putLength(exec, vm, obj, jsNumber(value)); + RETURN_IF_EXCEPTION(scope, void()); + if (UNLIKELY(!success)) + throwTypeError(exec, scope, ASCIILiteral(ReadonlyPropertyWriteError)); +} + +ALWAYS_INLINE bool speciesWatchpointIsValid(ExecState* exec, JSObject* thisObject) +{ + JSGlobalObject* globalObject = thisObject->globalObject(); + ArrayPrototype* arrayPrototype = globalObject->arrayPrototype(); + + if (globalObject->arraySpeciesWatchpoint().stateOnJSThread() == ClearWatchpoint) { + arrayPrototype->tryInitializeSpeciesWatchpoint(exec); + ASSERT(globalObject->arraySpeciesWatchpoint().stateOnJSThread() != ClearWatchpoint); + } + + return !thisObject->hasCustomProperties() + && arrayPrototype == thisObject->getPrototypeDirect() + && globalObject->arraySpeciesWatchpoint().stateOnJSThread() == IsWatched; +} + +enum class SpeciesConstructResult { + FastPath, + Exception, + CreatedObject +}; + +static ALWAYS_INLINE std::pair speciesConstructArray(ExecState* exec, JSObject* thisObject, unsigned length) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto exceptionResult = [] () { + return std::make_pair(SpeciesConstructResult::Exception, nullptr); + }; + + // ECMA 9.4.2.3: https://tc39.github.io/ecma262/#sec-arrayspeciescreate + JSValue constructor = jsUndefined(); + bool thisIsArray = isArray(exec, thisObject); + RETURN_IF_EXCEPTION(scope, exceptionResult()); + if (LIKELY(thisIsArray)) { + // Fast path in the normal case where the user has not set an own constructor and the Array.prototype.constructor is normal. + // We need prototype check for subclasses of Array, which are Array objects but have a different prototype by default. + bool isValid = speciesWatchpointIsValid(exec, thisObject); + if (LIKELY(isValid)) + return std::make_pair(SpeciesConstructResult::FastPath, nullptr); + + constructor = thisObject->get(exec, vm.propertyNames->constructor); + RETURN_IF_EXCEPTION(scope, exceptionResult()); + if (constructor.isConstructor()) { + JSObject* constructorObject = jsCast(constructor); + if (exec->lexicalGlobalObject() != constructorObject->globalObject()) + return std::make_pair(SpeciesConstructResult::FastPath, nullptr);; + } + if (constructor.isObject()) { + constructor = constructor.get(exec, vm.propertyNames->speciesSymbol); + RETURN_IF_EXCEPTION(scope, exceptionResult()); + if (constructor.isNull()) + return std::make_pair(SpeciesConstructResult::FastPath, nullptr);; + } + } else + RETURN_IF_EXCEPTION(scope, exceptionResult()); + + if (constructor.isUndefined()) + return std::make_pair(SpeciesConstructResult::FastPath, nullptr); + + MarkedArgumentBuffer args; + args.append(jsNumber(length)); + JSObject* newObject = construct(exec, constructor, args, "Species construction did not get a valid constructor"); + RETURN_IF_EXCEPTION(scope, exceptionResult()); + return std::make_pair(SpeciesConstructResult::CreatedObject, newObject); } -static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0) +static inline unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0) { JSValue value = exec->argument(argument); if (value.isUndefined()) @@ -178,7 +272,6 @@ static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument return indexDouble > length ? length : static_cast(indexDouble); } - // The shift/unshift function implement the shift/unshift behaviour required // by the corresponding array prototype methods, and by splice. In both cases, // the methods are operating an an array or array like object. @@ -193,9 +286,13 @@ static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument // currentCount) will be shifted to the left or right as appropriate; in the // case of shift this must be removing values, in the case of unshift this // must be introducing new values. + template void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length) { + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + RELEASE_ASSERT(currentCount > resultCount); unsigned count = currentCount - resultCount; @@ -204,36 +301,43 @@ void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned current if (isJSArray(thisObj)) { JSArray* array = asArray(thisObj); - if (array->length() == length && asArray(thisObj)->shiftCount(exec, header, count)) + if (array->length() == length && array->shiftCount(exec, header, count)) return; } for (unsigned k = header; k < length - currentCount; ++k) { unsigned from = k + currentCount; unsigned to = k + resultCount; - PropertySlot slot(thisObj); - if (thisObj->getPropertySlot(exec, from, slot)) { - JSValue value = slot.getValue(exec, from); - if (exec->hadException()) - return; - thisObj->methodTable()->putByIndex(thisObj, exec, to, value, true); - if (exec->hadException()) + JSValue value = getProperty(exec, thisObj, from); + RETURN_IF_EXCEPTION(scope, void()); + if (value) { + thisObj->putByIndexInline(exec, to, value, true); + RETURN_IF_EXCEPTION(scope, void()); + } else { + bool success = thisObj->methodTable(vm)->deletePropertyByIndex(thisObj, exec, to); + RETURN_IF_EXCEPTION(scope, void()); + if (!success) { + throwTypeError(exec, scope, ASCIILiteral(UnableToDeletePropertyError)); return; - } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, to)) { - throwTypeError(exec, ASCIILiteral("Unable to delete property.")); - return; + } } } for (unsigned k = length; k > length - count; --k) { - if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k - 1)) { - throwTypeError(exec, ASCIILiteral("Unable to delete property.")); + bool success = thisObj->methodTable(vm)->deletePropertyByIndex(thisObj, exec, k - 1); + RETURN_IF_EXCEPTION(scope, void()); + if (!success) { + throwTypeError(exec, scope, ASCIILiteral(UnableToDeletePropertyError)); return; } } } + template void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length) { + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + RELEASE_ASSERT(resultCount > currentCount); unsigned count = resultCount - currentCount; @@ -242,1118 +346,1125 @@ void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned curre // Guard against overflow. if (count > (UINT_MAX - length)) { - throwOutOfMemoryError(exec); + throwOutOfMemoryError(exec, scope); return; } if (isJSArray(thisObj)) { JSArray* array = asArray(thisObj); - if (array->length() == length && array->unshiftCount(exec, header, count)) - return; + if (array->length() == length) { + bool handled = array->unshiftCount(exec, header, count); + ASSERT(!scope.exception() || handled); + if (handled) + return; + } } - + for (unsigned k = length - currentCount; k > header; --k) { unsigned from = k + currentCount - 1; unsigned to = k + resultCount - 1; - PropertySlot slot(thisObj); - if (thisObj->getPropertySlot(exec, from, slot)) { - JSValue value = slot.getValue(exec, from); - if (exec->hadException()) + JSValue value = getProperty(exec, thisObj, from); + RETURN_IF_EXCEPTION(scope, void()); + if (value) { + thisObj->putByIndexInline(exec, to, value, true); + RETURN_IF_EXCEPTION(scope, void()); + } else { + bool success = thisObj->methodTable(vm)->deletePropertyByIndex(thisObj, exec, to); + RETURN_IF_EXCEPTION(scope, void()); + if (UNLIKELY(!success)) { + throwTypeError(exec, scope, ASCIILiteral(UnableToDeletePropertyError)); return; - thisObj->methodTable()->putByIndex(thisObj, exec, to, value, true); - } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, to)) { - throwTypeError(exec, ASCIILiteral("Unable to delete property.")); - return; + } } - if (exec->hadException()) - return; } } EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec) { - JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); // 1. Let array be the result of calling ToObject on the this value. JSObject* thisObject = thisValue.toObject(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); // 2. Let func be the result of calling the [[Get]] internal method of array with argument "join". - JSValue function = JSValue(thisObject).get(exec, exec->propertyNames().join); + JSValue function = JSValue(thisObject).get(exec, vm.propertyNames->join); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); // 3. If IsCallable(func) is false, then let func be the standard built-in method Object.prototype.toString (15.2.4.2). + bool customJoinCase = false; if (!function.isCell()) - return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable()->className(thisObject), "]")); + customJoinCase = true; CallData callData; CallType callType = getCallData(function, callData); - if (callType == CallTypeNone) - return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable()->className(thisObject), "]")); + if (callType == CallType::None) + customJoinCase = true; + + if (UNLIKELY(customJoinCase)) { + scope.release(); + return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable(vm)->className(thisObject), "]")); + } // 4. Return the result of calling the [[Call]] internal method of func providing array as the this value and an empty arguments list. - if (!isJSArray(thisObject) || callType != CallTypeHost || callData.native.function != arrayProtoFuncJoin) + if (!isJSArray(thisObject) || callType != CallType::Host || callData.native.function != arrayProtoFuncJoin) { + scope.release(); return JSValue::encode(call(exec, function, callType, callData, thisObject, exec->emptyList())); + } ASSERT(isJSArray(thisValue)); - JSArray* thisObj = asArray(thisValue); - - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + JSArray* thisArray = asArray(thisValue); + + unsigned length = thisArray->length(); - StringRecursionChecker checker(exec, thisObj); + StringRecursionChecker checker(exec, thisArray); + ASSERT(!scope.exception() || checker.earlyReturnValue()); if (JSValue earlyReturnValue = checker.earlyReturnValue()) return JSValue::encode(earlyReturnValue); - String separator(",", String::ConstructFromLiteral); - JSStringJoiner stringJoiner(separator, length); - for (unsigned k = 0; k < length; k++) { - JSValue element; - if (thisObj->canGetIndexQuickly(k)) - element = thisObj->getIndexQuickly(k); - else { - element = thisObj->get(exec, k); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - } - - if (element.isUndefinedOrNull()) - stringJoiner.append(String()); - else - stringJoiner.append(element.toWTFString(exec)); + JSStringJoiner joiner(*exec, ',', length); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + for (unsigned i = 0; i < length; ++i) { + JSValue element = thisArray->tryGetIndexQuickly(i); + if (!element) { + element = thisArray->get(exec, i); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } + joiner.append(*exec, element); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); } - return JSValue::encode(stringJoiner.join(exec)); + + scope.release(); + return JSValue::encode(joiner.join(*exec)); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec) { - JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); - JSObject* thisObj = thisValue.toObject(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + JSObject* thisObject = thisValue.toObject(exec); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + unsigned length = getLength(exec, thisObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); - StringRecursionChecker checker(exec, thisObj); + StringRecursionChecker checker(exec, thisObject); + ASSERT(!scope.exception() || checker.earlyReturnValue()); if (JSValue earlyReturnValue = checker.earlyReturnValue()) return JSValue::encode(earlyReturnValue); - String separator(",", String::ConstructFromLiteral); - JSStringJoiner stringJoiner(separator, length); - for (unsigned k = 0; k < length; k++) { - JSValue element = thisObj->get(exec, k); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - if (!element.isUndefinedOrNull()) { - JSObject* o = element.toObject(exec); - JSValue conversionFunction = o->get(exec, exec->propertyNames().toLocaleString); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - String str; + JSStringJoiner stringJoiner(*exec, ',', length); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + +#if ENABLE(INTL) + ArgList arguments(exec); + for (unsigned i = 0; i < length; ++i) { + JSValue element = thisObject->getIndex(exec, i); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (element.isUndefinedOrNull()) + element = jsEmptyString(exec); + else { + JSValue conversionFunction = element.get(exec, vm.propertyNames->toLocaleString); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); CallData callData; CallType callType = getCallData(conversionFunction, callData); - if (callType != CallTypeNone) - str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toWTFString(exec); - else - str = element.toWTFString(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - stringJoiner.append(str); + if (callType != CallType::None) { + element = call(exec, conversionFunction, callType, callData, element, arguments); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } } + stringJoiner.append(*exec, element); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); } +#else // !ENABLE(INTL) + for (unsigned i = 0; i < length; ++i) { + JSValue element = thisObject->getIndex(exec, i); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (element.isUndefinedOrNull()) + continue; + JSValue conversionFunction = element.get(exec, vm.propertyNames->toLocaleString); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + CallData callData; + CallType callType = getCallData(conversionFunction, callData); + if (callType != CallType::None) { + element = call(exec, conversionFunction, callType, callData, element, exec->emptyList()); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } + stringJoiner.append(*exec, element); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } +#endif // !ENABLE(INTL) - return JSValue::encode(stringJoiner.join(exec)); + scope.release(); + return JSValue::encode(stringJoiner.join(*exec)); } -EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) +static inline bool isHole(double value) { - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + return std::isnan(value); +} - StringRecursionChecker checker(exec, thisObj); - if (JSValue earlyReturnValue = checker.earlyReturnValue()) - return JSValue::encode(earlyReturnValue); +static inline bool isHole(const WriteBarrier& value) +{ + return !value; +} - String separator; - if (!exec->argument(0).isUndefined()) - separator = exec->argument(0).toWTFString(exec); - if (separator.isNull()) - separator = String(",", String::ConstructFromLiteral); +template static inline bool containsHole(T* data, unsigned length) +{ + for (unsigned i = 0; i < length; ++i) { + if (isHole(data[i])) + return true; + } + return false; +} - JSStringJoiner stringJoiner(separator, length); +static inline bool holesMustForwardToPrototype(ExecState& state, JSObject* object) +{ + auto& vm = state.vm(); + return object->structure(vm)->holesMustForwardToPrototype(vm); +} - unsigned k = 0; - if (isJSArray(thisObj)) { - JSArray* array = asArray(thisObj); +static JSValue slowJoin(ExecState& exec, JSObject* thisObject, JSString* separator, uint64_t length) +{ + VM& vm = exec.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); - for (; k < length; k++) { - if (!array->canGetIndexQuickly(k)) - break; + // 5. If len is zero, return the empty String. + if (!length) + return jsEmptyString(&exec); - JSValue element = array->getIndexQuickly(k); - if (!element.isUndefinedOrNull()) - stringJoiner.append(element.toWTFStringInline(exec)); - else - stringJoiner.append(String()); - } - } + // 6. Let element0 be Get(O, "0"). + JSValue element0 = thisObject->getIndex(&exec, 0); + RETURN_IF_EXCEPTION(scope, { }); - for (; k < length; k++) { - JSValue element = thisObj->get(exec, k); - if (!element.isUndefinedOrNull()) - stringJoiner.append(element.toWTFStringInline(exec)); - else - stringJoiner.append(String()); + // 7. If element0 is undefined or null, let R be the empty String; otherwise, let R be ? ToString(element0). + JSString* r = nullptr; + if (element0.isUndefinedOrNull()) + r = jsEmptyString(&exec); + else + r = element0.toString(&exec); + RETURN_IF_EXCEPTION(scope, { }); + + // 8. Let k be 1. + // 9. Repeat, while k < len + // 9.e Increase k by 1.. + for (uint64_t k = 1; k < length; ++k) { + // b. Let element be ? Get(O, ! ToString(k)). + JSValue element = thisObject->get(&exec, Identifier::fromString(&exec, AtomicString::number(k))); + RETURN_IF_EXCEPTION(scope, { }); + + // c. If element is undefined or null, let next be the empty String; otherwise, let next be ? ToString(element). + JSString* next = nullptr; + if (element.isUndefinedOrNull()) { + if (!separator->length()) + continue; + next = jsEmptyString(&exec); + } else + next = element.toString(&exec); + RETURN_IF_EXCEPTION(scope, { }); + + // a. Let S be the String value produced by concatenating R and sep. + // d. Let R be a String value produced by concatenating S and next. + r = jsString(&exec, r, separator, next); + RETURN_IF_EXCEPTION(scope, { }); } + // 10. Return R. + return r; +} - return JSValue::encode(stringJoiner.join(exec)); +static inline bool canUseFastJoin(const JSObject* thisObject) +{ + switch (thisObject->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + case ALL_INT32_INDEXING_TYPES: + case ALL_DOUBLE_INDEXING_TYPES: + return true; + default: + break; + } + return false; } -EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec) +static inline JSValue fastJoin(ExecState& state, JSObject* thisObject, StringView separator, unsigned length) { - JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode); - JSArray* arr = constructEmptyArray(exec, 0); - unsigned n = 0; - JSValue curArg = thisValue.toObject(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - size_t i = 0; - size_t argCount = exec->argumentCount(); - while (1) { - if (curArg.inherits(JSArray::info())) { - unsigned length = curArg.get(exec, exec->propertyNames().length).toUInt32(exec); - JSObject* curObject = curArg.toObject(exec); - for (unsigned k = 0; k < length; ++k) { - JSValue v = getProperty(exec, curObject, k); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - if (v) - arr->putDirectIndex(exec, n, v); - n++; + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + switch (thisObject->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + case ALL_INT32_INDEXING_TYPES: { + auto& butterfly = *thisObject->butterfly(); + if (length > butterfly.publicLength()) + break; + JSStringJoiner joiner(state, separator, length); + RETURN_IF_EXCEPTION(scope, { }); + auto data = butterfly.contiguous().data(); + bool holesKnownToBeOK = false; + for (unsigned i = 0; i < length; ++i) { + if (JSValue value = data[i].get()) { + if (!joiner.appendWithoutSideEffects(state, value)) + goto generalCase; + } else { + if (!holesKnownToBeOK) { + if (holesMustForwardToPrototype(state, thisObject)) + goto generalCase; + holesKnownToBeOK = true; + } + joiner.appendEmptyString(); } - } else { - arr->putDirectIndex(exec, n, curArg); - n++; } - if (i == argCount) + scope.release(); + return joiner.join(state); + } + case ALL_DOUBLE_INDEXING_TYPES: { + auto& butterfly = *thisObject->butterfly(); + if (length > butterfly.publicLength()) break; - curArg = exec->uncheckedArgument(i); - ++i; + JSStringJoiner joiner(state, separator, length); + RETURN_IF_EXCEPTION(scope, { }); + auto data = butterfly.contiguousDouble().data(); + bool holesKnownToBeOK = false; + for (unsigned i = 0; i < length; ++i) { + double value = data[i]; + if (!isHole(value)) + joiner.append(state, jsDoubleNumber(value)); + else { + if (!holesKnownToBeOK) { + if (thisObject->structure(vm)->holesMustForwardToPrototype(vm)) + goto generalCase; + holesKnownToBeOK = true; + } + joiner.appendEmptyString(); + } + } + scope.release(); + return joiner.join(state); + } + } + +generalCase: + JSStringJoiner joiner(state, separator, length); + RETURN_IF_EXCEPTION(scope, { }); + for (unsigned i = 0; i < length; ++i) { + JSValue element = thisObject->getIndex(&state, i); + RETURN_IF_EXCEPTION(scope, { }); + joiner.append(state, element); + RETURN_IF_EXCEPTION(scope, { }); + } + scope.release(); + return joiner.join(state); +} + +EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + // 1. Let O be ? ToObject(this value). + JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); + ASSERT(!!scope.exception() == !thisObject); + if (UNLIKELY(!thisObject)) + return encodedJSValue(); + + StringRecursionChecker checker(exec, thisObject); + ASSERT(!scope.exception() || checker.earlyReturnValue()); + if (JSValue earlyReturnValue = checker.earlyReturnValue()) + return JSValue::encode(earlyReturnValue); + + // 2. Let len be ? ToLength(? Get(O, "length")). + double length = toLength(exec, thisObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + // 3. If separator is undefined, let separator be the single-element String ",". + JSValue separatorValue = exec->argument(0); + if (separatorValue.isUndefined()) { + const LChar comma = ','; + + if (UNLIKELY(length > std::numeric_limits::max() || !canUseFastJoin(thisObject))) { + uint64_t length64 = static_cast(length); + ASSERT(static_cast(length64) == length); + JSString* jsSeparator = jsSingleCharacterString(exec, comma); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + scope.release(); + return JSValue::encode(slowJoin(*exec, thisObject, jsSeparator, length64)); + } + + unsigned unsignedLength = static_cast(length); + ASSERT(static_cast(unsignedLength) == length); + + scope.release(); + return JSValue::encode(fastJoin(*exec, thisObject, { &comma, 1 }, unsignedLength)); } - arr->setLength(exec, n); - return JSValue::encode(arr); + + // 4. Let sep be ? ToString(separator). + JSString* jsSeparator = separatorValue.toString(exec); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + if (UNLIKELY(length > std::numeric_limits::max() || !canUseFastJoin(thisObject))) { + uint64_t length64 = static_cast(length); + ASSERT(static_cast(length64) == length); + + scope.release(); + return JSValue::encode(slowJoin(*exec, thisObject, jsSeparator, length64)); + } + + auto viewWithString = jsSeparator->viewWithUnderlyingString(*exec); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + scope.release(); + return JSValue::encode(fastJoin(*exec, thisObject, viewWithString.view, length)); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState* exec) { - JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); - if (isJSArray(thisValue)) + JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); + + if (isJSArray(thisValue)) { + scope.release(); return JSValue::encode(asArray(thisValue)->pop(exec)); + } JSObject* thisObj = thisValue.toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + ASSERT(!!scope.exception() == !thisObj); + if (UNLIKELY(!thisObj)) + return encodedJSValue(); + unsigned length = getLength(exec, thisObj); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); - JSValue result; if (length == 0) { - putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length)); - result = jsUndefined(); - } else { - result = thisObj->get(exec, length - 1); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, length - 1)) { - throwTypeError(exec, ASCIILiteral("Unable to delete property.")); - return JSValue::encode(jsUndefined()); - } - putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1)); + scope.release(); + putLength(exec, vm, thisObj, jsNumber(length)); + return JSValue::encode(jsUndefined()); + } + + JSValue result = thisObj->get(exec, length - 1); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + bool success = thisObj->methodTable(vm)->deletePropertyByIndex(thisObj, exec, length - 1); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (UNLIKELY(!success)) { + throwTypeError(exec, scope, ASCIILiteral(UnableToDeletePropertyError)); + return encodedJSValue(); } + scope.release(); + putLength(exec, vm, thisObj, jsNumber(length - 1)); return JSValue::encode(result); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec) { - JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); if (isJSArray(thisValue) && exec->argumentCount() == 1) { JSArray* array = asArray(thisValue); + scope.release(); array->push(exec, exec->uncheckedArgument(0)); return JSValue::encode(jsNumber(array->length())); } JSObject* thisObj = thisValue.toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + ASSERT(!!scope.exception() == !thisObj); + if (UNLIKELY(!thisObj)) + return encodedJSValue(); + unsigned length = getLength(exec, thisObj); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); for (unsigned n = 0; n < exec->argumentCount(); n++) { // Check for integer overflow; where safe we can do a fast put by index. if (length + n >= length) - thisObj->methodTable()->putByIndex(thisObj, exec, length + n, exec->uncheckedArgument(n), true); + thisObj->methodTable(vm)->putByIndex(thisObj, exec, length + n, exec->uncheckedArgument(n), true); else { PutPropertySlot slot(thisObj); - Identifier propertyName(exec, JSValue(static_cast(length) + static_cast(n)).toWTFString(exec)); - thisObj->methodTable()->put(thisObj, exec, propertyName, exec->uncheckedArgument(n), slot); + Identifier propertyName = Identifier::fromString(exec, JSValue(static_cast(length) + static_cast(n)).toWTFString(exec)); + thisObj->methodTable(vm)->put(thisObj, exec, propertyName, exec->uncheckedArgument(n), slot); } - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); } JSValue newLength(static_cast(length) + static_cast(exec->argumentCount())); - putProperty(exec, thisObj, exec->propertyNames().length, newLength); + scope.release(); + putLength(exec, vm, thisObj, newLength); return JSValue::encode(newLength); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState* exec) { - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); + ASSERT(!!scope.exception() == !thisObject); + if (UNLIKELY(!thisObject)) + return encodedJSValue(); + + unsigned length = getLength(exec, thisObject); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + switch (thisObject->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + case ALL_INT32_INDEXING_TYPES: { + auto& butterfly = *thisObject->butterfly(); + if (length > butterfly.publicLength()) + break; + auto data = butterfly.contiguous().data(); + if (containsHole(data, length) && holesMustForwardToPrototype(*exec, thisObject)) + break; + std::reverse(data, data + length); + return JSValue::encode(thisObject); + } + case ALL_DOUBLE_INDEXING_TYPES: { + auto& butterfly = *thisObject->butterfly(); + if (length > butterfly.publicLength()) + break; + auto data = butterfly.contiguousDouble().data(); + if (containsHole(data, length) && holesMustForwardToPrototype(*exec, thisObject)) + break; + std::reverse(data, data + length); + return JSValue::encode(thisObject); + } + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { + auto& storage = *thisObject->butterfly()->arrayStorage(); + if (length > storage.vectorLength()) + break; + if (storage.hasHoles() && holesMustForwardToPrototype(*exec, thisObject)) + break; + auto data = storage.vector().data(); + std::reverse(data, data + length); + return JSValue::encode(thisObject); + } + } unsigned middle = length / 2; - for (unsigned k = 0; k < middle; k++) { - unsigned lk1 = length - k - 1; - JSValue obj2 = getProperty(exec, thisObj, lk1); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - JSValue obj = getProperty(exec, thisObj, k); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - if (obj2) { - thisObj->methodTable()->putByIndex(thisObj, exec, k, obj2, true); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k)) { - throwTypeError(exec, ASCIILiteral("Unable to delete property.")); - return JSValue::encode(jsUndefined()); + for (unsigned lower = 0; lower < middle; lower++) { + unsigned upper = length - lower - 1; + bool lowerExists = thisObject->hasProperty(exec, lower); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + JSValue lowerValue; + if (lowerExists) { + lowerValue = thisObject->get(exec, lower); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); } - if (obj) { - thisObj->methodTable()->putByIndex(thisObj, exec, lk1, obj, true); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, lk1)) { - throwTypeError(exec, ASCIILiteral("Unable to delete property.")); - return JSValue::encode(jsUndefined()); + bool upperExists = thisObject->hasProperty(exec, upper); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + JSValue upperValue; + if (upperExists) { + upperValue = thisObject->get(exec, upper); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } + + if (upperExists) { + thisObject->putByIndexInline(exec, lower, upperValue, true); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } else { + bool success = thisObject->methodTable(vm)->deletePropertyByIndex(thisObject, exec, lower); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (UNLIKELY(!success)) { + throwTypeError(exec, scope, ASCIILiteral(UnableToDeletePropertyError)); + return encodedJSValue(); + } + } + + if (lowerExists) { + thisObject->putByIndexInline(exec, upper, lowerValue, true); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } else { + bool success = thisObject->methodTable(vm)->deletePropertyByIndex(thisObject, exec, upper); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (UNLIKELY(!success)) { + throwTypeError(exec, scope, ASCIILiteral(UnableToDeletePropertyError)); + return encodedJSValue(); + } } } - return JSValue::encode(thisObj); + return JSValue::encode(thisObject); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec) { - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); + ASSERT(!!scope.exception() == !thisObj); + if (UNLIKELY(!thisObj)) + return encodedJSValue(); + unsigned length = getLength(exec, thisObj); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); - JSValue result; if (length == 0) { - putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length)); - result = jsUndefined(); - } else { - result = thisObj->get(exec, 0); - shift(exec, thisObj, 0, 1, 0, length); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1)); + scope.release(); + putLength(exec, vm, thisObj, jsNumber(length)); + return JSValue::encode(jsUndefined()); } + + JSValue result = thisObj->getIndex(exec, 0); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + shift(exec, thisObj, 0, 1, 0, length); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + scope.release(); + putLength(exec, vm, thisObj, jsNumber(length - 1)); return JSValue::encode(result); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec) { - // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10 - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - // We return a new array - JSArray* resObj = constructEmptyArray(exec, 0); - JSValue result = resObj; + // https://tc39.github.io/ecma262/#sec-array.prototype.slice + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); + ASSERT(!!scope.exception() == !thisObj); + if (UNLIKELY(!thisObj)) + return { }; + unsigned length = getLength(exec, thisObj); + RETURN_IF_EXCEPTION(scope, { }); unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length); + RETURN_IF_EXCEPTION(scope, { }); unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, length, length); + RETURN_IF_EXCEPTION(scope, { }); + + std::pair speciesResult = speciesConstructArray(exec, thisObj, end - begin); + // We can only get an exception if we call some user function. + ASSERT(!!scope.exception() == (speciesResult.first == SpeciesConstructResult::Exception)); + if (UNLIKELY(speciesResult.first == SpeciesConstructResult::Exception)) + return { }; + + bool okToDoFastPath = speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj) && length == getLength(exec, thisObj); + RETURN_IF_EXCEPTION(scope, { }); + if (LIKELY(okToDoFastPath)) { + if (JSArray* result = asArray(thisObj)->fastSlice(*exec, begin, end - begin)) + return JSValue::encode(result); + } + + JSObject* result; + if (speciesResult.first == SpeciesConstructResult::CreatedObject) + result = speciesResult.second; + else { + result = constructEmptyArray(exec, nullptr, end - begin); + RETURN_IF_EXCEPTION(scope, { }); + } unsigned n = 0; for (unsigned k = begin; k < end; k++, n++) { JSValue v = getProperty(exec, thisObj, k); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - if (v) - resObj->putDirectIndex(exec, n, v); + RETURN_IF_EXCEPTION(scope, { }); + if (v) { + result->putDirectIndex(exec, n, v, 0, PutDirectIndexShouldThrow); + RETURN_IF_EXCEPTION(scope, { }); + } } - resObj->setLength(exec, n); + scope.release(); + setLength(exec, vm, result, n); return JSValue::encode(result); } -inline JSValue getOrHole(JSObject* obj, ExecState* exec, unsigned propertyName) -{ - PropertySlot slot(obj); - if (obj->getPropertySlot(exec, propertyName, slot)) - return slot.getValue(exec, propertyName); - - return JSValue(); -} - -static bool attemptFastSort(ExecState* exec, JSObject* thisObj, JSValue function, CallData& callData, CallType& callType) +EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) { - if (thisObj->classInfo() != JSArray::info() - || asArray(thisObj)->hasSparseMap() - || shouldUseSlowPut(thisObj->structure()->indexingType())) - return false; - - if (isNumericCompareFunction(exec, callType, callData)) - asArray(thisObj)->sortNumeric(exec, function, callType, callData); - else if (callType != CallTypeNone) - asArray(thisObj)->sort(exec, function, callType, callData); - else - asArray(thisObj)->sort(exec); - return true; -} + // 15.4.4.12 -static bool performSlowSort(ExecState* exec, JSObject* thisObj, unsigned length, JSValue function, CallData& callData, CallType& callType) -{ - // "Min" sort. Not the fastest, but definitely less code than heapsort - // or quicksort, and much less swapping than bubblesort/insertionsort. - for (unsigned i = 0; i < length - 1; ++i) { - JSValue iObj = getOrHole(thisObj, exec, i); - if (exec->hadException()) - return false; - unsigned themin = i; - JSValue minObj = iObj; - for (unsigned j = i + 1; j < length; ++j) { - JSValue jObj = getOrHole(thisObj, exec, j); - if (exec->hadException()) - return false; - double compareResult; - if (!jObj) - compareResult = 1; - else if (!minObj) - compareResult = -1; - else if (jObj.isUndefined()) - compareResult = 1; // don't check minObj because there's no need to differentiate == (0) from > (1) - else if (minObj.isUndefined()) - compareResult = -1; - else if (callType != CallTypeNone) { - MarkedArgumentBuffer l; - l.append(jObj); - l.append(minObj); - compareResult = call(exec, function, callType, callData, jsUndefined(), l).toNumber(exec); - } else - compareResult = codePointCompareLessThan(jObj.toWTFStringInline(exec), minObj.toWTFStringInline(exec)) ? -1 : 1; - - if (compareResult < 0) { - themin = j; - minObj = jObj; - } - } - // Swap themin and i - if (themin > i) { - if (minObj) { - thisObj->methodTable()->putByIndex(thisObj, exec, i, minObj, true); - if (exec->hadException()) - return false; - } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, i)) { - throwTypeError(exec, "Unable to delete property."); - return false; - } - if (iObj) { - thisObj->methodTable()->putByIndex(thisObj, exec, themin, iObj, true); - if (exec->hadException()) - return false; - } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, themin)) { - throwTypeError(exec, "Unable to delete property."); - return false; - } + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); + ASSERT(!!scope.exception() == !thisObj); + if (UNLIKELY(!thisObj)) + return encodedJSValue(); + unsigned length = getLength(exec, thisObj); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + if (!exec->argumentCount()) { + std::pair speciesResult = speciesConstructArray(exec, thisObj, 0); + ASSERT(!!scope.exception() == (speciesResult.first == SpeciesConstructResult::Exception)); + if (UNLIKELY(speciesResult.first == SpeciesConstructResult::Exception)) + return encodedJSValue(); + + JSObject* result; + if (speciesResult.first == SpeciesConstructResult::CreatedObject) + result = speciesResult.second; + else { + result = constructEmptyArray(exec, nullptr); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); } - } - return true; -} - -EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) -{ - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (!length || exec->hadException()) - return JSValue::encode(thisObj); - - JSValue function = exec->argument(0); - CallData callData; - CallType callType = getCallData(function, callData); - if (attemptFastSort(exec, thisObj, function, callData, callType)) - return JSValue::encode(thisObj); - - // Assume that for small-ish arrays, doing the slow sort directly is better. - if (length < 1000) - return performSlowSort(exec, thisObj, length, function, callData, callType) ? JSValue::encode(thisObj) : JSValue::encode(jsUndefined()); - - JSGlobalObject* globalObject = JSGlobalObject::create( - exec->vm(), JSGlobalObject::createStructure(exec->vm(), jsNull())); - JSArray* flatArray = constructEmptyArray(globalObject->globalExec(), 0); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - PropertyNameArray nameArray(exec); - thisObj->methodTable()->getPropertyNames(thisObj, exec, nameArray, IncludeDontEnumProperties); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - Vector keys; - for (size_t i = 0; i < nameArray.size(); ++i) { - PropertyName name = nameArray[i]; - uint32_t index = name.asIndex(); - if (index == PropertyName::NotAnIndex) - continue; - - JSValue value = getOrHole(thisObj, exec, index); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - if (!value) - continue; - keys.append(index); - flatArray->push(exec, value); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + setLength(exec, vm, result, 0); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + scope.release(); + setLength(exec, vm, thisObj, length); + return JSValue::encode(result); } - - if (!attemptFastSort(exec, flatArray, function, callData, callType) - && !performSlowSort(exec, flatArray, flatArray->length(), function, callData, callType)) - return JSValue::encode(jsUndefined()); - - for (size_t i = 0; i < keys.size(); ++i) { - size_t index = keys[i]; - if (index < flatArray->length()) - continue; - - if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, index)) { - throwTypeError(exec, "Unable to delete property."); - return JSValue::encode(jsUndefined()); - } - } - - for (size_t i = flatArray->length(); i--;) { - JSValue value = getOrHole(flatArray, exec, i); - RELEASE_ASSERT(value); - thisObj->methodTable()->putByIndex(thisObj, exec, i, value, true); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - } - - return JSValue::encode(thisObj); -} - -EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) -{ - // 15.4.4.12 - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - if (!exec->argumentCount()) - return JSValue::encode(constructEmptyArray(exec, 0)); + unsigned actualStart = argumentClampedIndexFromStartOrEnd(exec, 0, length); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); - unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length); - - unsigned deleteCount = length - begin; + unsigned actualDeleteCount = length - actualStart; if (exec->argumentCount() > 1) { - double deleteDouble = exec->uncheckedArgument(1).toInteger(exec); - if (deleteDouble < 0) - deleteCount = 0; - else if (deleteDouble > length - begin) - deleteCount = length - begin; + double deleteCount = exec->uncheckedArgument(1).toInteger(exec); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (deleteCount < 0) + actualDeleteCount = 0; + else if (deleteCount > length - actualStart) + actualDeleteCount = length - actualStart; else - deleteCount = static_cast(deleteDouble); + actualDeleteCount = static_cast(deleteCount); } - JSArray* resObj = JSArray::tryCreateUninitialized(exec->vm(), exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), deleteCount); - if (!resObj) - return JSValue::encode(throwOutOfMemoryError(exec)); + std::pair speciesResult = speciesConstructArray(exec, thisObj, actualDeleteCount); + ASSERT(!!scope.exception() == (speciesResult.first == SpeciesConstructResult::Exception)); + if (speciesResult.first == SpeciesConstructResult::Exception) + return JSValue::encode(jsUndefined()); + + JSObject* result = nullptr; + bool okToDoFastPath = speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj) && length == getLength(exec, thisObj); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (LIKELY(okToDoFastPath)) + result = asArray(thisObj)->fastSlice(*exec, actualStart, actualDeleteCount); - JSValue result = resObj; - VM& vm = exec->vm(); - for (unsigned k = 0; k < deleteCount; k++) { - JSValue v = getProperty(exec, thisObj, k + begin); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - resObj->initializeIndex(vm, k, v); + if (!result) { + if (speciesResult.first == SpeciesConstructResult::CreatedObject) { + result = speciesResult.second; + + for (unsigned k = 0; k < actualDeleteCount; ++k) { + JSValue v = getProperty(exec, thisObj, k + actualStart); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (UNLIKELY(!v)) + continue; + result->putByIndexInline(exec, k, v, true); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } + } else { + result = JSArray::tryCreate(vm, exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), actualDeleteCount); + if (UNLIKELY(!result)) { + throwOutOfMemoryError(exec, scope); + return encodedJSValue(); + } + + for (unsigned k = 0; k < actualDeleteCount; ++k) { + JSValue v = getProperty(exec, thisObj, k + actualStart); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (UNLIKELY(!v)) + continue; + result->putDirectIndex(exec, k, v); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } + } } - unsigned additionalArgs = std::max(exec->argumentCount() - 2, 0); - if (additionalArgs < deleteCount) { - shift(exec, thisObj, begin, deleteCount, additionalArgs, length); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - } else if (additionalArgs > deleteCount) { - unshift(exec, thisObj, begin, deleteCount, additionalArgs, length); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + unsigned itemCount = std::max(exec->argumentCount() - 2, 0); + if (itemCount < actualDeleteCount) { + shift(exec, thisObj, actualStart, actualDeleteCount, itemCount, length); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } else if (itemCount > actualDeleteCount) { + unshift(exec, thisObj, actualStart, actualDeleteCount, itemCount, length); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); } - for (unsigned k = 0; k < additionalArgs; ++k) { - thisObj->methodTable()->putByIndex(thisObj, exec, k + begin, exec->uncheckedArgument(k + 2), true); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + for (unsigned k = 0; k < itemCount; ++k) { + thisObj->putByIndexInline(exec, k + actualStart, exec->uncheckedArgument(k + 2), true); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); } - - putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - deleteCount + additionalArgs)); + + scope.release(); + setLength(exec, vm, thisObj, length - actualDeleteCount + itemCount); return JSValue::encode(result); } EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec) { + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); // 15.4.4.13 - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); + ASSERT(!!scope.exception() == !thisObj); + if (UNLIKELY(!thisObj)) + return encodedJSValue(); + unsigned length = getLength(exec, thisObj); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); unsigned nrArgs = exec->argumentCount(); if (nrArgs) { unshift(exec, thisObj, 0, 0, nrArgs, length); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); } for (unsigned k = 0; k < nrArgs; ++k) { - thisObj->methodTable()->putByIndex(thisObj, exec, k, exec->uncheckedArgument(k), true); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + thisObj->putByIndexInline(exec, k, exec->uncheckedArgument(k), true); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); } JSValue result = jsNumber(length + nrArgs); - putProperty(exec, thisObj, exec->propertyNames().length, result); + scope.release(); + putLength(exec, vm, thisObj, result); return JSValue::encode(result); } -EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec) +EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec) { - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - JSValue function = exec->argument(0); - CallData callData; - CallType callType = getCallData(function, callData); - if (callType == CallTypeNone) - return throwVMTypeError(exec); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); - JSValue applyThis = exec->argument(1); - JSArray* resultArray = constructEmptyArray(exec, 0); + // 15.4.4.14 + JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); + ASSERT(!!scope.exception() == !thisObj); + if (UNLIKELY(!thisObj)) + return encodedJSValue(); + unsigned length = getLength(exec, thisObj); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); - unsigned filterIndex = 0; - unsigned k = 0; - if (callType == CallTypeJS && isJSArray(thisObj)) { - JSFunction* f = jsCast(function); - JSArray* array = asArray(thisObj); - CachedCall cachedCall(exec, f, 3); - for (; k < length && !exec->hadException(); ++k) { - if (!array->canGetIndexQuickly(k)) - break; - JSValue v = array->getIndexQuickly(k); - cachedCall.setThis(applyThis); - cachedCall.setArgument(0, v); - cachedCall.setArgument(1, jsNumber(k)); - cachedCall.setArgument(2, thisObj); - - JSValue result = cachedCall.call(); - if (result.toBoolean(exec)) - resultArray->putDirectIndex(exec, filterIndex++, v); - } - if (k == length) - return JSValue::encode(resultArray); - } - for (; k < length && !exec->hadException(); ++k) { - PropertySlot slot(thisObj); - if (!thisObj->getPropertySlot(exec, k, slot)) + unsigned index = argumentClampedIndexFromStartOrEnd(exec, 1, length); + JSValue searchElement = exec->argument(0); + for (; index < length; ++index) { + JSValue e = getProperty(exec, thisObj, index); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (!e) continue; - JSValue v = slot.getValue(exec, k); - - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - MarkedArgumentBuffer eachArguments; - eachArguments.append(v); - eachArguments.append(jsNumber(k)); - eachArguments.append(thisObj); - - JSValue result = call(exec, function, callType, callData, applyThis, eachArguments); - if (result.toBoolean(exec)) - resultArray->putDirectIndex(exec, filterIndex++, v); + if (JSValue::strictEqual(exec, searchElement, e)) + return JSValue::encode(jsNumber(index)); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); } - return JSValue::encode(resultArray); + + return JSValue::encode(jsNumber(-1)); } -EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec) +EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec) { - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); - JSValue function = exec->argument(0); - CallData callData; - CallType callType = getCallData(function, callData); - if (callType == CallTypeNone) - return throwVMTypeError(exec); + // 15.4.4.15 + JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec); + ASSERT(!!scope.exception() == !thisObj); + if (UNLIKELY(!thisObj)) + return encodedJSValue(); + unsigned length = getLength(exec, thisObj); + if (UNLIKELY(scope.exception()) || !length) + return JSValue::encode(jsNumber(-1)); - JSValue applyThis = exec->argument(1); + unsigned index = length - 1; + if (exec->argumentCount() >= 2) { + JSValue fromValue = exec->uncheckedArgument(1); + double fromDouble = fromValue.toInteger(exec); + if (fromDouble < 0) { + fromDouble += length; + if (fromDouble < 0) + return JSValue::encode(jsNumber(-1)); + } + if (fromDouble < length) + index = static_cast(fromDouble); + } - JSArray* resultArray = constructEmptyArray(exec, 0, length); - unsigned k = 0; - if (callType == CallTypeJS && isJSArray(thisObj)) { - JSFunction* f = jsCast(function); - JSArray* array = asArray(thisObj); - CachedCall cachedCall(exec, f, 3); - for (; k < length && !exec->hadException(); ++k) { - if (UNLIKELY(!array->canGetIndexQuickly(k))) - break; + JSValue searchElement = exec->argument(0); + do { + RELEASE_ASSERT(index < length); + JSValue e = getProperty(exec, thisObj, index); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (!e) + continue; + if (JSValue::strictEqual(exec, searchElement, e)) + return JSValue::encode(jsNumber(index)); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + } while (index--); - cachedCall.setThis(applyThis); - cachedCall.setArgument(0, array->getIndexQuickly(k)); - cachedCall.setArgument(1, jsNumber(k)); - cachedCall.setArgument(2, thisObj); + return JSValue::encode(jsNumber(-1)); +} - resultArray->putDirectIndex(exec, k, cachedCall.call()); +static bool moveElements(ExecState* exec, VM& vm, JSArray* target, unsigned targetOffset, JSArray* source, unsigned sourceLength) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + if (LIKELY(!hasAnyArrayStorage(source->indexingType()) && !source->structure()->holesMustForwardToPrototype(vm))) { + for (unsigned i = 0; i < sourceLength; ++i) { + JSValue value = source->tryGetIndexQuickly(i); + if (value) { + target->putDirectIndex(exec, targetOffset + i, value, 0, PutDirectIndexShouldThrow); + RETURN_IF_EXCEPTION(scope, false); + } + } + } else { + for (unsigned i = 0; i < sourceLength; ++i) { + JSValue value = getProperty(exec, source, i); + RETURN_IF_EXCEPTION(scope, false); + if (value) { + target->putDirectIndex(exec, targetOffset + i, value, 0, PutDirectIndexShouldThrow); + RETURN_IF_EXCEPTION(scope, false); + } } } - for (; k < length && !exec->hadException(); ++k) { - PropertySlot slot(thisObj); - if (!thisObj->getPropertySlot(exec, k, slot)) - continue; - JSValue v = slot.getValue(exec, k); + return true; +} - if (exec->hadException()) - return JSValue::encode(jsUndefined()); +static EncodedJSValue concatAppendOne(ExecState* exec, VM& vm, JSArray* first, JSValue second) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + + ASSERT(!isJSArray(second)); + ASSERT(!shouldUseSlowPut(first->indexingType())); + Butterfly* firstButterfly = first->butterfly(); + unsigned firstArraySize = firstButterfly->publicLength(); + + Checked checkedResultSize = firstArraySize; + checkedResultSize += 1; + if (UNLIKELY(checkedResultSize.hasOverflowed())) { + throwOutOfMemoryError(exec, scope); + return encodedJSValue(); + } - MarkedArgumentBuffer eachArguments; - eachArguments.append(v); - eachArguments.append(jsNumber(k)); - eachArguments.append(thisObj); + unsigned resultSize = checkedResultSize.unsafeGet(); + IndexingType type = first->mergeIndexingTypeForCopying(indexingTypeForValue(second) | IsArray); + + if (type == NonArray) + type = first->indexingType(); + + Structure* resultStructure = exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(type); + JSArray* result = JSArray::create(vm, resultStructure, resultSize); + if (UNLIKELY(!result)) { + throwOutOfMemoryError(exec, scope); + return encodedJSValue(); + } - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + bool success = result->appendMemcpy(exec, vm, 0, first); + ASSERT(!success || !scope.exception()); + if (!success) { + RETURN_IF_EXCEPTION(scope, encodedJSValue()); - JSValue result = call(exec, function, callType, callData, applyThis, eachArguments); - resultArray->putDirectIndex(exec, k, result); + bool success = moveElements(exec, vm, result, 0, first, firstArraySize); + ASSERT(!scope.exception() == success); + if (UNLIKELY(!success)) + return encodedJSValue(); } - return JSValue::encode(resultArray); + scope.release(); + result->putDirectIndex(exec, firstArraySize, second); + return JSValue::encode(result); + } -// Documentation for these three is available at: -// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:every -// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEach -// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:some -EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec) +EncodedJSValue JSC_HOST_CALL arrayProtoPrivateFuncConcatMemcpy(ExecState* exec) { - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + ASSERT(exec->argumentCount() == 2); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); - JSValue function = exec->argument(0); - CallData callData; - CallType callType = getCallData(function, callData); - if (callType == CallTypeNone) - return throwVMTypeError(exec); + JSArray* firstArray = jsCast(exec->uncheckedArgument(0)); + + // This code assumes that neither array has set Symbol.isConcatSpreadable. If the first array + // has indexed accessors then one of those accessors might change the value of Symbol.isConcatSpreadable + // on the second argument. + if (UNLIKELY(shouldUseSlowPut(firstArray->indexingType()))) + return JSValue::encode(jsNull()); + + // We need to check the species constructor here since checking it in the JS wrapper is too expensive for the non-optimizing tiers. + bool isValid = speciesWatchpointIsValid(exec, firstArray); + if (UNLIKELY(!isValid)) + return JSValue::encode(jsNull()); + + JSValue second = exec->uncheckedArgument(1); + if (!isJSArray(second)) { + scope.release(); + return concatAppendOne(exec, vm, firstArray, second); + } - JSValue applyThis = exec->argument(1); + JSArray* secondArray = jsCast(second); + + Butterfly* firstButterfly = firstArray->butterfly(); + Butterfly* secondButterfly = secondArray->butterfly(); - JSValue result = jsBoolean(true); + unsigned firstArraySize = firstButterfly->publicLength(); + unsigned secondArraySize = secondButterfly->publicLength(); - unsigned k = 0; - if (callType == CallTypeJS && isJSArray(thisObj)) { - JSFunction* f = jsCast(function); - JSArray* array = asArray(thisObj); - CachedCall cachedCall(exec, f, 3); - for (; k < length && !exec->hadException(); ++k) { - if (UNLIKELY(!array->canGetIndexQuickly(k))) - break; - - cachedCall.setThis(applyThis); - cachedCall.setArgument(0, array->getIndexQuickly(k)); - cachedCall.setArgument(1, jsNumber(k)); - cachedCall.setArgument(2, thisObj); - JSValue result = cachedCall.call(); - if (!result.toBoolean(exec)) - return JSValue::encode(jsBoolean(false)); - } + Checked checkedResultSize = firstArraySize; + checkedResultSize += secondArraySize; + + if (UNLIKELY(checkedResultSize.hasOverflowed())) { + throwOutOfMemoryError(exec, scope); + return encodedJSValue(); } - for (; k < length && !exec->hadException(); ++k) { - PropertySlot slot(thisObj); - if (!thisObj->getPropertySlot(exec, k, slot)) - continue; - MarkedArgumentBuffer eachArguments; - eachArguments.append(slot.getValue(exec, k)); - eachArguments.append(jsNumber(k)); - eachArguments.append(thisObj); + unsigned resultSize = checkedResultSize.unsafeGet(); + IndexingType secondType = secondArray->indexingType(); + IndexingType type = firstArray->mergeIndexingTypeForCopying(secondType); + if (type == NonArray || !firstArray->canFastCopy(vm, secondArray) || resultSize >= MIN_SPARSE_ARRAY_INDEX) { + JSArray* result = constructEmptyArray(exec, nullptr, resultSize); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + bool success = moveElements(exec, vm, result, 0, firstArray, firstArraySize); + ASSERT(!scope.exception() == success); + if (UNLIKELY(!success)) + return encodedJSValue(); + success = moveElements(exec, vm, result, firstArraySize, secondArray, secondArraySize); + ASSERT(!scope.exception() == success); + if (UNLIKELY(!success)) + return encodedJSValue(); + + return JSValue::encode(result); + } - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); + Structure* resultStructure = lexicalGlobalObject->arrayStructureForIndexingTypeDuringAllocation(type); + if (UNLIKELY(hasAnyArrayStorage(resultStructure->indexingType()))) + return JSValue::encode(jsNull()); - bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec); - if (!predicateResult) { - result = jsBoolean(false); - break; + ASSERT(!lexicalGlobalObject->isHavingABadTime()); + JSArray* result = JSArray::tryCreateForInitializationPrivate(vm, resultStructure, resultSize); + if (UNLIKELY(!result)) { + throwOutOfMemoryError(exec, scope); + return encodedJSValue(); + } + + if (type == ArrayWithDouble) { + double* buffer = result->butterfly()->contiguousDouble().data(); + memcpy(buffer, firstButterfly->contiguousDouble().data(), sizeof(JSValue) * firstArraySize); + memcpy(buffer + firstArraySize, secondButterfly->contiguousDouble().data(), sizeof(JSValue) * secondArraySize); + } else if (type != ArrayWithUndecided) { + WriteBarrier* buffer = result->butterfly()->contiguous().data(); + memcpy(buffer, firstButterfly->contiguous().data(), sizeof(JSValue) * firstArraySize); + if (secondType != ArrayWithUndecided) + memcpy(buffer + firstArraySize, secondButterfly->contiguous().data(), sizeof(JSValue) * secondArraySize); + else { + for (unsigned i = secondArraySize; i--;) + buffer[i + firstArraySize].clear(); } } + result->butterfly()->setPublicLength(resultSize); return JSValue::encode(result); } -EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec) +EncodedJSValue JSC_HOST_CALL arrayProtoPrivateFuncAppendMemcpy(ExecState* exec) { - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - JSValue function = exec->argument(0); - CallData callData; - CallType callType = getCallData(function, callData); - if (callType == CallTypeNone) - return throwVMTypeError(exec); - - JSValue applyThis = exec->argument(1); - - unsigned k = 0; - if (callType == CallTypeJS && isJSArray(thisObj)) { - JSFunction* f = jsCast(function); - JSArray* array = asArray(thisObj); - CachedCall cachedCall(exec, f, 3); - for (; k < length && !exec->hadException(); ++k) { - if (UNLIKELY(!array->canGetIndexQuickly(k))) - break; - - cachedCall.setThis(applyThis); - cachedCall.setArgument(0, array->getIndexQuickly(k)); - cachedCall.setArgument(1, jsNumber(k)); - cachedCall.setArgument(2, thisObj); - - cachedCall.call(); - } - } - for (; k < length && !exec->hadException(); ++k) { - PropertySlot slot(thisObj); - if (!thisObj->getPropertySlot(exec, k, slot)) - continue; - - MarkedArgumentBuffer eachArguments; - eachArguments.append(slot.getValue(exec, k)); - eachArguments.append(jsNumber(k)); - eachArguments.append(thisObj); + ASSERT(exec->argumentCount() == 3); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - call(exec, function, callType, callData, applyThis, eachArguments); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSArray* resultArray = jsCast(exec->uncheckedArgument(0)); + JSArray* otherArray = jsCast(exec->uncheckedArgument(1)); + JSValue startValue = exec->uncheckedArgument(2); + ASSERT(startValue.isAnyInt() && startValue.asAnyInt() >= 0 && startValue.asAnyInt() <= std::numeric_limits::max()); + unsigned startIndex = static_cast(startValue.asAnyInt()); + bool success = resultArray->appendMemcpy(exec, vm, startIndex, otherArray); + ASSERT(!success || !scope.exception()); + if (!success) { + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + moveElements(exec, vm, resultArray, startIndex, otherArray, otherArray->length()); } return JSValue::encode(jsUndefined()); } -EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec) -{ - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - JSValue function = exec->argument(0); - CallData callData; - CallType callType = getCallData(function, callData); - if (callType == CallTypeNone) - return throwVMTypeError(exec); +// -------------------- ArrayPrototype.constructor Watchpoint ------------------ - JSValue applyThis = exec->argument(1); +static bool verbose = false; - JSValue result = jsBoolean(false); +class ArrayPrototypeAdaptiveInferredPropertyWatchpoint : public AdaptiveInferredPropertyValueWatchpointBase { +public: + typedef AdaptiveInferredPropertyValueWatchpointBase Base; + ArrayPrototypeAdaptiveInferredPropertyWatchpoint(const ObjectPropertyCondition&, ArrayPrototype*); - unsigned k = 0; - if (callType == CallTypeJS && isJSArray(thisObj)) { - JSFunction* f = jsCast(function); - JSArray* array = asArray(thisObj); - CachedCall cachedCall(exec, f, 3); - for (; k < length && !exec->hadException(); ++k) { - if (UNLIKELY(!array->canGetIndexQuickly(k))) - break; - - cachedCall.setThis(applyThis); - cachedCall.setArgument(0, array->getIndexQuickly(k)); - cachedCall.setArgument(1, jsNumber(k)); - cachedCall.setArgument(2, thisObj); - JSValue result = cachedCall.call(); - if (result.toBoolean(exec)) - return JSValue::encode(jsBoolean(true)); - } - } - for (; k < length && !exec->hadException(); ++k) { - PropertySlot slot(thisObj); - if (!thisObj->getPropertySlot(exec, k, slot)) - continue; +private: + void handleFire(const FireDetail&) override; - MarkedArgumentBuffer eachArguments; - eachArguments.append(slot.getValue(exec, k)); - eachArguments.append(jsNumber(k)); - eachArguments.append(thisObj); + ArrayPrototype* m_arrayPrototype; +}; - if (exec->hadException()) - return JSValue::encode(jsUndefined()); +void ArrayPrototype::tryInitializeSpeciesWatchpoint(ExecState* exec) +{ + VM& vm = exec->vm(); - bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec); - if (predicateResult) { - result = jsBoolean(true); - break; - } - } - return JSValue::encode(result); -} + RELEASE_ASSERT(!m_constructorWatchpoint); + RELEASE_ASSERT(!m_constructorSpeciesWatchpoint); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec) -{ - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + auto scope = DECLARE_THROW_SCOPE(vm); - JSValue function = exec->argument(0); - CallData callData; - CallType callType = getCallData(function, callData); - if (callType == CallTypeNone) - return throwVMTypeError(exec); - - unsigned i = 0; - JSValue rv; - if (!length && exec->argumentCount() == 1) - return throwVMTypeError(exec); - - JSArray* array = 0; - if (isJSArray(thisObj)) - array = asArray(thisObj); - - if (exec->argumentCount() >= 2) - rv = exec->uncheckedArgument(1); - else if (array && array->canGetIndexQuickly(0)) { - rv = array->getIndexQuickly(0); - i = 1; - } else { - for (i = 0; i < length; i++) { - rv = getProperty(exec, thisObj, i); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - if (rv) - break; - } - if (!rv) - return throwVMTypeError(exec); - i++; - } + if (verbose) + dataLog("Initializing Array species watchpoints for Array.prototype: ", pointerDump(this), " with structure: ", pointerDump(this->structure()), "\nand Array: ", pointerDump(this->globalObject()->arrayConstructor()), " with structure: ", pointerDump(this->globalObject()->arrayConstructor()->structure()), "\n"); + // First we need to make sure that the Array.prototype.constructor property points to Array + // and that Array[Symbol.species] is the primordial GetterSetter. - if (callType == CallTypeJS && array) { - CachedCall cachedCall(exec, jsCast(function), 4); - for (; i < length && !exec->hadException(); ++i) { - cachedCall.setThis(jsUndefined()); - cachedCall.setArgument(0, rv); - JSValue v; - if (LIKELY(array->canGetIndexQuickly(i))) - v = array->getIndexQuickly(i); - else - break; // length has been made unsafe while we enumerate fallback to slow path - cachedCall.setArgument(1, v); - cachedCall.setArgument(2, jsNumber(i)); - cachedCall.setArgument(3, array); - rv = cachedCall.call(); - } - if (i == length) // only return if we reached the end of the array - return JSValue::encode(rv); - } + // We only initialize once so flattening the structures does not have any real cost. + Structure* prototypeStructure = this->structure(vm); + if (prototypeStructure->isDictionary()) + prototypeStructure = prototypeStructure->flattenDictionaryStructure(vm, this); + RELEASE_ASSERT(!prototypeStructure->isDictionary()); - for (; i < length && !exec->hadException(); ++i) { - JSValue prop = getProperty(exec, thisObj, i); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - if (!prop) - continue; - - MarkedArgumentBuffer eachArguments; - eachArguments.append(rv); - eachArguments.append(prop); - eachArguments.append(jsNumber(i)); - eachArguments.append(thisObj); - - rv = call(exec, function, callType, callData, jsUndefined(), eachArguments); - } - return JSValue::encode(rv); -} + JSGlobalObject* globalObject = this->globalObject(); + ArrayConstructor* arrayConstructor = globalObject->arrayConstructor(); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec) -{ - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); + auto invalidateWatchpoint = [&] { + globalObject->arraySpeciesWatchpoint().invalidate(vm, StringFireDetail("Was not able to set up array species watchpoint.")); + }; - JSValue function = exec->argument(0); - CallData callData; - CallType callType = getCallData(function, callData); - if (callType == CallTypeNone) - return throwVMTypeError(exec); - - unsigned i = 0; - JSValue rv; - if (!length && exec->argumentCount() == 1) - return throwVMTypeError(exec); - - JSArray* array = 0; - if (isJSArray(thisObj)) - array = asArray(thisObj); - - if (exec->argumentCount() >= 2) - rv = exec->uncheckedArgument(1); - else if (array && array->canGetIndexQuickly(length - 1)) { - rv = array->getIndexQuickly(length - 1); - i = 1; - } else { - for (i = 0; i < length; i++) { - rv = getProperty(exec, thisObj, length - i - 1); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - if (rv) - break; - } - if (!rv) - return throwVMTypeError(exec); - i++; - } - - if (callType == CallTypeJS && array) { - CachedCall cachedCall(exec, jsCast(function), 4); - for (; i < length && !exec->hadException(); ++i) { - unsigned idx = length - i - 1; - cachedCall.setThis(jsUndefined()); - cachedCall.setArgument(0, rv); - if (UNLIKELY(!array->canGetIndexQuickly(idx))) - break; // length has been made unsafe while we enumerate fallback to slow path - cachedCall.setArgument(1, array->getIndexQuickly(idx)); - cachedCall.setArgument(2, jsNumber(idx)); - cachedCall.setArgument(3, array); - rv = cachedCall.call(); - } - if (i == length) // only return if we reached the end of the array - return JSValue::encode(rv); - } - - for (; i < length && !exec->hadException(); ++i) { - unsigned idx = length - i - 1; - JSValue prop = getProperty(exec, thisObj, idx); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - if (!prop) - continue; - - MarkedArgumentBuffer eachArguments; - eachArguments.append(rv); - eachArguments.append(prop); - eachArguments.append(jsNumber(idx)); - eachArguments.append(thisObj); - - rv = call(exec, function, callType, callData, jsUndefined(), eachArguments); + PropertySlot constructorSlot(this, PropertySlot::InternalMethodType::VMInquiry); + this->getOwnPropertySlot(this, exec, vm.propertyNames->constructor, constructorSlot); + ASSERT_UNUSED(scope, !scope.exception()); + if (constructorSlot.slotBase() != this + || !constructorSlot.isCacheableValue() + || constructorSlot.getValue(exec, vm.propertyNames->constructor) != arrayConstructor) { + invalidateWatchpoint(); + return; } - return JSValue::encode(rv); -} - -EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec) -{ - // 15.4.4.14 - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - unsigned index = argumentClampedIndexFromStartOrEnd(exec, 1, length); - JSValue searchElement = exec->argument(0); - for (; index < length; ++index) { - JSValue e = getProperty(exec, thisObj, index); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - if (!e) - continue; - if (JSValue::strictEqual(exec, searchElement, e)) - return JSValue::encode(jsNumber(index)); + Structure* constructorStructure = arrayConstructor->structure(vm); + if (constructorStructure->isDictionary()) + constructorStructure = constructorStructure->flattenDictionaryStructure(vm, arrayConstructor); + + PropertySlot speciesSlot(arrayConstructor, PropertySlot::InternalMethodType::VMInquiry); + arrayConstructor->getOwnPropertySlot(arrayConstructor, exec, vm.propertyNames->speciesSymbol, speciesSlot); + ASSERT_UNUSED(scope, !scope.exception()); + if (speciesSlot.slotBase() != arrayConstructor + || !speciesSlot.isCacheableGetter() + || speciesSlot.getterSetter() != globalObject->speciesGetterSetter()) { + invalidateWatchpoint(); + return; } - return JSValue::encode(jsNumber(-1)); -} + // Now we need to setup the watchpoints to make sure these conditions remain valid. + prototypeStructure->startWatchingPropertyForReplacements(vm, constructorSlot.cachedOffset()); + constructorStructure->startWatchingPropertyForReplacements(vm, speciesSlot.cachedOffset()); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec) -{ - // 15.4.4.15 - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); - if (!length) - return JSValue::encode(jsNumber(-1)); + ObjectPropertyCondition constructorCondition = ObjectPropertyCondition::equivalence(vm, this, this, vm.propertyNames->constructor.impl(), arrayConstructor); + ObjectPropertyCondition speciesCondition = ObjectPropertyCondition::equivalence(vm, this, arrayConstructor, vm.propertyNames->speciesSymbol.impl(), globalObject->speciesGetterSetter()); - unsigned index = length - 1; - if (exec->argumentCount() >= 2) { - JSValue fromValue = exec->uncheckedArgument(1); - double fromDouble = fromValue.toInteger(exec); - if (fromDouble < 0) { - fromDouble += length; - if (fromDouble < 0) - return JSValue::encode(jsNumber(-1)); - } - if (fromDouble < length) - index = static_cast(fromDouble); + if (!constructorCondition.isWatchable() || !speciesCondition.isWatchable()) { + invalidateWatchpoint(); + return; } - JSValue searchElement = exec->argument(0); - do { - RELEASE_ASSERT(index < length); - JSValue e = getProperty(exec, thisObj, index); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - if (!e) - continue; - if (JSValue::strictEqual(exec, searchElement, e)) - return JSValue::encode(jsNumber(index)); - } while (index--); + m_constructorWatchpoint = std::make_unique(constructorCondition, this); + m_constructorWatchpoint->install(); - return JSValue::encode(jsNumber(-1)); -} + m_constructorSpeciesWatchpoint = std::make_unique(speciesCondition, this); + m_constructorSpeciesWatchpoint->install(); -EncodedJSValue JSC_HOST_CALL arrayProtoFuncValues(ExecState* exec) -{ - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateValue, thisObj)); + // We only watch this from the DFG, and the DFG makes sure to only start watching if the watchpoint is in the IsWatched state. + RELEASE_ASSERT(!globalObject->arraySpeciesWatchpoint().isBeingWatched()); + globalObject->arraySpeciesWatchpoint().touch(vm, "Set up array species watchpoint."); } -EncodedJSValue JSC_HOST_CALL arrayProtoFuncEntries(ExecState* exec) +ArrayPrototypeAdaptiveInferredPropertyWatchpoint::ArrayPrototypeAdaptiveInferredPropertyWatchpoint(const ObjectPropertyCondition& key, ArrayPrototype* prototype) + : Base(key) + , m_arrayPrototype(prototype) { - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateKeyValue, thisObj)); } - -EncodedJSValue JSC_HOST_CALL arrayProtoFuncKeys(ExecState* exec) + +void ArrayPrototypeAdaptiveInferredPropertyWatchpoint::handleFire(const FireDetail& detail) { - JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); - return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateKey, thisObj)); + StringPrintStream out; + out.print("ArrayPrototype adaption of ", key(), " failed: ", detail); + + StringFireDetail stringDetail(out.toCString().data()); + + if (verbose) + WTF::dataLog(stringDetail, "\n"); + + JSGlobalObject* globalObject = m_arrayPrototype->globalObject(); + globalObject->arraySpeciesWatchpoint().fireAll(globalObject->vm(), stringDetail); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.h b/Source/JavaScriptCore/runtime/ArrayPrototype.h index 472a1dd9c..081e9b35e 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.h +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2007, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2011, 2015 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,14 +18,15 @@ * */ -#ifndef ArrayPrototype_h -#define ArrayPrototype_h +#pragma once #include "JSArray.h" #include "Lookup.h" namespace JSC { +class ArrayPrototypeAdaptiveInferredPropertyWatchpoint; + class ArrayPrototype : public JSArray { private: ArrayPrototype(VM&, Structure*); @@ -33,21 +34,40 @@ private: public: typedef JSArray Base; + enum class SpeciesWatchpointStatus { + Uninitialized, + Initialized, + Fired + }; + static ArrayPrototype* create(VM&, JSGlobalObject*, Structure*); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); - - DECLARE_INFO; + DECLARE_EXPORT_INFO; static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), ArrayClass); + return Structure::create(vm, globalObject, prototype, TypeInfo(DerivedArrayType, StructureFlags), info(), ArrayClass); } + void tryInitializeSpeciesWatchpoint(ExecState*); + + static const bool needsDestruction = false; + // We don't need destruction since we use a finalizer. + static void destroy(JSC::JSCell*); + protected: void finishCreation(VM&, JSGlobalObject*); + +private: + // This bit is set if any user modifies the constructor property Array.prototype. This is used to optimize species creation for JSArrays. + friend ArrayPrototypeAdaptiveInferredPropertyWatchpoint; + std::unique_ptr m_constructorWatchpoint; + std::unique_ptr m_constructorSpeciesWatchpoint; }; -} // namespace JSC +EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*); +EncodedJSValue JSC_HOST_CALL arrayProtoFuncValues(ExecState*); +EncodedJSValue JSC_HOST_CALL arrayProtoPrivateFuncConcatMemcpy(ExecState*); +EncodedJSValue JSC_HOST_CALL arrayProtoPrivateFuncAppendMemcpy(ExecState*); -#endif // ArrayPrototype_h +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ArrayStorage.h b/Source/JavaScriptCore/runtime/ArrayStorage.h index a0287c921..c4e596d71 100644 --- a/Source/JavaScriptCore/runtime/ArrayStorage.h +++ b/Source/JavaScriptCore/runtime/ArrayStorage.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,16 +23,16 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ArrayStorage_h -#define ArrayStorage_h +#pragma once #include "ArrayConventions.h" #include "Butterfly.h" #include "IndexingHeader.h" +#include "MarkedSpace.h" #include "SparseArrayValueMap.h" +#include "Structure.h" #include "WriteBarrier.h" #include -#include namespace JSC { @@ -54,11 +54,12 @@ public: Butterfly* butterfly() { return reinterpret_cast(this); } IndexingHeader* indexingHeader() { return IndexingHeader::from(this); } + const IndexingHeader* indexingHeader() const { return IndexingHeader::from(this); } // We steal two fields from the indexing header: vectorLength and length. - unsigned length() { return indexingHeader()->publicLength(); } + unsigned length() const { return indexingHeader()->publicLength(); } void setLength(unsigned length) { indexingHeader()->setPublicLength(length); } - unsigned vectorLength() { return indexingHeader()->vectorLength(); } + unsigned vectorLength() const { return indexingHeader()->vectorLength(); } void setVectorLength(unsigned length) { indexingHeader()->setVectorLength(length); } ALWAYS_INLINE void copyHeaderFromDuringGC(const ArrayStorage& other) @@ -68,6 +69,11 @@ public: m_numValuesInVector = other.m_numValuesInVector; } + bool hasHoles() const + { + return m_numValuesInVector != length(); + } + bool inSparseMode() { return m_sparseMap && m_sparseMap->sparseMode(); @@ -94,9 +100,66 @@ public: { return ArrayStorage::vectorOffset() + vectorLength * sizeof(WriteBarrier); } -}; + + static size_t totalSizeFor(unsigned indexBias, size_t propertyCapacity, unsigned vectorLength) + { + return Butterfly::totalSize(indexBias, propertyCapacity, true, sizeFor(vectorLength)); + } + + size_t totalSize(size_t propertyCapacity) const + { + return totalSizeFor(m_indexBias, propertyCapacity, vectorLength()); + } + + size_t totalSize(Structure* structure) const + { + return totalSize(structure->outOfLineCapacity()); + } + + static unsigned availableVectorLength(unsigned indexBias, size_t propertyCapacity, unsigned vectorLength) + { + size_t cellSize = MarkedSpace::optimalSizeFor(totalSizeFor(indexBias, propertyCapacity, vectorLength)); + + vectorLength = (cellSize - totalSizeFor(indexBias, propertyCapacity, 0)) / sizeof(WriteBarrier); -} // namespace JSC + return vectorLength; + } + + static unsigned availableVectorLength(unsigned indexBias, Structure* structure, unsigned vectorLength) + { + return availableVectorLength(indexBias, structure->outOfLineCapacity(), vectorLength); + } + + unsigned availableVectorLength(size_t propertyCapacity, unsigned vectorLength) + { + return availableVectorLength(m_indexBias, propertyCapacity, vectorLength); + } + + unsigned availableVectorLength(Structure* structure, unsigned vectorLength) + { + return availableVectorLength(structure->outOfLineCapacity(), vectorLength); + } -#endif // ArrayStorage_h + static unsigned optimalVectorLength(unsigned indexBias, size_t propertyCapacity, unsigned vectorLength) + { + vectorLength = std::max(BASE_ARRAY_STORAGE_VECTOR_LEN, vectorLength); + return availableVectorLength(indexBias, propertyCapacity, vectorLength); + } + + static unsigned optimalVectorLength(unsigned indexBias, Structure* structure, unsigned vectorLength) + { + return optimalVectorLength(indexBias, structure->outOfLineCapacity(), vectorLength); + } + + unsigned optimalVectorLength(size_t propertyCapacity, unsigned vectorLength) + { + return optimalVectorLength(m_indexBias, propertyCapacity, vectorLength); + } + + unsigned optimalVectorLength(Structure* structure, unsigned vectorLength) + { + return optimalVectorLength(structure->outOfLineCapacity(), vectorLength); + } +}; +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/AsyncFunctionConstructor.cpp b/Source/JavaScriptCore/runtime/AsyncFunctionConstructor.cpp new file mode 100644 index 000000000..67840a884 --- /dev/null +++ b/Source/JavaScriptCore/runtime/AsyncFunctionConstructor.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 Caitlin Potter . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AsyncFunctionConstructor.h" + +#include "AsyncFunctionPrototype.h" +#include "FunctionConstructor.h" +#include "JSCInlines.h" + +namespace JSC { + +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(AsyncFunctionConstructor); + +const ClassInfo AsyncFunctionConstructor::s_info = { "AsyncFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(AsyncFunctionConstructor) }; + +AsyncFunctionConstructor::AsyncFunctionConstructor(VM& vm, Structure* structure) + : InternalFunction(vm, structure) +{ +} + +void AsyncFunctionConstructor::finishCreation(VM& vm, AsyncFunctionPrototype* prototype) +{ + Base::finishCreation(vm, "AsyncFunction"); + putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly); + + // Number of arguments for constructor + putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum); +} + +static EncodedJSValue JSC_HOST_CALL callAsyncFunctionConstructor(ExecState* exec) +{ + ArgList args(exec); + return JSValue::encode(constructFunction(exec, asInternalFunction(exec->jsCallee())->globalObject(), args, FunctionConstructionMode::Async)); +} + +static EncodedJSValue JSC_HOST_CALL constructAsyncFunctionConstructor(ExecState* exec) +{ + ArgList args(exec); + return JSValue::encode(constructFunction(exec, asInternalFunction(exec->jsCallee())->globalObject(), args, FunctionConstructionMode::Async)); +} + +CallType AsyncFunctionConstructor::getCallData(JSCell*, CallData& callData) +{ + callData.native.function = callAsyncFunctionConstructor; + return CallType::Host; +} + +ConstructType AsyncFunctionConstructor::getConstructData(JSCell*, ConstructData& constructData) +{ + constructData.native.function = constructAsyncFunctionConstructor; + return ConstructType::Host; +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/AsyncFunctionConstructor.h b/Source/JavaScriptCore/runtime/AsyncFunctionConstructor.h new file mode 100644 index 000000000..035a2c1e4 --- /dev/null +++ b/Source/JavaScriptCore/runtime/AsyncFunctionConstructor.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 Caitlin Potter . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "InternalFunction.h" + +namespace JSC { + +class AsyncFunctionPrototype; + +class AsyncFunctionConstructor : public InternalFunction { +public: + typedef InternalFunction Base; + + DECLARE_INFO; + + static AsyncFunctionConstructor* create(VM& vm, Structure* structure, AsyncFunctionPrototype* asyncFunctionPrototype) + { + AsyncFunctionConstructor* constructor = new (NotNull, allocateCell(vm.heap)) AsyncFunctionConstructor(vm, structure); + constructor->finishCreation(vm, asyncFunctionPrototype); + return constructor; + } + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + +private: + AsyncFunctionConstructor(VM&, Structure*); + void finishCreation(VM&, AsyncFunctionPrototype*); + static ConstructType getConstructData(JSCell*, ConstructData&); + static CallType getCallData(JSCell*, CallData&); +}; + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/AsyncFunctionPrototype.cpp b/Source/JavaScriptCore/runtime/AsyncFunctionPrototype.cpp new file mode 100644 index 000000000..ca3449efe --- /dev/null +++ b/Source/JavaScriptCore/runtime/AsyncFunctionPrototype.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 Caitlin Potter . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AsyncFunctionPrototype.h" + +#include "BuiltinExecutables.h" +#include "BuiltinNames.h" +#include "Error.h" +#include "JSArray.h" +#include "JSCInlines.h" +#include "JSFunction.h" +#include "JSString.h" +#include "JSStringBuilder.h" +#include "Lexer.h" + +namespace JSC { + +const ClassInfo AsyncFunctionPrototype::s_info = { "AsyncFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(AsyncFunctionPrototype) }; + +AsyncFunctionPrototype::AsyncFunctionPrototype(VM& vm, Structure* structure) + : JSC::JSNonFinalObject(vm, structure) +{ +} + +void AsyncFunctionPrototype::finishCreation(VM& vm) +{ + Base::finishCreation(vm); + ASSERT(inherits(vm, info())); + putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), DontDelete | ReadOnly | DontEnum); + putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "AsyncFunction"), DontEnum | ReadOnly); + vm.prototypeMap.addPrototype(this); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/AsyncFunctionPrototype.h b/Source/JavaScriptCore/runtime/AsyncFunctionPrototype.h new file mode 100644 index 000000000..b201e6b8f --- /dev/null +++ b/Source/JavaScriptCore/runtime/AsyncFunctionPrototype.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 Caitlin Potter . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "JSObject.h" + +namespace JSC { + +class AsyncFunctionPrototype : public JSNonFinalObject { +public: + typedef JSNonFinalObject Base; + + DECLARE_INFO; + + static AsyncFunctionPrototype* create(VM& vm, Structure* structure) + { + AsyncFunctionPrototype* prototype = new (NotNull, allocateCell(vm.heap)) AsyncFunctionPrototype(vm, structure); + prototype->finishCreation(vm); + return prototype; + } + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) + { + return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info()); + } + +protected: + void finishCreation(VM&); + +private: + AsyncFunctionPrototype(VM&, Structure*); +}; + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/AtomicsObject.cpp b/Source/JavaScriptCore/runtime/AtomicsObject.cpp new file mode 100644 index 000000000..9cd2427aa --- /dev/null +++ b/Source/JavaScriptCore/runtime/AtomicsObject.cpp @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2016-2017 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AtomicsObject.h" + +#include "JSCInlines.h" +#include "JSTypedArrays.h" +#include "ObjectPrototype.h" +#include "ReleaseHeapAccessScope.h" +#include "TypedArrayController.h" + +namespace JSC { + +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(AtomicsObject); + +#define FOR_EACH_ATOMICS_FUNC(macro) \ + macro(add, Add, 3) \ + macro(and, And, 3) \ + macro(compareExchange, CompareExchange, 4) \ + macro(exchange, Exchange, 3) \ + macro(isLockFree, IsLockFree, 1) \ + macro(load, Load, 2) \ + macro(or, Or, 3) \ + macro(store, Store, 3) \ + macro(sub, Sub, 3) \ + macro(wait, Wait, 4) \ + macro(wake, Wake, 3) \ + macro(xor, Xor, 3) + +#define DECLARE_FUNC_PROTO(lowerName, upperName, count) \ + EncodedJSValue JSC_HOST_CALL atomicsFunc ## upperName(ExecState*); +FOR_EACH_ATOMICS_FUNC(DECLARE_FUNC_PROTO) +#undef DECLARE_FUNC_PROTO + +const ClassInfo AtomicsObject::s_info = { "Atomics", &Base::s_info, 0, CREATE_METHOD_TABLE(AtomicsObject) }; + +AtomicsObject::AtomicsObject(VM& vm, Structure* structure) + : JSNonFinalObject(vm, structure) +{ +} + +AtomicsObject* AtomicsObject::create(VM& vm, JSGlobalObject* globalObject, Structure* structure) +{ + AtomicsObject* object = new (NotNull, allocateCell(vm.heap)) AtomicsObject(vm, structure); + object->finishCreation(vm, globalObject); + return object; +} + +Structure* AtomicsObject::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +{ + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); +} + +void AtomicsObject::finishCreation(VM& vm, JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + ASSERT(inherits(vm, info())); + +#define PUT_DIRECT_NATIVE_FUNC(lowerName, upperName, count) \ + putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, #lowerName), count, atomicsFunc ## upperName, Atomics ## upperName ## Intrinsic, DontEnum); + FOR_EACH_ATOMICS_FUNC(PUT_DIRECT_NATIVE_FUNC) +#undef PUT_DIRECT_NATIVE_FUNC +} + +namespace { + +template +EncodedJSValue atomicOperationWithArgsCase(ExecState* exec, ThrowScope& scope, JSArrayBufferView* typedArrayView, unsigned accessIndex, const Func& func) +{ + JSGenericTypedArrayView* typedArray = jsCast*>(typedArrayView); + + double extraArgs[numExtraArgs + 1]; // Add 1 to avoid 0 size array error in VS. + for (unsigned i = 0; i < numExtraArgs; ++i) { + double value = exec->argument(2 + i).toInteger(exec); + RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); + extraArgs[i] = value; + } + + return JSValue::encode(func(typedArray->typedVector() + accessIndex, extraArgs)); +} + +unsigned validatedAccessIndex(VM& vm, ExecState* exec, JSArrayBufferView* typedArrayView) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + JSValue accessIndexValue = exec->argument(1); + if (UNLIKELY(!accessIndexValue.isInt32())) { + double accessIndexDouble = accessIndexValue.toNumber(exec); + RETURN_IF_EXCEPTION(scope, 0); + if (accessIndexDouble == 0) + accessIndexValue = jsNumber(0); + else { + accessIndexValue = jsNumber(accessIndexDouble); + if (!accessIndexValue.isInt32()) { + throwRangeError(exec, scope, ASCIILiteral("Access index is not an integer.")); + return 0; + } + } + } + int32_t accessIndex = accessIndexValue.asInt32(); + + ASSERT(typedArrayView->length() <= static_cast(INT_MAX)); + if (static_cast(accessIndex) >= typedArrayView->length()) { + throwRangeError(exec, scope, ASCIILiteral("Access index out of bounds for atomic access.")); + return 0; + } + + return accessIndex; +} + +template +EncodedJSValue atomicOperationWithArgs(ExecState* exec, const Func& func) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSValue typedArrayValue = exec->argument(0); + if (!typedArrayValue.isCell()) { + throwTypeError(exec, scope, ASCIILiteral("Typed array argument must be a cell.")); + return JSValue::encode(jsUndefined()); + } + + JSCell* typedArrayCell = typedArrayValue.asCell(); + + JSType type = typedArrayCell->type(); + switch (type) { + case Int8ArrayType: + case Int16ArrayType: + case Int32ArrayType: + case Uint8ArrayType: + case Uint16ArrayType: + case Uint32ArrayType: + break; + default: + throwTypeError(exec, scope, ASCIILiteral("Typed array argument must be an Int8Array, Int16Array, Int32Array, Uint8Array, Uint16Array, or Uint32Array.")); + return JSValue::encode(jsUndefined()); + } + + JSArrayBufferView* typedArrayView = jsCast(typedArrayCell); + if (!typedArrayView->isShared()) { + throwTypeError(exec, scope, ASCIILiteral("Typed array argument must wrap a SharedArrayBuffer.")); + return JSValue::encode(jsUndefined()); + } + + unsigned accessIndex = validatedAccessIndex(vm, exec, typedArrayView); + RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); + + switch (type) { + case Int8ArrayType: + return atomicOperationWithArgsCase(exec, scope, typedArrayView, accessIndex, func); + case Int16ArrayType: + return atomicOperationWithArgsCase(exec, scope, typedArrayView, accessIndex, func); + case Int32ArrayType: + return atomicOperationWithArgsCase(exec, scope, typedArrayView, accessIndex, func); + case Uint8ArrayType: + return atomicOperationWithArgsCase(exec, scope, typedArrayView, accessIndex, func); + case Uint16ArrayType: + return atomicOperationWithArgsCase(exec, scope, typedArrayView, accessIndex, func); + case Uint32ArrayType: + return atomicOperationWithArgsCase(exec, scope, typedArrayView, accessIndex, func); + default: + RELEASE_ASSERT_NOT_REACHED(); + return JSValue::encode(jsUndefined()); + } +} + +} // anonymous namespace + +EncodedJSValue JSC_HOST_CALL atomicsFuncAdd(ExecState* exec) +{ + return atomicOperationWithArgs<1>( + exec, [&] (auto* ptr, const double* args) { + return jsNumber(WTF::atomicExchangeAdd(ptr, toInt32(args[0]))); + }); +} + +EncodedJSValue JSC_HOST_CALL atomicsFuncAnd(ExecState* exec) +{ + return atomicOperationWithArgs<1>( + exec, [&] (auto* ptr, const double* args) { + return jsNumber(WTF::atomicExchangeAnd(ptr, toInt32(args[0]))); + }); +} + +EncodedJSValue JSC_HOST_CALL atomicsFuncCompareExchange(ExecState* exec) +{ + return atomicOperationWithArgs<2>( + exec, [&] (auto* ptr, const double* args) { + typedef typename std::remove_pointer::type T; + T expected = static_cast(toInt32(args[0])); + T newValue = static_cast(toInt32(args[1])); + return jsNumber(WTF::atomicCompareExchangeStrong(ptr, expected, newValue)); + }); +} + +EncodedJSValue JSC_HOST_CALL atomicsFuncExchange(ExecState* exec) +{ + return atomicOperationWithArgs<1>( + exec, [&] (auto* ptr, const double* args) { + typedef typename std::remove_pointer::type T; + return jsNumber(WTF::atomicExchange(ptr, static_cast(toInt32(args[0])))); + }); +} + +EncodedJSValue JSC_HOST_CALL atomicsFuncIsLockFree(ExecState* exec) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + int32_t size = exec->argument(0).toInt32(exec); + RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); + + bool result; + switch (size) { + case 1: + case 2: + case 4: + result = true; + break; + default: + result = false; + break; + } + return JSValue::encode(jsBoolean(result)); +} + +EncodedJSValue JSC_HOST_CALL atomicsFuncLoad(ExecState* exec) +{ + return atomicOperationWithArgs<0>( + exec, [&] (auto* ptr, const double*) { + return jsNumber(WTF::atomicLoad(ptr)); + }); +} + +EncodedJSValue JSC_HOST_CALL atomicsFuncOr(ExecState* exec) +{ + return atomicOperationWithArgs<1>( + exec, [&] (auto* ptr, const double* args) { + return jsNumber(WTF::atomicExchangeOr(ptr, toInt32(args[0]))); + }); +} + +EncodedJSValue JSC_HOST_CALL atomicsFuncStore(ExecState* exec) +{ + return atomicOperationWithArgs<1>( + exec, [&] (auto* ptr, const double* args) { + typedef typename std::remove_pointer::type T; + double valueAsInt = args[0]; + T valueAsT = static_cast(toInt32(valueAsInt)); + WTF::atomicStore(ptr, valueAsT); + return jsNumber(valueAsInt); + }); +} + +EncodedJSValue JSC_HOST_CALL atomicsFuncSub(ExecState* exec) +{ + return atomicOperationWithArgs<1>( + exec, [&] (auto* ptr, const double* args) { + return jsNumber(WTF::atomicExchangeSub(ptr, toInt32(args[0]))); + }); +} + +EncodedJSValue JSC_HOST_CALL atomicsFuncWait(ExecState* exec) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSInt32Array* typedArray = jsDynamicCast(vm, exec->argument(0)); + if (!typedArray) { + throwTypeError(exec, scope, ASCIILiteral("Typed array for wait/wake must be an Int32Array.")); + return JSValue::encode(jsUndefined()); + } + + if (!typedArray->isShared()) { + throwTypeError(exec, scope, ASCIILiteral("Typed array for wait/wake must wrap a SharedArrayBuffer.")); + return JSValue::encode(jsUndefined()); + } + + unsigned accessIndex = validatedAccessIndex(vm, exec, typedArray); + RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); + + int32_t* ptr = typedArray->typedVector() + accessIndex; + + int32_t expectedValue = exec->argument(2).toInt32(exec); + RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); + + double timeoutInMilliseconds = exec->argument(3).toNumber(exec); + RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); + + if (!vm.m_typedArrayController->isAtomicsWaitAllowedOnCurrentThread()) { + throwTypeError(exec, scope, ASCIILiteral("Atomics.wait cannot be called from the current thread.")); + return JSValue::encode(jsUndefined()); + } + + Seconds timeout = Seconds::fromMilliseconds(timeoutInMilliseconds); + + // This covers the proposed rule: + // + // 4. If timeout is not provided or is undefined then let t be +inf. Otherwise: + // a. Let q be ? ToNumber(timeout). + // b. If q is NaN then let t be +inf, otherwise let t be max(0, q). + // + // exec->argument(3) returns undefined if it's not provided and ToNumber(undefined) returns NaN, + // so NaN is the only special case. + if (timeout == timeout) + timeout = std::max(0_s, timeout); + else + timeout = Seconds::infinity(); + + bool didPassValidation = false; + ParkingLot::ParkResult result; + { + ReleaseHeapAccessScope releaseHeapAccessScope(vm.heap); + result = ParkingLot::parkConditionally( + ptr, + [&] () -> bool { + didPassValidation = WTF::atomicLoad(ptr) == expectedValue; + return didPassValidation; + }, + [] () { }, + MonotonicTime::now() + timeout); + } + const char* resultString; + if (!didPassValidation) + resultString = "not-equal"; + else if (!result.wasUnparked) + resultString = "timed-out"; + else + resultString = "ok"; + return JSValue::encode(jsString(exec, ASCIILiteral(resultString))); +} + +EncodedJSValue JSC_HOST_CALL atomicsFuncWake(ExecState* exec) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSInt32Array* typedArray = jsDynamicCast(vm, exec->argument(0)); + if (!typedArray) { + throwTypeError(exec, scope, ASCIILiteral("Typed array for wait/wake must be an Int32Array.")); + return JSValue::encode(jsUndefined()); + } + + if (!typedArray->isShared()) { + throwTypeError(exec, scope, ASCIILiteral("Typed array for wait/wake must wrap a SharedArrayBuffer.")); + return JSValue::encode(jsUndefined()); + } + + unsigned accessIndex = validatedAccessIndex(vm, exec, typedArray); + RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); + + int32_t* ptr = typedArray->typedVector() + accessIndex; + + JSValue countValue = exec->argument(2); + unsigned count = UINT_MAX; + if (!countValue.isUndefined()) { + int32_t countInt = countValue.toInt32(exec); + RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); + count = std::max(0, countInt); + } + + return JSValue::encode(jsNumber(ParkingLot::unparkCount(ptr, count))); +} + +EncodedJSValue JSC_HOST_CALL atomicsFuncXor(ExecState* exec) +{ + return atomicOperationWithArgs<1>( + exec, [&] (auto* ptr, const double* args) { + return jsNumber(WTF::atomicExchangeXor(ptr, toInt32(args[0]))); + }); +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/AtomicsObject.h b/Source/JavaScriptCore/runtime/AtomicsObject.h new file mode 100644 index 000000000..e8144ce50 --- /dev/null +++ b/Source/JavaScriptCore/runtime/AtomicsObject.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "JSObject.h" + +namespace JSC { + +class AtomicsObject : public JSNonFinalObject { +private: + AtomicsObject(VM&, Structure*); + +public: + typedef JSNonFinalObject Base; + + static AtomicsObject* create(VM&, JSGlobalObject*, Structure*); + + DECLARE_INFO; + + static Structure* createStructure(VM&, JSGlobalObject*, JSValue); + +protected: + void finishCreation(VM&, JSGlobalObject*); +}; + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/AuxiliaryBarrier.h b/Source/JavaScriptCore/runtime/AuxiliaryBarrier.h new file mode 100644 index 000000000..3b7322f13 --- /dev/null +++ b/Source/JavaScriptCore/runtime/AuxiliaryBarrier.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +namespace JSC { + +class JSCell; +class VM; + +// An Auxiliary barrier is a barrier that does not try to reason about the value being stored into +// it, other than interpreting a falsy value as not needing a barrier. It's OK to use this for either +// JSCells or any other kind of data, so long as it responds to operator!(). +template +class AuxiliaryBarrier { +public: + AuxiliaryBarrier(): m_value() { } + + template + AuxiliaryBarrier(VM&, JSCell*, U&&); + + void clear() { m_value = T(); } + + template + void set(VM&, JSCell*, U&&); + + const T& get() const { return m_value; } + + T* slot() { return &m_value; } + + explicit operator bool() const { return !!m_value; } + + template + void setWithoutBarrier(U&& value) { m_value = std::forward(value); } + +private: + T m_value; +}; + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/AuxiliaryBarrierInlines.h b/Source/JavaScriptCore/runtime/AuxiliaryBarrierInlines.h new file mode 100644 index 000000000..6d4e789f0 --- /dev/null +++ b/Source/JavaScriptCore/runtime/AuxiliaryBarrierInlines.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "AuxiliaryBarrier.h" +#include "Heap.h" +#include "VM.h" + +namespace JSC { + +template +template +AuxiliaryBarrier::AuxiliaryBarrier(VM& vm, JSCell* owner, U&& value) +{ + m_value = std::forward(value); + vm.heap.writeBarrier(owner); +} + +template +template +void AuxiliaryBarrier::set(VM& vm, JSCell* owner, U&& value) +{ + m_value = std::forward(value); + vm.heap.writeBarrier(owner); +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/BasicBlockLocation.cpp b/Source/JavaScriptCore/runtime/BasicBlockLocation.cpp new file mode 100644 index 000000000..d97b0370d --- /dev/null +++ b/Source/JavaScriptCore/runtime/BasicBlockLocation.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 Saam Barati. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "BasicBlockLocation.h" + +#include "CCallHelpers.h" +#include +#include + +namespace JSC { + +BasicBlockLocation::BasicBlockLocation(int startOffset, int endOffset) + : m_startOffset(startOffset) + , m_endOffset(endOffset) + , m_executionCount(0) +{ +} + +void BasicBlockLocation::insertGap(int startOffset, int endOffset) +{ + std::pair gap(startOffset, endOffset); + if (!m_gaps.contains(gap)) + m_gaps.append(gap); +} + +Vector> BasicBlockLocation::getExecutedRanges() const +{ + Vector result; + Vector gaps = m_gaps; + int nextRangeStart = m_startOffset; + while (gaps.size()) { + Gap minGap(INT_MAX, 0); + unsigned minIdx = std::numeric_limits::max(); + for (unsigned idx = 0; idx < gaps.size(); idx++) { + // Because we know that the Gaps inside m_gaps aren't enclosed within one another, it suffices to just check the first element to test ordering. + if (gaps[idx].first < minGap.first) { + minGap = gaps[idx]; + minIdx = idx; + } + } + result.append(Gap(nextRangeStart, minGap.first - 1)); + nextRangeStart = minGap.second + 1; + gaps.remove(minIdx); + } + + result.append(Gap(nextRangeStart, m_endOffset)); + return result; +} + +void BasicBlockLocation::dumpData() const +{ + Vector executedRanges = getExecutedRanges(); + for (Gap gap : executedRanges) + dataLogF("\tBasicBlock: [%d, %d] hasExecuted: %s, executionCount:%zu\n", gap.first, gap.second, hasExecuted() ? "true" : "false", m_executionCount); +} + +#if ENABLE(JIT) +#if USE(JSVALUE64) +void BasicBlockLocation::emitExecuteCode(CCallHelpers& jit) const +{ + static_assert(sizeof(size_t) == 8, "Assuming size_t is 64 bits on 64 bit platforms."); + jit.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(&m_executionCount)); +} +#else +void BasicBlockLocation::emitExecuteCode(CCallHelpers& jit, MacroAssembler::RegisterID scratch) const +{ + static_assert(sizeof(size_t) == 4, "Assuming size_t is 32 bits on 32 bit platforms."); + jit.load32(&m_executionCount, scratch); + CCallHelpers::Jump done = jit.branchAdd32(CCallHelpers::Zero, scratch, CCallHelpers::TrustedImm32(1), scratch); + jit.store32(scratch, bitwise_cast(&m_executionCount)); + done.link(&jit); +} +#endif // USE(JSVALUE64) +#endif // ENABLE(JIT) + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/BasicBlockLocation.h b/Source/JavaScriptCore/runtime/BasicBlockLocation.h new file mode 100644 index 000000000..3ece6478f --- /dev/null +++ b/Source/JavaScriptCore/runtime/BasicBlockLocation.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * Copyright (C) 2014 Saam Barati. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "MacroAssembler.h" +#include +#include + +namespace JSC { + +class CCallHelpers; +class LLIntOffsetsExtractor; + +class BasicBlockLocation { +public: + typedef std::pair Gap; + + BasicBlockLocation(int startOffset = -1, int endOffset = -1); + + int startOffset() const { return m_startOffset; } + int endOffset() const { return m_endOffset; } + void setStartOffset(int startOffset) { m_startOffset = startOffset; } + void setEndOffset(int endOffset) { m_endOffset = endOffset; } + bool hasExecuted() const { return m_executionCount > 0; } + size_t executionCount() const { return m_executionCount; } + void insertGap(int, int); + Vector getExecutedRanges() const; + JS_EXPORT_PRIVATE void dumpData() const; +#if ENABLE(JIT) +#if USE(JSVALUE64) + void emitExecuteCode(CCallHelpers&) const; +#else + void emitExecuteCode(CCallHelpers&, MacroAssembler::RegisterID scratch) const; +#endif +#endif + +private: + friend class LLIntOffsetsExtractor; + + int m_startOffset; + int m_endOffset; + size_t m_executionCount; + Vector m_gaps; +}; + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h index 76def7138..601414ce0 100644 --- a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h +++ b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h @@ -11,10 +11,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,8 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef BatchedTransitionOptimizer_h -#define BatchedTransitionOptimizer_h +#pragma once #include "JSObject.h" @@ -35,22 +34,10 @@ class BatchedTransitionOptimizer { WTF_MAKE_NONCOPYABLE(BatchedTransitionOptimizer); public: BatchedTransitionOptimizer(VM& vm, JSObject* object) - : m_vm(&vm) - , m_object(object) { + if (!object->structure(vm)->isDictionary()) + object->convertToDictionary(vm); } - - ~BatchedTransitionOptimizer() - { - if (m_object->structure()->isDictionary()) - m_object->flattenDictionaryObject(*m_vm); - } - -private: - VM* m_vm; - JSObject* m_object; }; } // namespace JSC - -#endif // BatchedTransitionOptimizer_h diff --git a/Source/JavaScriptCore/runtime/BigInteger.h b/Source/JavaScriptCore/runtime/BigInteger.h index 0a0c477c2..6b0df5945 100644 --- a/Source/JavaScriptCore/runtime/BigInteger.h +++ b/Source/JavaScriptCore/runtime/BigInteger.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef BigInteger_h -#define BigInteger_h +#pragma once #include @@ -106,7 +105,4 @@ private: Vector m_values; }; -} - -#endif - +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp index 09fa26096..a0fff5840 100644 --- a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp +++ b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2008, 2016 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,13 +23,13 @@ #include "BooleanPrototype.h" #include "JSGlobalObject.h" -#include "Operations.h" +#include "JSCInlines.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(BooleanConstructor); -const ClassInfo BooleanConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(BooleanConstructor) }; +const ClassInfo BooleanConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(BooleanConstructor) }; BooleanConstructor::BooleanConstructor(VM& vm, Structure* structure) : InternalFunction(vm, structure) @@ -46,23 +46,22 @@ void BooleanConstructor::finishCreation(VM& vm, BooleanPrototype* booleanPrototy } // ECMA 15.6.2 -JSObject* constructBoolean(ExecState* exec, const ArgList& args) -{ - BooleanObject* obj = BooleanObject::create(exec->vm(), asInternalFunction(exec->callee())->globalObject()->booleanObjectStructure()); - obj->setInternalValue(exec->vm(), jsBoolean(args.at(0).toBoolean(exec))); - return obj; -} - static EncodedJSValue JSC_HOST_CALL constructWithBooleanConstructor(ExecState* exec) { - ArgList args(exec); - return JSValue::encode(constructBoolean(exec, args)); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSValue boolean = jsBoolean(exec->argument(0).toBoolean(exec)); + Structure* booleanStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), asInternalFunction(exec->jsCallee())->globalObject()->booleanObjectStructure()); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + BooleanObject* obj = BooleanObject::create(vm, booleanStructure); + obj->setInternalValue(vm, boolean); + return JSValue::encode(obj); } ConstructType BooleanConstructor::getConstructData(JSCell*, ConstructData& constructData) { constructData.native.function = constructWithBooleanConstructor; - return ConstructTypeHost; + return ConstructType::Host; } // ECMA 15.6.1 @@ -74,7 +73,7 @@ static EncodedJSValue JSC_HOST_CALL callBooleanConstructor(ExecState* exec) CallType BooleanConstructor::getCallData(JSCell*, CallData& callData) { callData.native.function = callBooleanConstructor; - return CallTypeHost; + return CallType::Host; } JSObject* constructBooleanFromImmediateBoolean(ExecState* exec, JSGlobalObject* globalObject, JSValue immediateBooleanValue) diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.h b/Source/JavaScriptCore/runtime/BooleanConstructor.h index 177f69e5c..bb8c5df2b 100644 --- a/Source/JavaScriptCore/runtime/BooleanConstructor.h +++ b/Source/JavaScriptCore/runtime/BooleanConstructor.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2016 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,20 +18,20 @@ * */ -#ifndef BooleanConstructor_h -#define BooleanConstructor_h +#pragma once #include "InternalFunction.h" namespace JSC { class BooleanPrototype; +class GetterSetter; class BooleanConstructor : public InternalFunction { public: typedef InternalFunction Base; - static BooleanConstructor* create(VM& vm, Structure* structure, BooleanPrototype* booleanPrototype) + static BooleanConstructor* create(VM& vm, Structure* structure, BooleanPrototype* booleanPrototype, GetterSetter*) { BooleanConstructor* constructor = new (NotNull, allocateCell(vm.heap)) BooleanConstructor(vm, structure); constructor->finishCreation(vm, booleanPrototype); @@ -55,8 +55,5 @@ private: }; JSObject* constructBooleanFromImmediateBoolean(ExecState*, JSGlobalObject*, JSValue); -JSObject* constructBoolean(ExecState*, const ArgList&); } // namespace JSC - -#endif // BooleanConstructor_h diff --git a/Source/JavaScriptCore/runtime/BooleanObject.cpp b/Source/JavaScriptCore/runtime/BooleanObject.cpp index 2c6092aa3..76439896c 100644 --- a/Source/JavaScriptCore/runtime/BooleanObject.cpp +++ b/Source/JavaScriptCore/runtime/BooleanObject.cpp @@ -22,13 +22,13 @@ #include "BooleanObject.h" #include "JSScope.h" -#include "Operations.h" +#include "JSCInlines.h" namespace JSC { STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(BooleanObject); -const ClassInfo BooleanObject::s_info = { "Boolean", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(BooleanObject) }; +const ClassInfo BooleanObject::s_info = { "Boolean", &JSWrapperObject::s_info, 0, CREATE_METHOD_TABLE(BooleanObject) }; BooleanObject::BooleanObject(VM& vm, Structure* structure) : JSWrapperObject(vm, structure) @@ -38,7 +38,7 @@ BooleanObject::BooleanObject(VM& vm, Structure* structure) void BooleanObject::finishCreation(VM& vm) { Base::finishCreation(vm); - ASSERT(inherits(info())); + ASSERT(inherits(vm, info())); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/BooleanObject.h b/Source/JavaScriptCore/runtime/BooleanObject.h index 6944db496..9e5aaf9b1 100644 --- a/Source/JavaScriptCore/runtime/BooleanObject.h +++ b/Source/JavaScriptCore/runtime/BooleanObject.h @@ -18,8 +18,7 @@ * */ -#ifndef BooleanObject_h -#define BooleanObject_h +#pragma once #include "JSWrapperObject.h" @@ -52,10 +51,8 @@ BooleanObject* asBooleanObject(JSValue); inline BooleanObject* asBooleanObject(JSValue value) { - ASSERT(asObject(value)->inherits(BooleanObject::info())); + ASSERT(asObject(value)->inherits(*value.getObject()->vm(), BooleanObject::info())); return static_cast(asObject(value)); } } // namespace JSC - -#endif // BooleanObject_h diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp index c73ead8be..c815ac01d 100644 --- a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp +++ b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2008, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2008, 2011, 2016 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,7 +26,7 @@ #include "JSFunction.h" #include "JSString.h" #include "ObjectPrototype.h" -#include "Operations.h" +#include "JSCInlines.h" namespace JSC { @@ -39,7 +39,7 @@ static EncodedJSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState*); namespace JSC { -const ClassInfo BooleanPrototype::s_info = { "Boolean", &BooleanObject::s_info, 0, ExecState::booleanPrototypeTable, CREATE_METHOD_TABLE(BooleanPrototype) }; +const ClassInfo BooleanPrototype::s_info = { "Boolean", &BooleanObject::s_info, &booleanPrototypeTable, CREATE_METHOD_TABLE(BooleanPrototype) }; /* Source for BooleanPrototype.lut.h @begin booleanPrototypeTable @@ -60,44 +60,42 @@ void BooleanPrototype::finishCreation(VM& vm, JSGlobalObject*) Base::finishCreation(vm); setInternalValue(vm, jsBoolean(false)); - ASSERT(inherits(info())); -} - -bool BooleanPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) -{ - return getStaticFunctionSlot(exec, ExecState::booleanPrototypeTable(exec->vm()), jsCast(object), propertyName, slot); + ASSERT(inherits(vm, info())); } // ------------------------------ Functions --------------------------- EncodedJSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState* exec) { - VM* vm = &exec->vm(); - JSValue thisValue = exec->hostThisValue(); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSValue thisValue = exec->thisValue(); if (thisValue == jsBoolean(false)) - return JSValue::encode(vm->smallStrings.falseString()); + return JSValue::encode(vm.smallStrings.falseString()); if (thisValue == jsBoolean(true)) - return JSValue::encode(vm->smallStrings.trueString()); + return JSValue::encode(vm.smallStrings.trueString()); - if (!thisValue.inherits(BooleanObject::info())) - return throwVMTypeError(exec); + if (!thisValue.inherits(vm, BooleanObject::info())) + return throwVMTypeError(exec, scope); if (asBooleanObject(thisValue)->internalValue() == jsBoolean(false)) - return JSValue::encode(vm->smallStrings.falseString()); + return JSValue::encode(vm.smallStrings.falseString()); ASSERT(asBooleanObject(thisValue)->internalValue() == jsBoolean(true)); - return JSValue::encode(vm->smallStrings.trueString()); + return JSValue::encode(vm.smallStrings.trueString()); } EncodedJSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState* exec) { - JSValue thisValue = exec->hostThisValue(); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSValue thisValue = exec->thisValue(); if (thisValue.isBoolean()) return JSValue::encode(thisValue); - if (!thisValue.inherits(BooleanObject::info())) - return throwVMTypeError(exec); + if (!thisValue.inherits(vm, BooleanObject::info())) + return throwVMTypeError(exec, scope); return JSValue::encode(asBooleanObject(thisValue)->internalValue()); } diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.h b/Source/JavaScriptCore/runtime/BooleanPrototype.h index 35ece4bd3..41a239d36 100644 --- a/Source/JavaScriptCore/runtime/BooleanPrototype.h +++ b/Source/JavaScriptCore/runtime/BooleanPrototype.h @@ -18,8 +18,7 @@ * */ -#ifndef BooleanPrototype_h -#define BooleanPrototype_h +#pragma once #include "BooleanObject.h" @@ -28,6 +27,7 @@ namespace JSC { class BooleanPrototype : public BooleanObject { public: typedef BooleanObject Base; + static const unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable; static BooleanPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) { @@ -45,13 +45,9 @@ public: protected: void finishCreation(VM&, JSGlobalObject*); - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | BooleanObject::StructureFlags; private: BooleanPrototype(VM&, Structure*); - static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); }; } // namespace JSC - -#endif // BooleanPrototype_h diff --git a/Source/JavaScriptCore/runtime/BundlePath.h b/Source/JavaScriptCore/runtime/BundlePath.h new file mode 100644 index 000000000..3b700d44c --- /dev/null +++ b/Source/JavaScriptCore/runtime/BundlePath.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +namespace JSC { + +const CString& bundlePath(); + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/Butterfly.h b/Source/JavaScriptCore/runtime/Butterfly.h index 04554ab71..8ed39b0bc 100644 --- a/Source/JavaScriptCore/runtime/Butterfly.h +++ b/Source/JavaScriptCore/runtime/Butterfly.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,14 +23,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef Butterfly_h -#define Butterfly_h +#pragma once #include "IndexingHeader.h" #include "PropertyOffset.h" #include "PropertyStorage.h" #include -#include namespace JSC { @@ -91,6 +89,12 @@ public: return reinterpret_cast(static_cast(base) + preCapacity + propertyCapacity + 1); } + ALWAYS_INLINE static unsigned availableContiguousVectorLength(size_t propertyCapacity, unsigned vectorLength); + static unsigned availableContiguousVectorLength(Structure*, unsigned vectorLength); + + ALWAYS_INLINE static unsigned optimalContiguousVectorLength(size_t propertyCapacity, unsigned vectorLength); + static unsigned optimalContiguousVectorLength(Structure*, unsigned vectorLength); + // This method is here not just because it's handy, but to remind you that // the whole point of butterflies is to do evil pointer arithmetic. static Butterfly* fromPointer(char* ptr) @@ -107,9 +111,9 @@ public: static Butterfly* createUninitialized(VM&, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes); + static Butterfly* tryCreate(VM& vm, JSCell*, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes); static Butterfly* create(VM&, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader&, size_t indexingPayloadSizeInBytes); static Butterfly* create(VM&, JSCell* intendedOwner, Structure*); - static Butterfly* createUninitializedDuringCollection(CopyVisitor&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes); IndexingHeader* indexingHeader() { return IndexingHeader::from(this); } const IndexingHeader* indexingHeader() const { return IndexingHeader::from(this); } @@ -158,9 +162,7 @@ public: // methods is not exhaustive and is not intended to encapsulate all possible allocation // modes of butterflies - there are code paths that allocate butterflies by calling // directly into Heap::tryAllocateStorage. - Butterfly* growPropertyStorage(VM&, JSCell* intendedOwner, size_t preCapacity, size_t oldPropertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity); - Butterfly* growPropertyStorage(VM&, JSCell* intendedOwner, Structure* oldStructure, size_t oldPropertyCapacity, size_t newPropertyCapacity); - Butterfly* growPropertyStorage(VM&, JSCell* intendedOwner, Structure* oldStructure, size_t newPropertyCapacity); + static Butterfly* createOrGrowPropertyStorage(Butterfly*, VM&, JSCell* intendedOwner, Structure*, size_t oldPropertyCapacity, size_t newPropertyCapacity); Butterfly* growArrayRight(VM&, JSCell* intendedOwner, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newIndexingPayloadSizeInBytes); // Assumes that preCapacity is zero, and asserts as much. Butterfly* growArrayRight(VM&, JSCell* intendedOwner, Structure*, size_t newIndexingPayloadSizeInBytes); Butterfly* resizeArray(VM&, JSCell* intendedOwner, size_t propertyCapacity, bool oldHasIndexingHeader, size_t oldIndexingPayloadSizeInBytes, size_t newPreCapacity, bool newHasIndexingHeader, size_t newIndexingPayloadSizeInBytes); @@ -170,6 +172,3 @@ public: }; } // namespace JSC - -#endif // Butterfly_h - diff --git a/Source/JavaScriptCore/runtime/ButterflyInlines.h b/Source/JavaScriptCore/runtime/ButterflyInlines.h index f5439bb02..88c6f8a67 100644 --- a/Source/JavaScriptCore/runtime/ButterflyInlines.h +++ b/Source/JavaScriptCore/runtime/ButterflyInlines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012-2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,34 +23,68 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ButterflyInlines_h -#define ButterflyInlines_h +#pragma once #include "ArrayStorage.h" #include "Butterfly.h" -#include "CopiedSpaceInlines.h" -#include "CopyVisitor.h" #include "VM.h" #include "Structure.h" namespace JSC { -inline Butterfly* Butterfly::createUninitialized(VM& vm, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) +ALWAYS_INLINE unsigned Butterfly::availableContiguousVectorLength(size_t propertyCapacity, unsigned vectorLength) +{ + size_t cellSize = totalSize(0, propertyCapacity, true, sizeof(EncodedJSValue) * vectorLength); + cellSize = MarkedSpace::optimalSizeFor(cellSize); + vectorLength = (cellSize - totalSize(0, propertyCapacity, true, 0)) / sizeof(EncodedJSValue); + return vectorLength; +} + +ALWAYS_INLINE unsigned Butterfly::availableContiguousVectorLength(Structure* structure, unsigned vectorLength) +{ + return availableContiguousVectorLength(structure ? structure->outOfLineCapacity() : 0, vectorLength); +} + +ALWAYS_INLINE unsigned Butterfly::optimalContiguousVectorLength(size_t propertyCapacity, unsigned vectorLength) +{ + if (!vectorLength) + vectorLength = BASE_CONTIGUOUS_VECTOR_LEN_EMPTY; + else + vectorLength = std::max(BASE_CONTIGUOUS_VECTOR_LEN, vectorLength); + return availableContiguousVectorLength(propertyCapacity, vectorLength); +} + +ALWAYS_INLINE unsigned Butterfly::optimalContiguousVectorLength(Structure* structure, unsigned vectorLength) +{ + return optimalContiguousVectorLength(structure ? structure->outOfLineCapacity() : 0, vectorLength); +} + +inline Butterfly* Butterfly::createUninitialized(VM& vm, JSCell*, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) { - void* temp; size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); - RELEASE_ASSERT(vm.heap.tryAllocateStorage(intendedOwner, size, &temp)); - Butterfly* result = fromBase(temp, preCapacity, propertyCapacity); + void* base = vm.auxiliarySpace.allocate(size); + Butterfly* result = fromBase(base, preCapacity, propertyCapacity); return result; } -inline Butterfly* Butterfly::create(VM& vm, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes) +inline Butterfly* Butterfly::tryCreate(VM& vm, JSCell*, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes) { - Butterfly* result = createUninitialized( - vm, intendedOwner, preCapacity, propertyCapacity, hasIndexingHeader, - indexingPayloadSizeInBytes); + size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); + void* base = vm.auxiliarySpace.tryAllocate(size); + if (!base) + return nullptr; + Butterfly* result = fromBase(base, preCapacity, propertyCapacity); if (hasIndexingHeader) *result->indexingHeader() = indexingHeader; + memset(result->propertyStorage() - propertyCapacity, 0, propertyCapacity * sizeof(EncodedJSValue)); + return result; +} + +inline Butterfly* Butterfly::create(VM& vm, JSCell* intendedOwner, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader& indexingHeader, size_t indexingPayloadSizeInBytes) +{ + Butterfly* result = tryCreate(vm, intendedOwner, preCapacity, propertyCapacity, hasIndexingHeader, indexingHeader, indexingPayloadSizeInBytes); + + RELEASE_ASSERT(result); return result; } @@ -61,53 +95,34 @@ inline Butterfly* Butterfly::create(VM& vm, JSCell* intendedOwner, Structure* st structure->hasIndexingHeader(intendedOwner), IndexingHeader(), 0); } -inline Butterfly* Butterfly::createUninitializedDuringCollection(CopyVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) -{ - size_t size = totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); - Butterfly* result = fromBase( - visitor.allocateNewSpace(size), - preCapacity, propertyCapacity); - return result; -} - inline void* Butterfly::base(Structure* structure) { return base(indexingHeader()->preCapacity(structure), structure->outOfLineCapacity()); } -inline Butterfly* Butterfly::growPropertyStorage( - VM& vm, JSCell* intendedOwner, size_t preCapacity, size_t oldPropertyCapacity, - bool hasIndexingHeader, size_t indexingPayloadSizeInBytes, size_t newPropertyCapacity) +inline Butterfly* Butterfly::createOrGrowPropertyStorage( + Butterfly* oldButterfly, VM& vm, JSCell* intendedOwner, Structure* structure, size_t oldPropertyCapacity, size_t newPropertyCapacity) { RELEASE_ASSERT(newPropertyCapacity > oldPropertyCapacity); + if (!oldButterfly) + return create(vm, intendedOwner, 0, newPropertyCapacity, false, IndexingHeader(), 0); + + size_t preCapacity = oldButterfly->indexingHeader()->preCapacity(structure); + size_t indexingPayloadSizeInBytes = oldButterfly->indexingHeader()->indexingPayloadSizeInBytes(structure); + bool hasIndexingHeader = structure->hasIndexingHeader(intendedOwner); Butterfly* result = createUninitialized( - vm, intendedOwner, preCapacity, newPropertyCapacity, hasIndexingHeader, - indexingPayloadSizeInBytes); + vm, intendedOwner, preCapacity, newPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); memcpy( result->propertyStorage() - oldPropertyCapacity, - propertyStorage() - oldPropertyCapacity, + oldButterfly->propertyStorage() - oldPropertyCapacity, totalSize(0, oldPropertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes)); + memset( + result->propertyStorage() - newPropertyCapacity, + 0, + (newPropertyCapacity - oldPropertyCapacity) * sizeof(EncodedJSValue)); return result; } -inline Butterfly* Butterfly::growPropertyStorage( - VM& vm, JSCell* intendedOwner, Structure* structure, size_t oldPropertyCapacity, - size_t newPropertyCapacity) -{ - return growPropertyStorage( - vm, intendedOwner, indexingHeader()->preCapacity(structure), oldPropertyCapacity, - structure->hasIndexingHeader(intendedOwner), - indexingHeader()->indexingPayloadSizeInBytes(structure), newPropertyCapacity); -} - -inline Butterfly* Butterfly::growPropertyStorage( - VM& vm, JSCell* intendedOwner, Structure* oldStructure, size_t newPropertyCapacity) -{ - return growPropertyStorage( - vm, intendedOwner, oldStructure, oldStructure->outOfLineCapacity(), - newPropertyCapacity); -} - inline Butterfly* Butterfly::createOrGrowArrayRight( Butterfly* oldButterfly, VM& vm, JSCell* intendedOwner, Structure* oldStructure, size_t propertyCapacity, bool hadIndexingHeader, size_t oldIndexingPayloadSizeInBytes, @@ -129,13 +144,16 @@ inline Butterfly* Butterfly::growArrayRight( size_t newIndexingPayloadSizeInBytes) { ASSERT_UNUSED(oldStructure, !indexingHeader()->preCapacity(oldStructure)); - ASSERT_UNUSED(oldStructure, hadIndexingHeader == oldStructure->hasIndexingHeader(intendedOwner)); + ASSERT_UNUSED(intendedOwner, hadIndexingHeader == oldStructure->hasIndexingHeader(intendedOwner)); void* theBase = base(0, propertyCapacity); size_t oldSize = totalSize(0, propertyCapacity, hadIndexingHeader, oldIndexingPayloadSizeInBytes); size_t newSize = totalSize(0, propertyCapacity, true, newIndexingPayloadSizeInBytes); - if (!vm.heap.tryReallocateStorage(intendedOwner, &theBase, oldSize, newSize)) - return 0; - return fromBase(theBase, 0, propertyCapacity); + void* newBase = vm.auxiliarySpace.tryAllocate(newSize); + if (!newBase) + return nullptr; + // FIXME: This probably shouldn't be a memcpy. + memcpy(newBase, theBase, oldSize); + return fromBase(newBase, 0, propertyCapacity); } inline Butterfly* Butterfly::growArrayRight( @@ -181,7 +199,7 @@ inline Butterfly* Butterfly::resizeArray( inline Butterfly* Butterfly::unshift(Structure* structure, size_t numberOfSlots) { - ASSERT(hasArrayStorage(structure->indexingType())); + ASSERT(hasAnyArrayStorage(structure->indexingType())); ASSERT(numberOfSlots <= indexingHeader()->preCapacity(structure)); unsigned propertyCapacity = structure->outOfLineCapacity(); // FIXME: It would probably be wise to rewrite this as a loop since (1) we know in which @@ -200,7 +218,7 @@ inline Butterfly* Butterfly::unshift(Structure* structure, size_t numberOfSlots) inline Butterfly* Butterfly::shift(Structure* structure, size_t numberOfSlots) { - ASSERT(hasArrayStorage(structure->indexingType())); + ASSERT(hasAnyArrayStorage(structure->indexingType())); unsigned propertyCapacity = structure->outOfLineCapacity(); // FIXME: See comment in unshift(), above. memmove( @@ -211,6 +229,3 @@ inline Butterfly* Butterfly::shift(Structure* structure, size_t numberOfSlots) } } // namespace JSC - -#endif // ButterflyInlines_h - diff --git a/Source/JavaScriptCore/runtime/CallData.cpp b/Source/JavaScriptCore/runtime/CallData.cpp index cf0ba7992..4402c6214 100644 --- a/Source/JavaScriptCore/runtime/CallData.cpp +++ b/Source/JavaScriptCore/runtime/CallData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2016 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,17 +26,43 @@ #include "config.h" #include "CallData.h" -#include "Executable.h" #include "Interpreter.h" +#include "JSCInlines.h" #include "JSFunction.h" -#include "Operations.h" +#include "ScriptProfilingScope.h" namespace JSC { JSValue call(ExecState* exec, JSValue functionObject, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args) { - ASSERT(callType == CallTypeJS || callType == CallTypeHost); + ASSERT(callType == CallType::JS || callType == CallType::Host); return exec->interpreter()->executeCall(exec, asObject(functionObject), callType, callData, thisValue, args); } +JSValue call(ExecState* exec, JSValue functionObject, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args, NakedPtr& returnedException) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_CATCH_SCOPE(vm); + JSValue result = call(exec, functionObject, callType, callData, thisValue, args); + if (UNLIKELY(scope.exception())) { + returnedException = scope.exception(); + scope.clearException(); + return jsUndefined(); + } + RELEASE_ASSERT(result); + return result; +} + +JSValue profiledCall(ExecState* exec, ProfilingReason reason, JSValue functionObject, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args) +{ + ScriptProfilingScope profilingScope(exec->vmEntryGlobalObject(), reason); + return call(exec, functionObject, callType, callData, thisValue, args); +} + +JSValue profiledCall(ExecState* exec, ProfilingReason reason, JSValue functionObject, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args, NakedPtr& returnedException) +{ + ScriptProfilingScope profilingScope(exec->vmEntryGlobalObject(), reason); + return call(exec, functionObject, callType, callData, thisValue, args, returnedException); +} + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/CallData.h b/Source/JavaScriptCore/runtime/CallData.h index 3bbac734f..53043aaf1 100644 --- a/Source/JavaScriptCore/runtime/CallData.h +++ b/Source/JavaScriptCore/runtime/CallData.h @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -26,39 +26,50 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CallData_h -#define CallData_h +#pragma once #include "JSCJSValue.h" +#include namespace JSC { class ArgList; +class Exception; class ExecState; class FunctionExecutable; class JSObject; class JSScope; -enum CallType { - CallTypeNone, - CallTypeHost, - CallTypeJS +enum class CallType : unsigned { + None, + Host, + JS }; typedef EncodedJSValue (JSC_HOST_CALL *NativeFunction)(ExecState*); -union CallData { - struct { - NativeFunction function; - } native; - struct { - FunctionExecutable* functionExecutable; - JSScope* scope; - } js; +struct CallData { + union { + struct { + NativeFunction function; + } native; + struct { + FunctionExecutable* functionExecutable; + JSScope* scope; + } js; + }; +}; + +enum class ProfilingReason { + API, + Microtask, + Other }; JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&); +JS_EXPORT_PRIVATE JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&, NakedPtr& returnedException); -} // namespace JSC +JS_EXPORT_PRIVATE JSValue profiledCall(ExecState*, ProfilingReason, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&); +JS_EXPORT_PRIVATE JSValue profiledCall(ExecState*, ProfilingReason, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&, NakedPtr& returnedException); -#endif // CallData_h +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/CatchScope.cpp b/Source/JavaScriptCore/runtime/CatchScope.cpp new file mode 100644 index 000000000..f7bb37ab9 --- /dev/null +++ b/Source/JavaScriptCore/runtime/CatchScope.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CatchScope.h" + +namespace JSC { + +#if ENABLE(EXCEPTION_SCOPE_VERIFICATION) + +CatchScope::CatchScope(VM& vm, ExceptionEventLocation location) + : ExceptionScope(vm, location) +{ + m_vm.verifyExceptionCheckNeedIsSatisfied(m_recursionDepth, m_location); +} + +CatchScope::~CatchScope() +{ + RELEASE_ASSERT(m_vm.m_topExceptionScope); + m_vm.verifyExceptionCheckNeedIsSatisfied(m_recursionDepth, m_location); +} + +#endif // ENABLE(EXCEPTION_SCOPE_VERIFICATION) + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/CatchScope.h b/Source/JavaScriptCore/runtime/CatchScope.h new file mode 100644 index 000000000..1f2a8e714 --- /dev/null +++ b/Source/JavaScriptCore/runtime/CatchScope.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "ExceptionScope.h" + +namespace JSC { + +#if ENABLE(EXCEPTION_SCOPE_VERIFICATION) + +// If a function can clear JS exceptions, it should declare a CatchScope at the +// top of the function (as early as possible) using the DECLARE_CATCH_SCOPE macro. +// Declaring a CatchScope in a function means that the function intends to clear +// pending exceptions before returning to its caller. + +class CatchScope : public ExceptionScope { +public: + JS_EXPORT_PRIVATE CatchScope(VM&, ExceptionEventLocation); + CatchScope(const CatchScope&) = delete; + CatchScope(CatchScope&&) = default; + + JS_EXPORT_PRIVATE ~CatchScope(); + + void clearException() { m_vm.clearException(); } +}; + +#define DECLARE_CATCH_SCOPE(vm__) \ + JSC::CatchScope((vm__), JSC::ExceptionEventLocation(__FUNCTION__, __FILE__, __LINE__)) + +#else // not ENABLE(EXCEPTION_SCOPE_VERIFICATION) + +class CatchScope : public ExceptionScope { +public: + ALWAYS_INLINE CatchScope(VM& vm) + : ExceptionScope(vm) + { } + CatchScope(const CatchScope&) = delete; + CatchScope(CatchScope&&) = default; + + ALWAYS_INLINE void clearException() { m_vm.clearException(); } +}; + +#define DECLARE_CATCH_SCOPE(vm__) \ + JSC::CatchScope((vm__)) + +#endif // ENABLE(EXCEPTION_SCOPE_VERIFICATION) + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/ClassInfo.h b/Source/JavaScriptCore/runtime/ClassInfo.h index 8ff75f4eb..480aea220 100644 --- a/Source/JavaScriptCore/runtime/ClassInfo.h +++ b/Source/JavaScriptCore/runtime/ClassInfo.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003-2017 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -20,17 +20,15 @@ * */ -#ifndef ClassInfo_h -#define ClassInfo_h +#pragma once #include "CallFrame.h" #include "ConstructData.h" -#include "CopyToken.h" #include "JSCell.h" namespace JSC { -class HashEntry; +class HeapSnapshotBuilder; class JSArrayBufferView; struct HashTable; @@ -40,20 +38,17 @@ struct MethodTable { typedef void (*VisitChildrenFunctionPtr)(JSCell*, SlotVisitor&); VisitChildrenFunctionPtr visitChildren; - - typedef void (*CopyBackingStoreFunctionPtr)(JSCell*, CopyVisitor&, CopyToken); - CopyBackingStoreFunctionPtr copyBackingStore; - + typedef CallType (*GetCallDataFunctionPtr)(JSCell*, CallData&); GetCallDataFunctionPtr getCallData; typedef ConstructType (*GetConstructDataFunctionPtr)(JSCell*, ConstructData&); GetConstructDataFunctionPtr getConstructData; - typedef void (*PutFunctionPtr)(JSCell*, ExecState*, PropertyName propertyName, JSValue, PutPropertySlot&); + typedef bool (*PutFunctionPtr)(JSCell*, ExecState*, PropertyName propertyName, JSValue, PutPropertySlot&); PutFunctionPtr put; - typedef void (*PutByIndexFunctionPtr)(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); + typedef bool (*PutByIndexFunctionPtr)(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow); PutByIndexFunctionPtr putByIndex; typedef bool (*DeletePropertyFunctionPtr)(JSCell*, ExecState*, PropertyName); @@ -83,9 +78,18 @@ struct MethodTable { typedef void (*GetPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); GetPropertyNamesFunctionPtr getPropertyNames; + typedef uint32_t (*GetEnumerableLengthFunctionPtr)(ExecState*, JSObject*); + GetEnumerableLengthFunctionPtr getEnumerableLength; + + GetPropertyNamesFunctionPtr getStructurePropertyNames; + GetPropertyNamesFunctionPtr getGenericPropertyNames; + typedef String (*ClassNameFunctionPtr)(const JSObject*); ClassNameFunctionPtr className; + typedef String (*ToStringNameFunctionPtr)(const JSObject*, ExecState*); + ToStringNameFunctionPtr toStringName; + typedef bool (*CustomHasInstanceFunctionPtr)(JSObject*, ExecState*, JSValue); CustomHasInstanceFunctionPtr customHasInstance; @@ -95,8 +99,32 @@ struct MethodTable { typedef ArrayBuffer* (*SlowDownAndWasteMemory)(JSArrayBufferView*); SlowDownAndWasteMemory slowDownAndWasteMemory; - typedef PassRefPtr (*GetTypedArrayImpl)(JSArrayBufferView*); + typedef RefPtr (*GetTypedArrayImpl)(JSArrayBufferView*); GetTypedArrayImpl getTypedArrayImpl; + + typedef bool (*PreventExtensionsFunctionPtr)(JSObject*, ExecState*); + PreventExtensionsFunctionPtr preventExtensions; + + typedef bool (*IsExtensibleFunctionPtr)(JSObject*, ExecState*); + IsExtensibleFunctionPtr isExtensible; + + typedef bool (*SetPrototypeFunctionPtr)(JSObject*, ExecState*, JSValue, bool shouldThrowIfCantSet); + SetPrototypeFunctionPtr setPrototype; + + typedef JSValue (*GetPrototypeFunctionPtr)(JSObject*, ExecState*); + GetPrototypeFunctionPtr getPrototype; + + typedef void (*DumpToStreamFunctionPtr)(const JSCell*, PrintStream&); + DumpToStreamFunctionPtr dumpToStream; + + typedef void (*HeapSnapshotFunctionPtr)(JSCell*, HeapSnapshotBuilder&); + HeapSnapshotFunctionPtr heapSnapshot; + + typedef size_t (*EstimatedSizeFunctionPtr)(JSCell*); + EstimatedSizeFunctionPtr estimatedSize; + + typedef void (*VisitOutputConstraintsPtr)(JSCell*, SlotVisitor&); + VisitOutputConstraintsPtr visitOutputConstraints; }; #define CREATE_MEMBER_CHECKER(member) \ @@ -121,7 +149,6 @@ struct MethodTable { #define CREATE_METHOD_TABLE(ClassName) { \ &ClassName::destroy, \ &ClassName::visitChildren, \ - &ClassName::copyBackingStore, \ &ClassName::getCallData, \ &ClassName::getConstructData, \ &ClassName::put, \ @@ -135,11 +162,23 @@ struct MethodTable { &ClassName::getOwnPropertyNames, \ &ClassName::getOwnNonIndexPropertyNames, \ &ClassName::getPropertyNames, \ + &ClassName::getEnumerableLength, \ + &ClassName::getStructurePropertyNames, \ + &ClassName::getGenericPropertyNames, \ &ClassName::className, \ + &ClassName::toStringName, \ &ClassName::customHasInstance, \ &ClassName::defineOwnProperty, \ &ClassName::slowDownAndWasteMemory, \ - &ClassName::getTypedArrayImpl \ + &ClassName::getTypedArrayImpl, \ + &ClassName::preventExtensions, \ + &ClassName::isExtensible, \ + &ClassName::setPrototype, \ + &ClassName::getPrototype, \ + &ClassName::dumpToStream, \ + &ClassName::heapSnapshot, \ + &ClassName::estimatedSize, \ + &ClassName::visitOutputConstraints \ }, \ ClassName::TypedArrayStorageType @@ -151,25 +190,6 @@ struct ClassInfo { // nullptrif there is none. const ClassInfo* parentClass; - // Static hash-table of properties. - // For classes that can be used from multiple threads, it is accessed via a getter function - // that would typically return a pointer to a thread-specific value. - const HashTable* propHashTable(ExecState* exec) const - { - if (classPropHashTableGetterFunction) - return &classPropHashTableGetterFunction(exec->vm()); - - return staticPropHashTable; - } - - const HashTable* propHashTable(VM& vm) const - { - if (classPropHashTableGetterFunction) - return &classPropHashTableGetterFunction(vm); - - return staticPropHashTable; - } - bool isSubClassOf(const ClassInfo* other) const { for (const ClassInfo* ci = this; ci; ci = ci->parentClass) { @@ -179,20 +199,9 @@ struct ClassInfo { return false; } - bool hasStaticProperties() const - { - for (const ClassInfo* ci = this; ci; ci = ci->parentClass) { - if (ci->staticPropHashTable || ci->classPropHashTableGetterFunction) - return true; - } - return false; - } - - bool hasStaticSetterOrReadonlyProperties(VM&) const; + JS_EXPORT_PRIVATE bool hasStaticSetterOrReadonlyProperties() const; const HashTable* staticPropHashTable; - typedef const HashTable& (*ClassPropHashTableGetterFunction)(VM&); - const ClassPropHashTableGetterFunction classPropHashTableGetterFunction; MethodTable methodTable; @@ -200,5 +209,3 @@ struct ClassInfo { }; } // namespace JSC - -#endif // ClassInfo_h diff --git a/Source/JavaScriptCore/runtime/ClonedArguments.cpp b/Source/JavaScriptCore/runtime/ClonedArguments.cpp new file mode 100644 index 000000000..b7bdfadbc --- /dev/null +++ b/Source/JavaScriptCore/runtime/ClonedArguments.cpp @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2015-2017 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ClonedArguments.h" + +#include "GetterSetter.h" +#include "InlineCallFrame.h" +#include "JSCInlines.h" + +namespace JSC { + +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ClonedArguments); + +const ClassInfo ClonedArguments::s_info = { "Arguments", &Base::s_info, 0, CREATE_METHOD_TABLE(ClonedArguments) }; + +ClonedArguments::ClonedArguments(VM& vm, Structure* structure, Butterfly* butterfly) + : Base(vm, structure, butterfly) +{ +} + +ClonedArguments* ClonedArguments::createEmpty( + VM& vm, Structure* structure, JSFunction* callee, unsigned length) +{ + unsigned vectorLength = length; + if (vectorLength > MAX_STORAGE_VECTOR_LENGTH) + return 0; + + Butterfly* butterfly; + if (UNLIKELY(structure->needsSlowPutIndexing())) { + butterfly = createArrayStorageButterfly(vm, nullptr, structure, length, vectorLength); + butterfly->arrayStorage()->m_numValuesInVector = vectorLength; + + } else { + void* temp = vm.auxiliarySpace.tryAllocate(Butterfly::totalSize(0, structure->outOfLineCapacity(), true, vectorLength * sizeof(EncodedJSValue))); + if (!temp) + return 0; + butterfly = Butterfly::fromBase(temp, 0, structure->outOfLineCapacity()); + butterfly->setVectorLength(vectorLength); + butterfly->setPublicLength(length); + + for (unsigned i = length; i < vectorLength; ++i) + butterfly->contiguous()[i].clear(); + } + + ClonedArguments* result = + new (NotNull, allocateCell(vm.heap)) + ClonedArguments(vm, structure, butterfly); + result->finishCreation(vm); + + result->m_callee.set(vm, result, callee); + result->putDirect(vm, clonedArgumentsLengthPropertyOffset, jsNumber(length)); + return result; +} + +ClonedArguments* ClonedArguments::createEmpty(ExecState* exec, JSFunction* callee, unsigned length) +{ + VM& vm = exec->vm(); + // NB. Some clients might expect that the global object of of this object is the global object + // of the callee. We don't do this for now, but maybe we should. + ClonedArguments* result = createEmpty(vm, exec->lexicalGlobalObject()->clonedArgumentsStructure(), callee, length); + ASSERT(!result->structure(vm)->needsSlowPutIndexing() || shouldUseSlowPut(result->structure(vm)->indexingType())); + return result; +} + +ClonedArguments* ClonedArguments::createWithInlineFrame(ExecState* myFrame, ExecState* targetFrame, InlineCallFrame* inlineCallFrame, ArgumentsMode mode) +{ + VM& vm = myFrame->vm(); + + JSFunction* callee; + + if (inlineCallFrame) + callee = jsCast(inlineCallFrame->calleeRecovery.recover(targetFrame)); + else + callee = jsCast(targetFrame->jsCallee()); + + ClonedArguments* result = nullptr; + + unsigned length = 0; // Initialize because VC needs it. + switch (mode) { + case ArgumentsMode::Cloned: { + if (inlineCallFrame) { + if (inlineCallFrame->argumentCountRegister.isValid()) + length = targetFrame->r(inlineCallFrame->argumentCountRegister).unboxedInt32(); + else + length = inlineCallFrame->arguments.size(); + length--; + result = createEmpty(myFrame, callee, length); + + for (unsigned i = length; i--;) + result->initializeIndex(vm, i, inlineCallFrame->arguments[i + 1].recover(targetFrame)); + } else { + length = targetFrame->argumentCount(); + result = createEmpty(myFrame, callee, length); + + for (unsigned i = length; i--;) + result->initializeIndex(vm, i, targetFrame->uncheckedArgument(i)); + } + break; + } + + case ArgumentsMode::FakeValues: { + result = createEmpty(myFrame, callee, 0); + break; + } } + + ASSERT(myFrame->lexicalGlobalObject()->clonedArgumentsStructure() == result->structure()); + ASSERT(!result->structure(vm)->needsSlowPutIndexing() || shouldUseSlowPut(result->structure(vm)->indexingType())); + return result; +} + +ClonedArguments* ClonedArguments::createWithMachineFrame(ExecState* myFrame, ExecState* targetFrame, ArgumentsMode mode) +{ + ClonedArguments* result = createWithInlineFrame(myFrame, targetFrame, nullptr, mode); + ASSERT(!result->structure()->needsSlowPutIndexing() || shouldUseSlowPut(result->structure()->indexingType())); + return result; +} + +ClonedArguments* ClonedArguments::createByCopyingFrom( + ExecState* exec, Structure* structure, Register* argumentStart, unsigned length, + JSFunction* callee) +{ + VM& vm = exec->vm(); + ClonedArguments* result = createEmpty(vm, structure, callee, length); + + for (unsigned i = length; i--;) + result->initializeIndex(vm, i, argumentStart[i].jsValue()); + ASSERT(!result->structure(vm)->needsSlowPutIndexing() || shouldUseSlowPut(result->structure(vm)->indexingType())); + return result; +} + +Structure* ClonedArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType) +{ + Structure* structure = Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), indexingType); + PropertyOffset offset; + structure = structure->addPropertyTransition(vm, structure, vm.propertyNames->length, DontEnum, offset); + ASSERT(offset == clonedArgumentsLengthPropertyOffset); + return structure; +} + +Structure* ClonedArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +{ + // We use contiguous storage because optimizations in the FTL assume that cloned arguments creation always produces the same initial structure. + return createStructure(vm, globalObject, prototype, NonArrayWithContiguous); +} + +Structure* ClonedArguments::createSlowPutStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +{ + return createStructure(vm, globalObject, prototype, NonArrayWithSlowPutArrayStorage); +} + +bool ClonedArguments::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName ident, PropertySlot& slot) +{ + ClonedArguments* thisObject = jsCast(object); + VM& vm = exec->vm(); + + if (!thisObject->specialsMaterialized()) { + FunctionExecutable* executable = jsCast(thisObject->m_callee->executable()); + bool isStrictMode = executable->isStrictMode(); + + if (ident == vm.propertyNames->callee) { + if (isStrictMode) { + slot.setGetterSlot(thisObject, DontDelete | DontEnum | Accessor, thisObject->globalObject()->throwTypeErrorArgumentsCalleeAndCallerGetterSetter()); + return true; + } + slot.setValue(thisObject, 0, thisObject->m_callee.get()); + return true; + } + + if (ident == vm.propertyNames->iteratorSymbol) { + slot.setValue(thisObject, DontEnum, thisObject->globalObject()->arrayProtoValuesFunction()); + return true; + } + } + + return Base::getOwnPropertySlot(thisObject, exec, ident, slot); +} + +void ClonedArguments::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode) +{ + ClonedArguments* thisObject = jsCast(object); + thisObject->materializeSpecialsIfNecessary(exec); + Base::getOwnPropertyNames(thisObject, exec, array, mode); +} + +bool ClonedArguments::put(JSCell* cell, ExecState* exec, PropertyName ident, JSValue value, PutPropertySlot& slot) +{ + ClonedArguments* thisObject = jsCast(cell); + VM& vm = exec->vm(); + + if (ident == vm.propertyNames->callee + || ident == vm.propertyNames->iteratorSymbol) { + thisObject->materializeSpecialsIfNecessary(exec); + PutPropertySlot dummy = slot; // Shadow the given PutPropertySlot to prevent caching. + return Base::put(thisObject, exec, ident, value, dummy); + } + + return Base::put(thisObject, exec, ident, value, slot); +} + +bool ClonedArguments::deleteProperty(JSCell* cell, ExecState* exec, PropertyName ident) +{ + ClonedArguments* thisObject = jsCast(cell); + VM& vm = exec->vm(); + + if (ident == vm.propertyNames->callee + || ident == vm.propertyNames->iteratorSymbol) + thisObject->materializeSpecialsIfNecessary(exec); + + return Base::deleteProperty(thisObject, exec, ident); +} + +bool ClonedArguments::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName ident, const PropertyDescriptor& descriptor, bool shouldThrow) +{ + ClonedArguments* thisObject = jsCast(object); + VM& vm = exec->vm(); + + if (ident == vm.propertyNames->callee + || ident == vm.propertyNames->iteratorSymbol) + thisObject->materializeSpecialsIfNecessary(exec); + + return Base::defineOwnProperty(object, exec, ident, descriptor, shouldThrow); +} + +void ClonedArguments::materializeSpecials(ExecState* exec) +{ + RELEASE_ASSERT(!specialsMaterialized()); + VM& vm = exec->vm(); + + FunctionExecutable* executable = jsCast(m_callee->executable()); + bool isStrictMode = executable->isStrictMode(); + + if (isStrictMode) + putDirectAccessor(exec, vm.propertyNames->callee, globalObject()->throwTypeErrorArgumentsCalleeAndCallerGetterSetter(), DontDelete | DontEnum | Accessor); + else + putDirect(vm, vm.propertyNames->callee, JSValue(m_callee.get())); + + putDirect(vm, vm.propertyNames->iteratorSymbol, globalObject()->arrayProtoValuesFunction(), DontEnum); + + m_callee.clear(); +} + +void ClonedArguments::materializeSpecialsIfNecessary(ExecState* exec) +{ + if (!specialsMaterialized()) + materializeSpecials(exec); +} + +void ClonedArguments::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + ClonedArguments* thisObject = jsCast(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); + visitor.append(thisObject->m_callee); +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/ClonedArguments.h b/Source/JavaScriptCore/runtime/ClonedArguments.h new file mode 100644 index 000000000..7601c5c91 --- /dev/null +++ b/Source/JavaScriptCore/runtime/ClonedArguments.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2015-2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "ArgumentsMode.h" +#include "JSObject.h" + +namespace JSC { + +// This is an Arguments-class object that we create when you do function.arguments, or you say +// "arguments" inside a function in strict mode. It behaves almpst entirely like an ordinary +// JavaScript object. All of the arguments values are simply copied from the stack (possibly via +// some sophisticated ValueRecovery's if an optimizing compiler is in play) and the appropriate +// properties of the object are populated. The only reason why we need a special class is to make +// the object claim to be "Arguments" from a toString standpoint, and to avoid materializing the +// caller/callee/@@iterator properties unless someone asks for them. +class ClonedArguments : public JSNonFinalObject { +public: + typedef JSNonFinalObject Base; + static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames; + +private: + ClonedArguments(VM&, Structure*, Butterfly*); + +public: + static ClonedArguments* createEmpty(VM&, Structure*, JSFunction* callee, unsigned length); + static ClonedArguments* createEmpty(ExecState*, JSFunction* callee, unsigned length); + static ClonedArguments* createWithInlineFrame(ExecState* myFrame, ExecState* targetFrame, InlineCallFrame*, ArgumentsMode); + static ClonedArguments* createWithMachineFrame(ExecState* myFrame, ExecState* targetFrame, ArgumentsMode); + static ClonedArguments* createByCopyingFrom(ExecState*, Structure*, Register* argumentsStart, unsigned length, JSFunction* callee); + + static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); + static Structure* createSlowPutStructure(VM&, JSGlobalObject*, JSValue prototype); + + static void visitChildren(JSCell*, SlotVisitor&); + + DECLARE_INFO; + +private: + static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype, IndexingType); + + static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + static bool deleteProperty(JSCell*, ExecState*, PropertyName); + static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); + + bool specialsMaterialized() const { return !m_callee; } + void materializeSpecials(ExecState*); + void materializeSpecialsIfNecessary(ExecState*); + + WriteBarrier m_callee; // Set to nullptr when we materialize all of our special properties. +}; + +static const PropertyOffset clonedArgumentsLengthPropertyOffset = 100; + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp index 510e383fa..6c1c0c05c 100644 --- a/Source/JavaScriptCore/runtime/CodeCache.cpp +++ b/Source/JavaScriptCore/runtime/CodeCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All Rights Reserved. + * Copyright (C) 2012, 2016 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,15 +24,9 @@ */ #include "config.h" - #include "CodeCache.h" -#include "BytecodeGenerator.h" -#include "CodeSpecializationKind.h" -#include "Operations.h" -#include "Parser.h" -#include "StrongInlines.h" -#include "UnlinkedCodeBlock.h" +#include "IndirectEvalExecutable.h" namespace JSC { @@ -54,117 +48,117 @@ void CodeCacheMap::pruneSlowCase() } } -CodeCache::CodeCache() -{ -} - -CodeCache::~CodeCache() -{ -} - -template struct CacheTypes { }; - -template <> struct CacheTypes { - typedef JSC::ProgramNode RootNode; - static const SourceCodeKey::CodeType codeType = SourceCodeKey::ProgramType; -}; - -template <> struct CacheTypes { - typedef JSC::EvalNode RootNode; - static const SourceCodeKey::CodeType codeType = SourceCodeKey::EvalType; -}; - template -UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +UnlinkedCodeBlockType* CodeCache::getUnlinkedGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType) { - SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes::codeType, strictness); - CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue()); - bool canCache = debuggerMode == DebuggerOff && profilerMode == ProfilerOff; - if (!addResult.isNewEntry && canCache) { - UnlinkedCodeBlockType* unlinkedCodeBlock = jsCast(addResult.iterator->value.cell.get()); - unsigned firstLine = source.firstLine() + unlinkedCodeBlock->firstLine(); + DerivedContextType derivedContextType = executable->derivedContextType(); + bool isArrowFunctionContext = executable->isArrowFunctionContext(); + SourceCodeKey key( + source, String(), CacheTypes::codeType, strictMode, scriptMode, + derivedContextType, evalContextType, isArrowFunctionContext, debuggerMode, + vm.typeProfiler() ? TypeProfilerEnabled::Yes : TypeProfilerEnabled::No, + vm.controlFlowProfiler() ? ControlFlowProfilerEnabled::Yes : ControlFlowProfilerEnabled::No); + SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key); + if (cache && Options::useCodeCache()) { + UnlinkedCodeBlockType* unlinkedCodeBlock = jsCast(cache->cell.get()); unsigned lineCount = unlinkedCodeBlock->lineCount(); - unsigned startColumn = unlinkedCodeBlock->startColumn() + source.startColumn(); + unsigned startColumn = unlinkedCodeBlock->startColumn() + source.startColumn().oneBasedInt(); bool endColumnIsOnStartLine = !lineCount; unsigned endColumn = unlinkedCodeBlock->endColumn() + (endColumnIsOnStartLine ? startColumn : 1); - executable->recordParse(unlinkedCodeBlock->codeFeatures(), unlinkedCodeBlock->hasCapturedVariables(), firstLine, firstLine + lineCount, startColumn, endColumn); + executable->recordParse(unlinkedCodeBlock->codeFeatures(), unlinkedCodeBlock->hasCapturedVariables(), source.firstLine().oneBasedInt() + lineCount, endColumn); + source.provider()->setSourceURLDirective(unlinkedCodeBlock->sourceURLDirective()); + source.provider()->setSourceMappingURLDirective(unlinkedCodeBlock->sourceMappingURLDirective()); return unlinkedCodeBlock; } + + VariableEnvironment variablesUnderTDZ; + UnlinkedCodeBlockType* unlinkedCodeBlock = generateUnlinkedCodeBlock(vm, executable, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ); - typedef typename CacheTypes::RootNode RootNode; - RefPtr rootNode = parse(&vm, source, 0, Identifier(), strictness, JSParseProgramCode, error); - if (!rootNode) { - m_sourceCode.remove(addResult.iterator); - return 0; - } - unsigned lineCount = rootNode->lastLine() - rootNode->lineNo(); - unsigned startColumn = rootNode->startColumn() + 1; - bool endColumnIsOnStartLine = !lineCount; - unsigned unlinkedEndColumn = rootNode->endColumn(); - unsigned endColumn = unlinkedEndColumn + (endColumnIsOnStartLine ? startColumn : 1); - executable->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo(), rootNode->lastLine(), startColumn, endColumn); - - UnlinkedCodeBlockType* unlinkedCodeBlock = UnlinkedCodeBlockType::create(&vm, executable->executableInfo()); - unlinkedCodeBlock->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo() - source.firstLine(), lineCount, unlinkedEndColumn); - - OwnPtr generator(adoptPtr(new BytecodeGenerator(vm, rootNode.get(), unlinkedCodeBlock, debuggerMode, profilerMode))); - error = generator->generate(); - rootNode->destroyData(); - if (error.m_type != ParserError::ErrorNone) { - m_sourceCode.remove(addResult.iterator); - return 0; - } - - if (!canCache) { - m_sourceCode.remove(addResult.iterator); - return unlinkedCodeBlock; - } + if (unlinkedCodeBlock && Options::useCodeCache()) + m_sourceCode.addCache(key, SourceCodeValue(vm, unlinkedCodeBlock, m_sourceCode.age())); - addResult.iterator->value = SourceCodeValue(vm, unlinkedCodeBlock, m_sourceCode.age()); return unlinkedCodeBlock; } -UnlinkedProgramCodeBlock* CodeCache::getProgramCodeBlock(VM& vm, ProgramExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +UnlinkedProgramCodeBlock* CodeCache::getUnlinkedProgramCodeBlock(VM& vm, ProgramExecutable* executable, const SourceCode& source, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ParserError& error) { - return getGlobalCodeBlock(vm, executable, source, strictness, debuggerMode, profilerMode, error); + return getUnlinkedGlobalCodeBlock(vm, executable, source, strictMode, JSParserScriptMode::Classic, debuggerMode, error, EvalContextType::None); } -UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, EvalExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error) +UnlinkedEvalCodeBlock* CodeCache::getUnlinkedEvalCodeBlock(VM& vm, IndirectEvalExecutable* executable, const SourceCode& source, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType) { - return getGlobalCodeBlock(vm, executable, source, strictness, debuggerMode, profilerMode, error); + return getUnlinkedGlobalCodeBlock(vm, executable, source, strictMode, JSParserScriptMode::Classic, debuggerMode, error, evalContextType); } -UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& vm, const Identifier& name, const SourceCode& source, ParserError& error) +UnlinkedModuleProgramCodeBlock* CodeCache::getUnlinkedModuleProgramCodeBlock(VM& vm, ModuleProgramExecutable* executable, const SourceCode& source, DebuggerMode debuggerMode, ParserError& error) { - SourceCodeKey key = SourceCodeKey(source, name.string(), SourceCodeKey::FunctionType, JSParseNormal); - CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue()); - if (!addResult.isNewEntry) - return jsCast(addResult.iterator->value.cell.get()); + return getUnlinkedGlobalCodeBlock(vm, executable, source, JSParserStrictMode::Strict, JSParserScriptMode::Module, debuggerMode, error, EvalContextType::None); +} + +UnlinkedFunctionExecutable* CodeCache::getUnlinkedGlobalFunctionExecutable(VM& vm, const Identifier& name, const SourceCode& source, DebuggerMode debuggerMode, ParserError& error) +{ + bool isArrowFunctionContext = false; + SourceCodeKey key( + source, name.string(), SourceCodeType::FunctionType, + JSParserStrictMode::NotStrict, + JSParserScriptMode::Classic, + DerivedContextType::None, + EvalContextType::None, + isArrowFunctionContext, + debuggerMode, + vm.typeProfiler() ? TypeProfilerEnabled::Yes : TypeProfilerEnabled::No, + vm.controlFlowProfiler() ? ControlFlowProfilerEnabled::Yes : ControlFlowProfilerEnabled::No); + SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key); + if (cache && Options::useCodeCache()) { + UnlinkedFunctionExecutable* executable = jsCast(cache->cell.get()); + source.provider()->setSourceURLDirective(executable->sourceURLDirective()); + source.provider()->setSourceMappingURLDirective(executable->sourceMappingURLDirective()); + return executable; + } JSTextPosition positionBeforeLastNewline; - RefPtr program = parse(&vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error, &positionBeforeLastNewline); + std::unique_ptr program = parse( + &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin, + JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, + error, &positionBeforeLastNewline); if (!program) { - ASSERT(error.m_type != ParserError::ErrorNone); - m_sourceCode.remove(addResult.iterator); - return 0; + RELEASE_ASSERT(error.isValid()); + return nullptr; } - // This function assumes an input string that would result in a single anonymous function expression. - StatementNode* exprStatement = program->singleStatement(); - ASSERT(exprStatement); - ASSERT(exprStatement->isExprStatement()); - ExpressionNode* funcExpr = static_cast(exprStatement)->expr(); - ASSERT(funcExpr); - RELEASE_ASSERT(funcExpr->isFuncExprNode()); - FunctionBodyNode* body = static_cast(funcExpr)->body(); - body->setEndPosition(positionBeforeLastNewline); - ASSERT(body); - ASSERT(body->ident().isNull()); - - UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, body, true); - functionExecutable->m_nameValue.set(vm, functionExecutable, jsString(&vm, name.string())); - - addResult.iterator->value = SourceCodeValue(vm, functionExecutable, m_sourceCode.age()); + // This function assumes an input string that would result in a single function declaration. + StatementNode* statement = program->singleStatement(); + if (UNLIKELY(!statement)) { + JSToken token; + error = ParserError(ParserError::SyntaxError, ParserError::SyntaxErrorIrrecoverable, token, "Parser error", -1); + return nullptr; + } + ASSERT(statement->isBlock()); + + StatementNode* funcDecl = static_cast(statement)->singleStatement(); + if (UNLIKELY(!funcDecl)) { + JSToken token; + error = ParserError(ParserError::SyntaxError, ParserError::SyntaxErrorIrrecoverable, token, "Parser error", -1); + return nullptr; + } + ASSERT(funcDecl->isFuncDeclNode()); + + FunctionMetadataNode* metadata = static_cast(funcDecl)->metadata(); + ASSERT(metadata); + if (!metadata) + return nullptr; + + metadata->overrideName(name); + metadata->setEndPosition(positionBeforeLastNewline); + // The Function constructor only has access to global variables, so no variables will be under TDZ. + VariableEnvironment emptyTDZVariables; + ConstructAbility constructAbility = constructAbilityForParseMode(metadata->parseMode()); + UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, constructAbility, JSParserScriptMode::Classic, emptyTDZVariables, DerivedContextType::None); + + functionExecutable->setSourceURLDirective(source.provider()->sourceURL()); + functionExecutable->setSourceMappingURLDirective(source.provider()->sourceMappingURL()); + + m_sourceCode.addCache(key, SourceCodeValue(vm, functionExecutable, m_sourceCode.age())); return functionExecutable; } diff --git a/Source/JavaScriptCore/runtime/CodeCache.h b/Source/JavaScriptCore/runtime/CodeCache.h index f3ff7478d..b4ab8e56c 100644 --- a/Source/JavaScriptCore/runtime/CodeCache.h +++ b/Source/JavaScriptCore/runtime/CodeCache.h @@ -23,96 +23,42 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CodeCache_h -#define CodeCache_h +#pragma once -#include "CodeSpecializationKind.h" +#include "BytecodeGenerator.h" +#include "ExecutableInfo.h" +#include "JSCInlines.h" +#include "Parser.h" #include "ParserModes.h" -#include "SourceCode.h" +#include "SourceCodeKey.h" #include "Strong.h" -#include "WeakRandom.h" +#include "StrongInlines.h" +#include "UnlinkedCodeBlock.h" +#include "UnlinkedEvalCodeBlock.h" +#include "UnlinkedModuleProgramCodeBlock.h" +#include "UnlinkedProgramCodeBlock.h" +#include "UnlinkedSourceCode.h" #include #include -#include -#include #include namespace JSC { class EvalExecutable; -class FunctionBodyNode; +class IndirectEvalExecutable; class Identifier; -class JSScope; +class DirectEvalExecutable; +class ModuleProgramExecutable; +class ParserError; class ProgramExecutable; +class SourceCode; class UnlinkedCodeBlock; class UnlinkedEvalCodeBlock; -class UnlinkedFunctionCodeBlock; class UnlinkedFunctionExecutable; +class UnlinkedModuleProgramCodeBlock; class UnlinkedProgramCodeBlock; class VM; -struct ParserError; -class SourceCode; -class SourceProvider; - -class SourceCodeKey { -public: - enum CodeType { EvalType, ProgramType, FunctionType }; - - SourceCodeKey() - { - } - - SourceCodeKey(const SourceCode& sourceCode, const String& name, CodeType codeType, JSParserStrictness jsParserStrictness) - : m_sourceCode(sourceCode) - , m_name(name) - , m_flags((codeType << 1) | jsParserStrictness) - , m_hash(string().impl()->hash()) - { - } - - SourceCodeKey(WTF::HashTableDeletedValueType) - : m_sourceCode(WTF::HashTableDeletedValue) - { - } - - bool isHashTableDeletedValue() const { return m_sourceCode.isHashTableDeletedValue(); } - - unsigned hash() const { return m_hash; } - - size_t length() const { return m_sourceCode.length(); } - - bool isNull() const { return m_sourceCode.isNull(); } - - // To save memory, we compute our string on demand. It's expected that source - // providers cache their strings to make this efficient. - String string() const { return m_sourceCode.toString(); } - - bool operator==(const SourceCodeKey& other) const - { - return m_hash == other.m_hash - && length() == other.length() - && m_flags == other.m_flags - && m_name == other.m_name - && string() == other.string(); - } - -private: - SourceCode m_sourceCode; - String m_name; - unsigned m_flags; - unsigned m_hash; -}; - -struct SourceCodeKeyHash { - static unsigned hash(const SourceCodeKey& key) { return key.hash(); } - static bool equal(const SourceCodeKey& a, const SourceCodeKey& b) { return a == b; } - static const bool safeToCompareToEmptyOrDeleted = false; -}; - -struct SourceCodeKeyHashTraits : SimpleClassHashTraits { - static const bool hasIsEmptyValueFunction = true; - static bool isEmptyValue(const SourceCodeKey& sourceCodeKey) { return sourceCodeKey.isNull(); } -}; +class VariableEnvironment; struct SourceCodeValue { SourceCodeValue() @@ -131,7 +77,7 @@ struct SourceCodeValue { class CodeCacheMap { public: - typedef HashMap MapType; + typedef HashMap MapType; typedef MapType::iterator iterator; typedef MapType::AddResult AddResult; @@ -145,18 +91,15 @@ public: { } - AddResult add(const SourceCodeKey& key, const SourceCodeValue& value) + SourceCodeValue* findCacheAndUpdateAge(const SourceCodeKey& key) { prune(); - AddResult addResult = m_map.add(key, value); - if (addResult.isNewEntry) { - m_size += key.length(); - m_age += key.length(); - return addResult; - } + iterator findResult = m_map.find(key); + if (findResult == m_map.end()) + return nullptr; - int64_t age = m_age - addResult.iterator->value.age; + int64_t age = m_age - findResult->value.age; if (age > m_capacity) { // A requested object is older than the cache's capacity. We can // infer that requested objects are subject to high eviction probability, @@ -171,7 +114,20 @@ public: m_capacity = m_minCapacity; } - addResult.iterator->value.age = m_age; + findResult->value.age = m_age; + m_age += key.length(); + + return &findResult->value; + } + + AddResult addCache(const SourceCodeKey& key, const SourceCodeValue& value) + { + prune(); + + AddResult addResult = m_map.add(key, value); + ASSERT(addResult.isNewEntry); + + m_size += key.length(); m_age += key.length(); return addResult; } @@ -233,30 +189,73 @@ private: int64_t m_age; }; -// Caches top-level code such as