summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/runtime')
-rw-r--r--Source/JavaScriptCore/runtime/ArgList.cpp11
-rw-r--r--Source/JavaScriptCore/runtime/ArgList.h21
-rw-r--r--Source/JavaScriptCore/runtime/Arguments.cpp387
-rw-r--r--Source/JavaScriptCore/runtime/Arguments.h298
-rw-r--r--Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.cpp61
-rw-r--r--Source/JavaScriptCore/runtime/ArgumentsMode.h39
-rw-r--r--Source/JavaScriptCore/runtime/ArityCheckMode.h39
-rw-r--r--Source/JavaScriptCore/runtime/ArrayBuffer.cpp10
-rw-r--r--Source/JavaScriptCore/runtime/ArrayBuffer.h2
-rw-r--r--Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp11
-rw-r--r--Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h14
-rw-r--r--Source/JavaScriptCore/runtime/ArrayBufferView.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/ArrayBufferView.h22
-rw-r--r--Source/JavaScriptCore/runtime/ArrayConstructor.cpp28
-rw-r--r--Source/JavaScriptCore/runtime/ArrayConstructor.h11
-rw-r--r--Source/JavaScriptCore/runtime/ArrayConventions.h9
-rw-r--r--Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp33
-rw-r--r--Source/JavaScriptCore/runtime/ArrayIteratorPrototype.h3
-rw-r--r--Source/JavaScriptCore/runtime/ArrayPrototype.cpp1437
-rw-r--r--Source/JavaScriptCore/runtime/ArrayPrototype.h24
-rw-r--r--Source/JavaScriptCore/runtime/ArrayStorage.h9
-rw-r--r--Source/JavaScriptCore/runtime/BasicBlockLocation.cpp100
-rw-r--r--Source/JavaScriptCore/runtime/BasicBlockLocation.h74
-rw-r--r--Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h6
-rw-r--r--Source/JavaScriptCore/runtime/BooleanConstructor.cpp20
-rw-r--r--Source/JavaScriptCore/runtime/BooleanConstructor.h6
-rw-r--r--Source/JavaScriptCore/runtime/BooleanObject.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/BooleanPrototype.cpp10
-rw-r--r--Source/JavaScriptCore/runtime/BooleanPrototype.h2
-rw-r--r--Source/JavaScriptCore/runtime/BundlePath.h39
-rw-r--r--Source/JavaScriptCore/runtime/Butterfly.h5
-rw-r--r--Source/JavaScriptCore/runtime/ButterflyInlines.h38
-rw-r--r--Source/JavaScriptCore/runtime/CallData.cpp27
-rw-r--r--Source/JavaScriptCore/runtime/CallData.h14
-rw-r--r--Source/JavaScriptCore/runtime/ClassInfo.h45
-rw-r--r--Source/JavaScriptCore/runtime/ClonedArguments.cpp248
-rw-r--r--Source/JavaScriptCore/runtime/ClonedArguments.h79
-rw-r--r--Source/JavaScriptCore/runtime/CodeCache.cpp134
-rw-r--r--Source/JavaScriptCore/runtime/CodeCache.h113
-rw-r--r--Source/JavaScriptCore/runtime/CommonIdentifiers.cpp54
-rw-r--r--Source/JavaScriptCore/runtime/CommonIdentifiers.h203
-rw-r--r--Source/JavaScriptCore/runtime/CommonSlowPaths.cpp468
-rw-r--r--Source/JavaScriptCore/runtime/CommonSlowPaths.h194
-rw-r--r--Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.cpp1
-rw-r--r--Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.h2
-rw-r--r--Source/JavaScriptCore/runtime/Completion.cpp155
-rw-r--r--Source/JavaScriptCore/runtime/Completion.h49
-rw-r--r--Source/JavaScriptCore/runtime/ConcurrentJITLock.h6
-rw-r--r--Source/JavaScriptCore/runtime/ConsoleClient.cpp254
-rw-r--r--Source/JavaScriptCore/runtime/ConsoleClient.h73
-rw-r--r--Source/JavaScriptCore/runtime/ConsolePrototype.cpp400
-rw-r--r--Source/JavaScriptCore/runtime/ConsolePrototype.h (renamed from Source/JavaScriptCore/runtime/SetIteratorConstructor.h)30
-rw-r--r--Source/JavaScriptCore/runtime/ConsoleTypes.h75
-rw-r--r--Source/JavaScriptCore/runtime/ConstantMode.cpp46
-rw-r--r--Source/JavaScriptCore/runtime/ConstantMode.h15
-rw-r--r--Source/JavaScriptCore/runtime/ConstructAbility.h38
-rw-r--r--Source/JavaScriptCore/runtime/ConstructData.cpp24
-rw-r--r--Source/JavaScriptCore/runtime/ConstructData.h62
-rw-r--r--Source/JavaScriptCore/runtime/ControlFlowProfiler.cpp137
-rw-r--r--Source/JavaScriptCore/runtime/ControlFlowProfiler.h115
-rw-r--r--Source/JavaScriptCore/runtime/CustomGetterSetter.cpp50
-rw-r--r--Source/JavaScriptCore/runtime/CustomGetterSetter.h77
-rw-r--r--Source/JavaScriptCore/runtime/DataView.cpp6
-rw-r--r--Source/JavaScriptCore/runtime/DataView.h4
-rw-r--r--Source/JavaScriptCore/runtime/DateConstructor.cpp171
-rw-r--r--Source/JavaScriptCore/runtime/DateConstructor.h55
-rw-r--r--Source/JavaScriptCore/runtime/DateConversion.h2
-rw-r--r--Source/JavaScriptCore/runtime/DateInstance.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/DateInstance.h120
-rw-r--r--Source/JavaScriptCore/runtime/DateInstanceCache.h95
-rw-r--r--Source/JavaScriptCore/runtime/DatePrototype.cpp218
-rw-r--r--Source/JavaScriptCore/runtime/DatePrototype.h58
-rw-r--r--Source/JavaScriptCore/runtime/DirectArguments.cpp185
-rw-r--r--Source/JavaScriptCore/runtime/DirectArguments.h158
-rw-r--r--Source/JavaScriptCore/runtime/DirectArgumentsOffset.cpp (renamed from Source/JavaScriptCore/runtime/JSArgumentsIterator.cpp)21
-rw-r--r--Source/JavaScriptCore/runtime/DirectArgumentsOffset.h53
-rw-r--r--Source/JavaScriptCore/runtime/DumpContext.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/DumpContext.h4
-rw-r--r--Source/JavaScriptCore/runtime/EnumerationMode.h80
-rw-r--r--Source/JavaScriptCore/runtime/Error.cpp218
-rw-r--r--Source/JavaScriptCore/runtime/Error.h204
-rw-r--r--Source/JavaScriptCore/runtime/ErrorConstructor.cpp18
-rw-r--r--Source/JavaScriptCore/runtime/ErrorConstructor.h45
-rw-r--r--Source/JavaScriptCore/runtime/ErrorHandlingScope.cpp55
-rw-r--r--Source/JavaScriptCore/runtime/ErrorHandlingScope.h45
-rw-r--r--Source/JavaScriptCore/runtime/ErrorInstance.cpp119
-rw-r--r--Source/JavaScriptCore/runtime/ErrorInstance.h67
-rw-r--r--Source/JavaScriptCore/runtime/ErrorPrototype.cpp12
-rw-r--r--Source/JavaScriptCore/runtime/ErrorPrototype.h57
-rw-r--r--Source/JavaScriptCore/runtime/Exception.cpp83
-rw-r--r--Source/JavaScriptCore/runtime/Exception.h (renamed from Source/JavaScriptCore/runtime/JSArgumentsIterator.h)75
-rw-r--r--Source/JavaScriptCore/runtime/ExceptionFuzz.cpp57
-rw-r--r--Source/JavaScriptCore/runtime/ExceptionFuzz.h49
-rw-r--r--Source/JavaScriptCore/runtime/ExceptionHelpers.cpp249
-rw-r--r--Source/JavaScriptCore/runtime/ExceptionHelpers.h44
-rw-r--r--Source/JavaScriptCore/runtime/Executable.cpp638
-rw-r--r--Source/JavaScriptCore/runtime/Executable.h485
-rw-r--r--Source/JavaScriptCore/runtime/FunctionConstructor.cpp53
-rw-r--r--Source/JavaScriptCore/runtime/FunctionConstructor.h56
-rw-r--r--Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp7
-rw-r--r--Source/JavaScriptCore/runtime/FunctionHasExecutedCache.cpp100
-rw-r--r--Source/JavaScriptCore/runtime/FunctionHasExecutedCache.h65
-rw-r--r--Source/JavaScriptCore/runtime/FunctionPrototype.cpp139
-rw-r--r--Source/JavaScriptCore/runtime/FunctionPrototype.h54
-rw-r--r--Source/JavaScriptCore/runtime/FunctionRareData.cpp93
-rw-r--r--Source/JavaScriptCore/runtime/FunctionRareData.h121
-rw-r--r--Source/JavaScriptCore/runtime/GCActivityCallback.cpp191
-rw-r--r--Source/JavaScriptCore/runtime/GCActivityCallback.h112
-rw-r--r--Source/JavaScriptCore/runtime/GeneratorFrame.cpp97
-rw-r--r--Source/JavaScriptCore/runtime/GeneratorFrame.h90
-rw-r--r--Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.cpp77
-rw-r--r--Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.h66
-rw-r--r--Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.cpp56
-rw-r--r--Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.h60
-rw-r--r--Source/JavaScriptCore/runtime/GeneratorPrototype.cpp62
-rw-r--r--Source/JavaScriptCore/runtime/GeneratorPrototype.h64
-rw-r--r--Source/JavaScriptCore/runtime/GenericArguments.h62
-rw-r--r--Source/JavaScriptCore/runtime/GenericArgumentsInlines.h233
-rw-r--r--Source/JavaScriptCore/runtime/GenericOffset.h113
-rw-r--r--Source/JavaScriptCore/runtime/GenericTypedArrayView.h12
-rw-r--r--Source/JavaScriptCore/runtime/GenericTypedArrayViewInlines.h28
-rw-r--r--Source/JavaScriptCore/runtime/GetPutInfo.h223
-rw-r--r--Source/JavaScriptCore/runtime/GetterSetter.cpp49
-rw-r--r--Source/JavaScriptCore/runtime/GetterSetter.h162
-rw-r--r--Source/JavaScriptCore/runtime/Identifier.cpp126
-rw-r--r--Source/JavaScriptCore/runtime/Identifier.h490
-rw-r--r--Source/JavaScriptCore/runtime/IdentifierInlines.h154
-rw-r--r--Source/JavaScriptCore/runtime/IndexingHeader.h12
-rw-r--r--Source/JavaScriptCore/runtime/IndexingHeaderInlines.h2
-rw-r--r--Source/JavaScriptCore/runtime/IndexingType.h46
-rw-r--r--Source/JavaScriptCore/runtime/InferredType.cpp600
-rw-r--r--Source/JavaScriptCore/runtime/InferredType.h293
-rw-r--r--Source/JavaScriptCore/runtime/InferredTypeTable.cpp166
-rw-r--r--Source/JavaScriptCore/runtime/InferredTypeTable.h114
-rw-r--r--Source/JavaScriptCore/runtime/InferredValue.cpp132
-rw-r--r--Source/JavaScriptCore/runtime/InferredValue.h138
-rw-r--r--Source/JavaScriptCore/runtime/InitializeThreading.cpp11
-rw-r--r--Source/JavaScriptCore/runtime/InitializeThreading.h8
-rw-r--r--Source/JavaScriptCore/runtime/InspectorInstrumentationObject.cpp99
-rw-r--r--Source/JavaScriptCore/runtime/InspectorInstrumentationObject.h67
-rw-r--r--Source/JavaScriptCore/runtime/IntegralTypedArrayBase.h4
-rw-r--r--Source/JavaScriptCore/runtime/IntendedStructureChain.cpp141
-rw-r--r--Source/JavaScriptCore/runtime/IntendedStructureChain.h70
-rw-r--r--Source/JavaScriptCore/runtime/InternalFunction.cpp41
-rw-r--r--Source/JavaScriptCore/runtime/InternalFunction.h51
-rw-r--r--Source/JavaScriptCore/runtime/IntlCollator.cpp450
-rw-r--r--Source/JavaScriptCore/runtime/IntlCollator.h86
-rw-r--r--Source/JavaScriptCore/runtime/IntlCollatorConstructor.cpp178
-rw-r--r--Source/JavaScriptCore/runtime/IntlCollatorConstructor.h67
-rw-r--r--Source/JavaScriptCore/runtime/IntlCollatorPrototype.cpp152
-rw-r--r--Source/JavaScriptCore/runtime/IntlCollatorPrototype.h58
-rw-r--r--Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp917
-rw-r--r--Source/JavaScriptCore/runtime/IntlDateTimeFormat.h108
-rw-r--r--Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp179
-rw-r--r--Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.h67
-rw-r--r--Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp157
-rw-r--r--Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.h58
-rw-r--r--Source/JavaScriptCore/runtime/IntlNumberFormat.cpp454
-rw-r--r--Source/JavaScriptCore/runtime/IntlNumberFormat.h87
-rw-r--r--Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.cpp179
-rw-r--r--Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.h67
-rw-r--r--Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp127
-rw-r--r--Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.h58
-rw-r--r--Source/JavaScriptCore/runtime/IntlObject.cpp998
-rw-r--r--Source/JavaScriptCore/runtime/IntlObject.h76
-rw-r--r--Source/JavaScriptCore/runtime/Intrinsic.h24
-rw-r--r--Source/JavaScriptCore/runtime/IterationStatus.h38
-rw-r--r--Source/JavaScriptCore/runtime/IteratorOperations.cpp156
-rw-r--r--Source/JavaScriptCore/runtime/IteratorOperations.h46
-rw-r--r--Source/JavaScriptCore/runtime/IteratorPrototype.cpp (renamed from Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.cpp)23
-rw-r--r--Source/JavaScriptCore/runtime/IteratorPrototype.h (renamed from Source/JavaScriptCore/runtime/MapIteratorConstructor.h)27
-rw-r--r--Source/JavaScriptCore/runtime/JSAPIValueWrapper.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSAPIValueWrapper.h71
-rw-r--r--Source/JavaScriptCore/runtime/JSActivation.cpp234
-rw-r--r--Source/JavaScriptCore/runtime/JSActivation.h208
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.cpp1017
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.h97
-rw-r--r--Source/JavaScriptCore/runtime/JSArrayBuffer.cpp6
-rw-r--r--Source/JavaScriptCore/runtime/JSArrayBuffer.h3
-rw-r--r--Source/JavaScriptCore/runtime/JSArrayBufferConstructor.cpp33
-rw-r--r--Source/JavaScriptCore/runtime/JSArrayBufferConstructor.h5
-rw-r--r--Source/JavaScriptCore/runtime/JSArrayBufferPrototype.cpp13
-rw-r--r--Source/JavaScriptCore/runtime/JSArrayBufferView.cpp64
-rw-r--r--Source/JavaScriptCore/runtime/JSArrayBufferView.h24
-rw-r--r--Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h8
-rw-r--r--Source/JavaScriptCore/runtime/JSArrayIterator.cpp139
-rw-r--r--Source/JavaScriptCore/runtime/JSArrayIterator.h29
-rw-r--r--Source/JavaScriptCore/runtime/JSBoundFunction.cpp33
-rw-r--r--Source/JavaScriptCore/runtime/JSBoundFunction.h9
-rw-r--r--Source/JavaScriptCore/runtime/JSBoundSlotBaseFunction.cpp94
-rw-r--r--Source/JavaScriptCore/runtime/JSBoundSlotBaseFunction.h75
-rw-r--r--Source/JavaScriptCore/runtime/JSCInlines.h56
-rw-r--r--Source/JavaScriptCore/runtime/JSCJSValue.cpp142
-rw-r--r--Source/JavaScriptCore/runtime/JSCJSValue.h134
-rw-r--r--Source/JavaScriptCore/runtime/JSCJSValueInlines.h189
-rw-r--r--Source/JavaScriptCore/runtime/JSCallee.cpp69
-rw-r--r--Source/JavaScriptCore/runtime/JSCallee.h108
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.cpp61
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.h107
-rw-r--r--Source/JavaScriptCore/runtime/JSCellInlines.h161
-rw-r--r--Source/JavaScriptCore/runtime/JSConsole.cpp (renamed from Source/JavaScriptCore/runtime/ArrayIteratorConstructor.cpp)16
-rw-r--r--Source/JavaScriptCore/runtime/JSConsole.h (renamed from Source/JavaScriptCore/runtime/ArrayIteratorConstructor.h)38
-rw-r--r--Source/JavaScriptCore/runtime/JSDataView.cpp82
-rw-r--r--Source/JavaScriptCore/runtime/JSDataView.h8
-rw-r--r--Source/JavaScriptCore/runtime/JSDataViewPrototype.cpp150
-rw-r--r--Source/JavaScriptCore/runtime/JSDataViewPrototype.h5
-rw-r--r--Source/JavaScriptCore/runtime/JSDateMath.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/JSDateMath.h10
-rw-r--r--Source/JavaScriptCore/runtime/JSDestructibleObject.h11
-rw-r--r--Source/JavaScriptCore/runtime/JSEnvironmentRecord.cpp (renamed from Source/JavaScriptCore/runtime/JSVariableObject.cpp)18
-rw-r--r--Source/JavaScriptCore/runtime/JSEnvironmentRecord.h118
-rw-r--r--Source/JavaScriptCore/runtime/JSExportMacros.h7
-rw-r--r--Source/JavaScriptCore/runtime/JSFunction.cpp232
-rw-r--r--Source/JavaScriptCore/runtime/JSFunction.h312
-rw-r--r--Source/JavaScriptCore/runtime/JSFunctionInlines.h61
-rw-r--r--Source/JavaScriptCore/runtime/JSGeneratorFunction.cpp67
-rw-r--r--Source/JavaScriptCore/runtime/JSGeneratorFunction.h82
-rw-r--r--Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h121
-rw-r--r--Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.h6
-rw-r--r--Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructorInlines.h212
-rw-r--r--Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h115
-rw-r--r--Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeFunctions.h432
-rw-r--r--Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeInlines.h103
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.cpp50
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.h71
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.cpp787
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.h362
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.cpp88
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.h74
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp247
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h12
-rw-r--r--Source/JavaScriptCore/runtime/JSInternalPromise.cpp69
-rw-r--r--Source/JavaScriptCore/runtime/JSInternalPromise.h60
-rw-r--r--Source/JavaScriptCore/runtime/JSInternalPromiseConstructor.cpp93
-rw-r--r--Source/JavaScriptCore/runtime/JSInternalPromiseConstructor.h55
-rw-r--r--Source/JavaScriptCore/runtime/JSInternalPromiseDeferred.cpp81
-rw-r--r--Source/JavaScriptCore/runtime/JSInternalPromiseDeferred.h (renamed from Source/JavaScriptCore/runtime/JSPromiseReaction.h)43
-rw-r--r--Source/JavaScriptCore/runtime/JSInternalPromisePrototype.cpp61
-rw-r--r--Source/JavaScriptCore/runtime/JSInternalPromisePrototype.h49
-rw-r--r--Source/JavaScriptCore/runtime/JSJob.cpp76
-rw-r--r--Source/JavaScriptCore/runtime/JSJob.h (renamed from Source/JavaScriptCore/runtime/JSPromiseFunctions.h)24
-rw-r--r--Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp115
-rw-r--r--Source/JavaScriptCore/runtime/JSLexicalEnvironment.h94
-rw-r--r--Source/JavaScriptCore/runtime/JSLock.cpp328
-rw-r--r--Source/JavaScriptCore/runtime/JSLock.h196
-rw-r--r--Source/JavaScriptCore/runtime/JSMap.cpp63
-rw-r--r--Source/JavaScriptCore/runtime/JSMap.h75
-rw-r--r--Source/JavaScriptCore/runtime/JSMapIterator.cpp18
-rw-r--r--Source/JavaScriptCore/runtime/JSMapIterator.h46
-rw-r--r--Source/JavaScriptCore/runtime/JSModuleEnvironment.cpp133
-rw-r--r--Source/JavaScriptCore/runtime/JSModuleEnvironment.h103
-rw-r--r--Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp197
-rw-r--r--Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h80
-rw-r--r--Source/JavaScriptCore/runtime/JSModuleRecord.cpp903
-rw-r--r--Source/JavaScriptCore/runtime/JSModuleRecord.h221
-rw-r--r--Source/JavaScriptCore/runtime/JSNameScope.cpp83
-rw-r--r--Source/JavaScriptCore/runtime/JSNameScope.h90
-rw-r--r--Source/JavaScriptCore/runtime/JSNativeStdFunction.cpp76
-rw-r--r--Source/JavaScriptCore/runtime/JSNativeStdFunction.h69
-rw-r--r--Source/JavaScriptCore/runtime/JSNotAnObject.cpp6
-rw-r--r--Source/JavaScriptCore/runtime/JSNotAnObject.h74
-rw-r--r--Source/JavaScriptCore/runtime/JSONObject.cpp166
-rw-r--r--Source/JavaScriptCore/runtime/JSONObject.h50
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp1362
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.h860
-rw-r--r--Source/JavaScriptCore/runtime/JSObjectInlines.h69
-rw-r--r--Source/JavaScriptCore/runtime/JSPromise.cpp130
-rw-r--r--Source/JavaScriptCore/runtime/JSPromise.h63
-rw-r--r--Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp501
-rw-r--r--Source/JavaScriptCore/runtime/JSPromiseConstructor.h22
-rw-r--r--Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp217
-rw-r--r--Source/JavaScriptCore/runtime/JSPromiseDeferred.h31
-rw-r--r--Source/JavaScriptCore/runtime/JSPromiseFunctions.cpp274
-rw-r--r--Source/JavaScriptCore/runtime/JSPromisePrototype.cpp156
-rw-r--r--Source/JavaScriptCore/runtime/JSPromisePrototype.h14
-rw-r--r--Source/JavaScriptCore/runtime/JSPromiseReaction.cpp158
-rw-r--r--Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp94
-rw-r--r--Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h146
-rw-r--r--Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp196
-rw-r--r--Source/JavaScriptCore/runtime/JSPropertyNameIterator.h149
-rw-r--r--Source/JavaScriptCore/runtime/JSProxy.cpp45
-rw-r--r--Source/JavaScriptCore/runtime/JSProxy.h11
-rw-r--r--Source/JavaScriptCore/runtime/JSScope.cpp217
-rw-r--r--Source/JavaScriptCore/runtime/JSScope.h148
-rw-r--r--Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp36
-rw-r--r--Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h37
-rw-r--r--Source/JavaScriptCore/runtime/JSSet.cpp54
-rw-r--r--Source/JavaScriptCore/runtime/JSSet.h73
-rw-r--r--Source/JavaScriptCore/runtime/JSSetIterator.cpp18
-rw-r--r--Source/JavaScriptCore/runtime/JSSetIterator.h35
-rw-r--r--Source/JavaScriptCore/runtime/JSString.cpp339
-rw-r--r--Source/JavaScriptCore/runtime/JSString.h1044
-rw-r--r--Source/JavaScriptCore/runtime/JSStringBuilder.h139
-rw-r--r--Source/JavaScriptCore/runtime/JSStringIterator.cpp61
-rw-r--r--Source/JavaScriptCore/runtime/JSStringIterator.h66
-rw-r--r--Source/JavaScriptCore/runtime/JSStringJoiner.cpp141
-rw-r--r--Source/JavaScriptCore/runtime/JSStringJoiner.h122
-rw-r--r--Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp19
-rw-r--r--Source/JavaScriptCore/runtime/JSSymbolTableObject.h162
-rw-r--r--Source/JavaScriptCore/runtime/JSTemplateRegistryKey.cpp57
-rw-r--r--Source/JavaScriptCore/runtime/JSTemplateRegistryKey.h (renamed from Source/JavaScriptCore/runtime/NameInstance.h)44
-rw-r--r--Source/JavaScriptCore/runtime/JSType.h45
-rw-r--r--Source/JavaScriptCore/runtime/JSTypeInfo.h159
-rw-r--r--Source/JavaScriptCore/runtime/JSTypedArrayConstructors.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.cpp7
-rw-r--r--Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.h1
-rw-r--r--Source/JavaScriptCore/runtime/JSTypedArrayViewConstructor.cpp118
-rw-r--r--Source/JavaScriptCore/runtime/JSTypedArrayViewConstructor.h64
-rw-r--r--Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.cpp301
-rw-r--r--Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.h55
-rw-r--r--Source/JavaScriptCore/runtime/JSTypedArrays.cpp5
-rw-r--r--Source/JavaScriptCore/runtime/JSWeakMap.cpp6
-rw-r--r--Source/JavaScriptCore/runtime/JSWeakMap.h2
-rw-r--r--Source/JavaScriptCore/runtime/JSWeakSet.cpp (renamed from Source/JavaScriptCore/runtime/SetIteratorConstructor.cpp)25
-rw-r--r--Source/JavaScriptCore/runtime/JSWeakSet.h81
-rw-r--r--Source/JavaScriptCore/runtime/JSWithScope.cpp7
-rw-r--r--Source/JavaScriptCore/runtime/JSWithScope.h20
-rw-r--r--Source/JavaScriptCore/runtime/JSWrapperObject.cpp5
-rw-r--r--Source/JavaScriptCore/runtime/JSWrapperObject.h93
-rw-r--r--Source/JavaScriptCore/runtime/LiteralParser.cpp57
-rw-r--r--Source/JavaScriptCore/runtime/LiteralParser.h4
-rw-r--r--Source/JavaScriptCore/runtime/Lookup.cpp77
-rw-r--r--Source/JavaScriptCore/runtime/Lookup.h510
-rw-r--r--Source/JavaScriptCore/runtime/MapConstructor.cpp99
-rw-r--r--Source/JavaScriptCore/runtime/MapConstructor.h7
-rw-r--r--Source/JavaScriptCore/runtime/MapData.cpp256
-rw-r--r--Source/JavaScriptCore/runtime/MapData.h239
-rw-r--r--Source/JavaScriptCore/runtime/MapDataInlines.h290
-rw-r--r--Source/JavaScriptCore/runtime/MapIteratorPrototype.cpp21
-rw-r--r--Source/JavaScriptCore/runtime/MapPrototype.cpp166
-rw-r--r--Source/JavaScriptCore/runtime/MapPrototype.h7
-rw-r--r--Source/JavaScriptCore/runtime/MathCommon.cpp443
-rw-r--r--Source/JavaScriptCore/runtime/MathCommon.h63
-rw-r--r--Source/JavaScriptCore/runtime/MathObject.cpp613
-rw-r--r--Source/JavaScriptCore/runtime/MathObject.h53
-rw-r--r--Source/JavaScriptCore/runtime/MemoryStatistics.cpp (renamed from Source/JavaScriptCore/runtime/NameInstance.cpp)28
-rw-r--r--Source/JavaScriptCore/runtime/MemoryStatistics.h2
-rw-r--r--Source/JavaScriptCore/runtime/ModuleLoaderObject.cpp394
-rw-r--r--Source/JavaScriptCore/runtime/ModuleLoaderObject.h88
-rw-r--r--Source/JavaScriptCore/runtime/NamePrototype.cpp81
-rw-r--r--Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp37
-rw-r--r--Source/JavaScriptCore/runtime/NativeErrorConstructor.h67
-rw-r--r--Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/NativeErrorPrototype.h39
-rw-r--r--Source/JavaScriptCore/runtime/NativeStdFunctionCell.cpp58
-rw-r--r--Source/JavaScriptCore/runtime/NativeStdFunctionCell.h61
-rw-r--r--Source/JavaScriptCore/runtime/NullGetterFunction.cpp (renamed from Source/JavaScriptCore/runtime/MapIteratorConstructor.cpp)29
-rw-r--r--Source/JavaScriptCore/runtime/NullGetterFunction.h62
-rw-r--r--Source/JavaScriptCore/runtime/NullSetterFunction.cpp91
-rw-r--r--Source/JavaScriptCore/runtime/NullSetterFunction.h62
-rw-r--r--Source/JavaScriptCore/runtime/NumberConstructor.cpp122
-rw-r--r--Source/JavaScriptCore/runtime/NumberConstructor.h64
-rw-r--r--Source/JavaScriptCore/runtime/NumberObject.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/NumberObject.h48
-rw-r--r--Source/JavaScriptCore/runtime/NumberPrototype.cpp35
-rw-r--r--Source/JavaScriptCore/runtime/NumberPrototype.h52
-rw-r--r--Source/JavaScriptCore/runtime/NumericStrings.h104
-rw-r--r--Source/JavaScriptCore/runtime/ObjectConstructor.cpp375
-rw-r--r--Source/JavaScriptCore/runtime/ObjectConstructor.h105
-rw-r--r--Source/JavaScriptCore/runtime/ObjectPrototype.cpp144
-rw-r--r--Source/JavaScriptCore/runtime/ObjectPrototype.h30
-rw-r--r--Source/JavaScriptCore/runtime/Operations.cpp26
-rw-r--r--Source/JavaScriptCore/runtime/Operations.h88
-rw-r--r--Source/JavaScriptCore/runtime/Options.cpp653
-rw-r--r--Source/JavaScriptCore/runtime/Options.h576
-rw-r--r--Source/JavaScriptCore/runtime/PrivateName.h23
-rw-r--r--Source/JavaScriptCore/runtime/PropertyDescriptor.cpp28
-rw-r--r--Source/JavaScriptCore/runtime/PropertyDescriptor.h122
-rw-r--r--Source/JavaScriptCore/runtime/PropertyMapHashTable.h151
-rw-r--r--Source/JavaScriptCore/runtime/PropertyName.h99
-rw-r--r--Source/JavaScriptCore/runtime/PropertyNameArray.cpp55
-rw-r--r--Source/JavaScriptCore/runtime/PropertyNameArray.h201
-rw-r--r--Source/JavaScriptCore/runtime/PropertyOffset.h1
-rw-r--r--Source/JavaScriptCore/runtime/PropertySlot.cpp7
-rw-r--r--Source/JavaScriptCore/runtime/PropertySlot.h143
-rw-r--r--Source/JavaScriptCore/runtime/PropertyTable.cpp43
-rw-r--r--Source/JavaScriptCore/runtime/Protect.h58
-rw-r--r--Source/JavaScriptCore/runtime/PrototypeMap.cpp38
-rw-r--r--Source/JavaScriptCore/runtime/PrototypeMap.h16
-rw-r--r--Source/JavaScriptCore/runtime/ProxyConstructor.cpp89
-rw-r--r--Source/JavaScriptCore/runtime/ProxyConstructor.h59
-rw-r--r--Source/JavaScriptCore/runtime/ProxyObject.cpp311
-rw-r--r--Source/JavaScriptCore/runtime/ProxyObject.h76
-rw-r--r--Source/JavaScriptCore/runtime/PureNaN.h98
-rw-r--r--Source/JavaScriptCore/runtime/PutPropertySlot.h165
-rw-r--r--Source/JavaScriptCore/runtime/ReflectObject.cpp217
-rw-r--r--Source/JavaScriptCore/runtime/ReflectObject.h63
-rw-r--r--Source/JavaScriptCore/runtime/RegExp.cpp86
-rw-r--r--Source/JavaScriptCore/runtime/RegExp.h125
-rw-r--r--Source/JavaScriptCore/runtime/RegExpCache.cpp7
-rw-r--r--Source/JavaScriptCore/runtime/RegExpCache.h8
-rw-r--r--Source/JavaScriptCore/runtime/RegExpCachedResult.cpp34
-rw-r--r--Source/JavaScriptCore/runtime/RegExpCachedResult.h91
-rw-r--r--Source/JavaScriptCore/runtime/RegExpConstructor.cpp157
-rw-r--r--Source/JavaScriptCore/runtime/RegExpConstructor.h147
-rw-r--r--Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp107
-rw-r--r--Source/JavaScriptCore/runtime/RegExpMatchesArray.h110
-rw-r--r--Source/JavaScriptCore/runtime/RegExpObject.cpp185
-rw-r--r--Source/JavaScriptCore/runtime/RegExpObject.h123
-rw-r--r--Source/JavaScriptCore/runtime/RegExpPrototype.cpp280
-rw-r--r--Source/JavaScriptCore/runtime/RegExpPrototype.h51
-rw-r--r--Source/JavaScriptCore/runtime/RuntimeFlags.h99
-rw-r--r--Source/JavaScriptCore/runtime/RuntimeType.cpp88
-rw-r--r--Source/JavaScriptCore/runtime/RuntimeType.h60
-rw-r--r--Source/JavaScriptCore/runtime/SamplingCounter.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/SamplingCounter.h2
-rw-r--r--Source/JavaScriptCore/runtime/SamplingProfiler.cpp786
-rw-r--r--Source/JavaScriptCore/runtime/SamplingProfiler.h176
-rw-r--r--Source/JavaScriptCore/runtime/ScopeOffset.cpp42
-rw-r--r--Source/JavaScriptCore/runtime/ScopeOffset.h51
-rw-r--r--Source/JavaScriptCore/runtime/ScopedArguments.cpp154
-rw-r--r--Source/JavaScriptCore/runtime/ScopedArguments.h157
-rw-r--r--Source/JavaScriptCore/runtime/ScopedArgumentsTable.cpp109
-rw-r--r--Source/JavaScriptCore/runtime/ScopedArgumentsTable.h96
-rw-r--r--Source/JavaScriptCore/runtime/SetConstructor.cpp86
-rw-r--r--Source/JavaScriptCore/runtime/SetConstructor.h7
-rw-r--r--Source/JavaScriptCore/runtime/SetIteratorPrototype.cpp20
-rw-r--r--Source/JavaScriptCore/runtime/SetPrototype.cpp152
-rw-r--r--Source/JavaScriptCore/runtime/SetPrototype.h7
-rw-r--r--Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/SlowPathReturnType.h86
-rw-r--r--Source/JavaScriptCore/runtime/SmallStrings.cpp27
-rw-r--r--Source/JavaScriptCore/runtime/SmallStrings.h118
-rw-r--r--Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp27
-rw-r--r--Source/JavaScriptCore/runtime/SparseArrayValueMap.h8
-rw-r--r--Source/JavaScriptCore/runtime/StackAlignment.h21
-rw-r--r--Source/JavaScriptCore/runtime/StrictEvalActivation.cpp8
-rw-r--r--Source/JavaScriptCore/runtime/StrictEvalActivation.h14
-rw-r--r--Source/JavaScriptCore/runtime/StringConstructor.cpp52
-rw-r--r--Source/JavaScriptCore/runtime/StringConstructor.h52
-rw-r--r--Source/JavaScriptCore/runtime/StringIteratorPrototype.cpp66
-rw-r--r--Source/JavaScriptCore/runtime/StringIteratorPrototype.h64
-rw-r--r--Source/JavaScriptCore/runtime/StringObject.cpp21
-rw-r--r--Source/JavaScriptCore/runtime/StringObject.h102
-rw-r--r--Source/JavaScriptCore/runtime/StringPrototype.cpp1029
-rw-r--r--Source/JavaScriptCore/runtime/StringPrototype.h49
-rw-r--r--Source/JavaScriptCore/runtime/StringRecursionChecker.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/StringRecursionChecker.h20
-rw-r--r--Source/JavaScriptCore/runtime/Structure.cpp897
-rw-r--r--Source/JavaScriptCore/runtime/Structure.h475
-rw-r--r--Source/JavaScriptCore/runtime/StructureChain.cpp9
-rw-r--r--Source/JavaScriptCore/runtime/StructureChain.h101
-rw-r--r--Source/JavaScriptCore/runtime/StructureIDBlob.h95
-rw-r--r--Source/JavaScriptCore/runtime/StructureIDTable.cpp119
-rw-r--r--Source/JavaScriptCore/runtime/StructureIDTable.h94
-rw-r--r--Source/JavaScriptCore/runtime/StructureInlines.h153
-rw-r--r--Source/JavaScriptCore/runtime/StructureRareData.cpp179
-rw-r--r--Source/JavaScriptCore/runtime/StructureRareData.h46
-rw-r--r--Source/JavaScriptCore/runtime/StructureRareDataInlines.h8
-rw-r--r--Source/JavaScriptCore/runtime/StructureTransitionTable.h41
-rw-r--r--Source/JavaScriptCore/runtime/Symbol.cpp96
-rw-r--r--Source/JavaScriptCore/runtime/Symbol.h110
-rw-r--r--Source/JavaScriptCore/runtime/SymbolConstructor.cpp128
-rw-r--r--Source/JavaScriptCore/runtime/SymbolConstructor.h (renamed from Source/JavaScriptCore/runtime/NameConstructor.h)32
-rw-r--r--Source/JavaScriptCore/runtime/SymbolObject.cpp56
-rw-r--r--Source/JavaScriptCore/runtime/SymbolObject.h67
-rw-r--r--Source/JavaScriptCore/runtime/SymbolPrototype.cpp107
-rw-r--r--Source/JavaScriptCore/runtime/SymbolPrototype.h (renamed from Source/JavaScriptCore/runtime/NamePrototype.h)30
-rw-r--r--Source/JavaScriptCore/runtime/SymbolTable.cpp207
-rw-r--r--Source/JavaScriptCore/runtime/SymbolTable.h416
-rw-r--r--Source/JavaScriptCore/runtime/TemplateRegistry.cpp (renamed from Source/JavaScriptCore/runtime/NameConstructor.cpp)60
-rw-r--r--Source/JavaScriptCore/runtime/TemplateRegistry.h48
-rw-r--r--Source/JavaScriptCore/runtime/TemplateRegistryKey.h103
-rw-r--r--Source/JavaScriptCore/runtime/TestRunnerUtils.cpp75
-rw-r--r--Source/JavaScriptCore/runtime/TestRunnerUtils.h18
-rw-r--r--Source/JavaScriptCore/runtime/Tracing.d40
-rw-r--r--Source/JavaScriptCore/runtime/Tracing.h4
-rw-r--r--Source/JavaScriptCore/runtime/TypeLocationCache.cpp61
-rw-r--r--Source/JavaScriptCore/runtime/TypeLocationCache.h68
-rw-r--r--Source/JavaScriptCore/runtime/TypeProfiler.cpp168
-rw-r--r--Source/JavaScriptCore/runtime/TypeProfiler.h144
-rw-r--r--Source/JavaScriptCore/runtime/TypeProfilerLog.cpp98
-rw-r--r--Source/JavaScriptCore/runtime/TypeProfilerLog.h (renamed from Source/JavaScriptCore/runtime/JSVariableObject.h)80
-rw-r--r--Source/JavaScriptCore/runtime/TypeSet.cpp587
-rw-r--r--Source/JavaScriptCore/runtime/TypeSet.h110
-rw-r--r--Source/JavaScriptCore/runtime/TypedArrayAdaptors.h4
-rw-r--r--Source/JavaScriptCore/runtime/TypedArrayBase.h22
-rw-r--r--Source/JavaScriptCore/runtime/TypedArrayType.cpp35
-rw-r--r--Source/JavaScriptCore/runtime/TypedArrayType.h7
-rw-r--r--Source/JavaScriptCore/runtime/TypeofType.cpp63
-rw-r--r--Source/JavaScriptCore/runtime/TypeofType.h52
-rw-r--r--Source/JavaScriptCore/runtime/VM.cpp729
-rw-r--r--Source/JavaScriptCore/runtime/VM.h931
-rw-r--r--Source/JavaScriptCore/runtime/VMEntryScope.cpp66
-rw-r--r--Source/JavaScriptCore/runtime/VMEntryScope.h16
-rw-r--r--Source/JavaScriptCore/runtime/VMInlines.h44
-rw-r--r--Source/JavaScriptCore/runtime/VarOffset.cpp76
-rw-r--r--Source/JavaScriptCore/runtime/VarOffset.h247
-rw-r--r--Source/JavaScriptCore/runtime/Watchdog.cpp223
-rw-r--r--Source/JavaScriptCore/runtime/Watchdog.h89
-rw-r--r--Source/JavaScriptCore/runtime/WatchdogMac.cpp0
-rw-r--r--Source/JavaScriptCore/runtime/WatchdogNone.cpp50
-rw-r--r--Source/JavaScriptCore/runtime/WeakGCMap.h72
-rw-r--r--Source/JavaScriptCore/runtime/WeakGCMapInlines.h59
-rw-r--r--Source/JavaScriptCore/runtime/WeakMapConstructor.cpp90
-rw-r--r--Source/JavaScriptCore/runtime/WeakMapConstructor.h3
-rw-r--r--Source/JavaScriptCore/runtime/WeakMapData.cpp14
-rw-r--r--Source/JavaScriptCore/runtime/WeakMapData.h16
-rw-r--r--Source/JavaScriptCore/runtime/WeakMapPrototype.cpp38
-rw-r--r--Source/JavaScriptCore/runtime/WeakRandom.h94
-rw-r--r--Source/JavaScriptCore/runtime/WeakSetConstructor.cpp125
-rw-r--r--Source/JavaScriptCore/runtime/WeakSetConstructor.h (renamed from Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.h)25
-rw-r--r--Source/JavaScriptCore/runtime/WeakSetPrototype.cpp99
-rw-r--r--Source/JavaScriptCore/runtime/WeakSetPrototype.h (renamed from Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.h)16
-rw-r--r--Source/JavaScriptCore/runtime/WriteBarrier.h55
-rw-r--r--Source/JavaScriptCore/runtime/WriteBarrierInlines.h67
506 files changed, 43604 insertions, 17790 deletions
diff --git a/Source/JavaScriptCore/runtime/ArgList.cpp b/Source/JavaScriptCore/runtime/ArgList.cpp
index e13104df5..3023151bf 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, 2004, 2005, 2006, 2007, 2009, 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 Library General Public
@@ -24,7 +24,7 @@
#include "HeapRootVisitor.h"
#include "JSCJSValue.h"
#include "JSObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
using std::min;
@@ -53,13 +53,14 @@ void MarkedArgumentBuffer::markLists(HeapRootVisitor& heapRootVisitor, ListSet&
void MarkedArgumentBuffer::slowAppend(JSValue v)
{
- int newCapacity = m_capacity * 4;
- EncodedJSValue* newBuffer = new EncodedJSValue[newCapacity];
+ int newCapacity = (Checked<int>(m_capacity) * 2).unsafeGet();
+ size_t size = (Checked<size_t>(newCapacity) * sizeof(EncodedJSValue)).unsafeGet();
+ EncodedJSValue* newBuffer = static_cast<EncodedJSValue*>(fastMalloc(size));
for (int i = 0; i < m_capacity; ++i)
newBuffer[i] = m_buffer[i];
if (EncodedJSValue* base = mallocBase())
- delete [] base;
+ fastFree(base);
m_buffer = newBuffer;
m_capacity = newCapacity;
diff --git a/Source/JavaScriptCore/runtime/ArgList.h b/Source/JavaScriptCore/runtime/ArgList.h
index 9aafc9070..8ae622d07 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, 2007, 2008, 2009, 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 Library General Public
@@ -57,7 +57,7 @@ public:
m_markSet->remove(this);
if (EncodedJSValue* base = mallocBase())
- delete [] base;
+ fastFree(base);
}
size_t size() const { return m_size; }
@@ -119,23 +119,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 {
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<Arguments*>(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<Arguments*>(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<Arguments*>(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<Arguments*>(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<Arguments*>(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<Arguments*>(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<Arguments*>(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<Arguments*>(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<Arguments*>(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<Arguments*>(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<WriteBarrier<Unknown>*>(callFrame) == m_registers);
-
- m_registerArray = std::make_unique<WriteBarrier<Unknown>[]>(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<WriteBarrier<Unknown>[]>(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<Arguments*>(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 <wtf/StdLibExtras.h>
-
-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<Arguments>(vm.heap)) Arguments(callFrame);
- arguments->finishCreation(callFrame);
- return arguments;
- }
-
- static Arguments* create(VM& vm, CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
- {
- Arguments* arguments = new (NotNull, allocateCell<Arguments>(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<Unknown>& argument(size_t);
- void allocateSlowArguments();
-
- void init(CallFrame*);
-
- WriteBarrier<JSActivation> 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<Unknown>* m_registers;
- std::unique_ptr<WriteBarrier<Unknown>[]> m_registerArray;
-
- struct SlowArgumentData {
- std::unique_ptr<SlowArgument[]> 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<SlowArgumentData> m_slowArgumentData;
-
- WriteBarrier<JSFunction> m_callee;
-};
-
-Arguments* asArguments(JSValue);
-
-inline Arguments* asArguments(JSValue value)
-{
- ASSERT(asObject(value)->inherits(Arguments::info()));
- return static_cast<Arguments*>(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<SlowArgumentData>();
- m_slowArgumentData->bytecodeToMachineCaptureOffset = 0;
- m_slowArgumentData->slowArguments = std::make_unique<SlowArgument[]>(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<Unknown>& 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<JSFunction*>(callFrame->callee());
- m_numArguments = callFrame->argumentCount();
- m_registers = reinterpret_cast<WriteBarrierBase<Unknown>*>(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<unsigned>(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<WriteBarrierBase<Unknown>*>(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<FunctionExecutable*>(inlineCallFrame->executable.get())->isStrictMode();
- ASSERT(!jsCast<FunctionExecutable*>(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/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<JSArgumentsIterator*>(callFrame->thisValue())->next(callFrame, result))
- return JSValue::encode(result);
- return JSValue::encode(callFrame->vm().iterationTerminator.get());
-}
-
-}
diff --git a/Source/JavaScriptCore/runtime/ArgumentsMode.h b/Source/JavaScriptCore/runtime/ArgumentsMode.h
new file mode 100644
index 000000000..67cd3348d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ArgumentsMode.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef ArgumentsMode_h
+#define ArgumentsMode_h
+
+namespace JSC {
+
+enum class ArgumentsMode {
+ Cloned,
+ FakeValues
+};
+
+} // namespace JSC
+
+#endif // ArgumentsMode_h
+
diff --git a/Source/JavaScriptCore/runtime/ArityCheckMode.h b/Source/JavaScriptCore/runtime/ArityCheckMode.h
new file mode 100644
index 000000000..f2090c057
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ArityCheckMode.h
@@ -0,0 +1,39 @@
+/*
+ * 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 ArityCheckMode_h
+#define ArityCheckMode_h
+
+namespace JSC {
+
+enum ArityCheckMode {
+ ArityCheckNotRequired,
+ MustCheckArity
+};
+
+} // namespace JSC
+
+#endif // ArityCheckMode_h
+
diff --git a/Source/JavaScriptCore/runtime/ArrayBuffer.cpp b/Source/JavaScriptCore/runtime/ArrayBuffer.cpp
index 2c49b6976..5a7ad268e 100644
--- a/Source/JavaScriptCore/runtime/ArrayBuffer.cpp
+++ b/Source/JavaScriptCore/runtime/ArrayBuffer.cpp
@@ -28,7 +28,7 @@
#include "ArrayBufferNeuteringWatchpoint.h"
#include "JSArrayBufferView.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include <wtf/RefPtr.h>
namespace JSC {
@@ -44,20 +44,20 @@ bool ArrayBuffer::transfer(ArrayBufferContents& result)
bool isNeuterable = !m_pinCount;
- if (isNeuterable)
- m_contents.transfer(result);
- else {
+ if (!isNeuterable) {
m_contents.copyTo(result);
if (!result.m_data)
return false;
+ return true;
}
+ m_contents.transfer(result);
for (size_t i = numberOfIncomingReferences(); i--;) {
JSCell* cell = incomingReferenceAt(i);
if (JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(cell))
view->neuter();
else if (ArrayBufferNeuteringWatchpoint* watchpoint = jsDynamicCast<ArrayBufferNeuteringWatchpoint*>(cell))
- watchpoint->set()->fireAll();
+ watchpoint->fireAll();
}
return true;
}
diff --git a/Source/JavaScriptCore/runtime/ArrayBuffer.h b/Source/JavaScriptCore/runtime/ArrayBuffer.h
index f0d7d2719..a7b6f33d7 100644
--- a/Source/JavaScriptCore/runtime/ArrayBuffer.h
+++ b/Source/JavaScriptCore/runtime/ArrayBuffer.h
@@ -96,7 +96,7 @@ public:
static inline PassRefPtr<ArrayBuffer> create(ArrayBufferContents&);
static inline PassRefPtr<ArrayBuffer> createAdopted(const void* data, unsigned byteLength);
- // Only for use by Uint8ClampedArray::createUninitialized.
+ // Only for use by Uint8ClampedArray::createUninitialized and SharedBuffer::createArrayBuffer.
static inline PassRefPtr<ArrayBuffer> createUninitialized(unsigned numElements, unsigned elementByteSize);
inline void* data();
diff --git a/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp
index b11a0ad3a..a15b50440 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("Array buffer was neutered");
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h
index 96dbd69c7..ab26f0332 100644
--- a/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h
+++ b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h
@@ -31,27 +31,27 @@
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<WatchpointSet> m_set;
};
diff --git a/Source/JavaScriptCore/runtime/ArrayBufferView.cpp b/Source/JavaScriptCore/runtime/ArrayBufferView.cpp
index 2332e2663..f0fe06be4 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
diff --git a/Source/JavaScriptCore/runtime/ArrayBufferView.h b/Source/JavaScriptCore/runtime/ArrayBufferView.h
index 2b8f70d8b..3fc10b0dd 100644
--- a/Source/JavaScriptCore/runtime/ArrayBufferView.h
+++ b/Source/JavaScriptCore/runtime/ArrayBufferView.h
@@ -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
@@ -77,22 +77,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 <typename T>
- static bool verifySubRange(
- PassRefPtr<ArrayBuffer> buffer,
- unsigned byteOffset,
- unsigned numElements)
+ static bool verifySubRangeLength(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned numElements, size_t size)
{
unsigned byteLength = buffer->byteLength();
- if (sizeof(T) > 1 && byteOffset % sizeof(T))
- return false;
if (byteOffset > byteLength)
return false;
- unsigned remainingElements = (byteLength - byteOffset) / sizeof(T);
+ unsigned remainingElements = (byteLength - byteOffset) / size;
if (numElements > remainingElements)
return false;
return true;
diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp
index 72fc5619f..cf02ea324 100644
--- a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp
@@ -29,10 +29,11 @@
#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "ExceptionHelpers.h"
+#include "GetterSetter.h"
#include "JSArray.h"
#include "JSFunction.h"
#include "Lookup.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
@@ -46,11 +47,13 @@ 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,47 +62,48 @@ ArrayConstructor::ArrayConstructor(VM& vm, Structure* structure)
{
}
-void ArrayConstructor::finishCreation(VM& vm, ArrayPrototype* arrayPrototype)
+void ArrayConstructor::finishCreation(VM& vm, ArrayPrototype* arrayPrototype, GetterSetter* speciesSymbol)
{
Base::finishCreation(vm, arrayPrototype->classInfo()->className);
putDirectWithoutTransition(vm, vm.propertyNames->prototype, arrayPrototype, DontEnum | DontDelete | ReadOnly);
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
+ putDirectNonIndexAccessor(vm, vm.propertyNames->speciesSymbol, speciesSymbol, Accessor | ReadOnly | DontEnum);
}
bool ArrayConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
{
- return getStaticFunctionSlot<InternalFunction>(exec, ExecState::arrayConstructorTable(exec->vm()), jsCast<ArrayConstructor*>(object), propertyName, slot);
+ return getStaticFunctionSlot<InternalFunction>(exec, arrayConstructorTable, jsCast<ArrayConstructor*>(object), propertyName, slot);
}
// ------------------------------ Functions ---------------------------
-JSObject* constructArrayWithSizeQuirk(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, JSValue length)
+JSObject* constructArrayWithSizeQuirk(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, JSValue length, JSValue newTarget)
{
if (!length.isNumber())
- return constructArrayNegativeIndexed(exec, profile, globalObject, &length, 1);
+ 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 constructEmptyArray(exec, profile, globalObject, n, newTarget);
}
-static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args)
+static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args, JSValue newTarget)
{
JSGlobalObject* globalObject = asInternalFunction(exec->callee())->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)
@@ -111,7 +115,7 @@ ConstructType ArrayConstructor::getConstructData(JSCell*, ConstructData& constru
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)
diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.h b/Source/JavaScriptCore/runtime/ArrayConstructor.h
index a6ac76ea4..5256a52da 100644
--- a/Source/JavaScriptCore/runtime/ArrayConstructor.h
+++ b/Source/JavaScriptCore/runtime/ArrayConstructor.h
@@ -28,15 +28,17 @@ namespace JSC {
class ArrayAllocationProfile;
class ArrayPrototype;
class JSArray;
+class GetterSetter;
class ArrayConstructor : public InternalFunction {
public:
typedef InternalFunction Base;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
- static ArrayConstructor* create(VM& vm, Structure* structure, ArrayPrototype* arrayPrototype)
+ static ArrayConstructor* create(VM& vm, Structure* structure, ArrayPrototype* arrayPrototype, GetterSetter* speciesSymbol)
{
ArrayConstructor* constructor = new (NotNull, allocateCell<ArrayConstructor>(vm.heap)) ArrayConstructor(vm, structure);
- constructor->finishCreation(vm, arrayPrototype);
+ constructor->finishCreation(vm, arrayPrototype, speciesSymbol);
return constructor;
}
@@ -48,8 +50,7 @@ public:
}
protected:
- void finishCreation(VM&, ArrayPrototype*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
+ void finishCreation(VM&, ArrayPrototype*, GetterSetter* speciesSymbol);
private:
ArrayConstructor(VM&, Structure*);
@@ -59,7 +60,7 @@ private:
static CallType getCallData(JSCell*, CallData&);
};
-JSObject* constructArrayWithSizeQuirk(ExecState*, ArrayAllocationProfile*, JSGlobalObject*, JSValue);
+JSObject* constructArrayWithSizeQuirk(ExecState*, ArrayAllocationProfile*, JSGlobalObject*, JSValue length, JSValue prototype = JSValue());
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ArrayConventions.h b/Source/JavaScriptCore/runtime/ArrayConventions.h
index e5ef96336..9c62ea9b8 100644
--- a/Source/JavaScriptCore/runtime/ArrayConventions.h
+++ b/Source/JavaScriptCore/runtime/ArrayConventions.h
@@ -38,7 +38,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,7 +58,14 @@ 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 <rdar://problem/5971391>.
+
+// 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
diff --git a/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp
index 1ccb791b7..132469d04 100644
--- a/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp
@@ -20,36 +20,51 @@
* 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"
+namespace JSC {
+
+}
+
+#include "ArrayIteratorPrototype.lut.h"
+
+#include "IteratorOperations.h"
#include "JSArrayIterator.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) };
-static EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeIterate(ExecState*);
+const ClassInfo ArrayIteratorPrototype::s_info = { "Array Iterator", &Base::s_info, &arrayIteratorPrototypeTable, CREATE_METHOD_TABLE(ArrayIteratorPrototype) };
-void ArrayIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
+/* Source for ArrayIteratorPrototype.lut.h
+@begin arrayIteratorPrototypeTable
+ next JSBuiltin DontEnum|Function 0
+@end
+*/
+
+void ArrayIteratorPrototype::finishCreation(VM& vm, JSGlobalObject*)
{
Base::finishCreation(vm);
ASSERT(inherits(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)
+bool ArrayIteratorPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
- return JSValue::encode(callFrame->thisValue());
+ return getStaticFunctionSlot<Base>(exec, arrayIteratorPrototypeTable, jsCast<ArrayIteratorPrototype*>(object), propertyName, slot);
}
-}
+// ------------------------------ Array Functions ----------------------------
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.h b/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.h
index 10ee9a6a2..2b234f8ee 100644
--- a/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.h
+++ b/Source/JavaScriptCore/runtime/ArrayIteratorPrototype.h
@@ -33,6 +33,7 @@ namespace JSC {
class ArrayIteratorPrototype : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | Base::StructureFlags;
static ArrayIteratorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
{
@@ -53,7 +54,9 @@ private:
: Base(vm, structure)
{
}
+
void finishCreation(VM&, JSGlobalObject*);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
};
}
diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
index c8659eee2..ae1a6c28a 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, 2007-2009, 2011, 2013, 2015-2016 Apple Inc. All rights reserved.
* Copyright (C) 2003 Peter Kelly (pmk@post.com)
* Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
*
@@ -24,6 +24,9 @@
#include "config.h"
#include "ArrayPrototype.h"
+#include "AdaptiveInferredPropertyValueWatchpointBase.h"
+#include "ArrayConstructor.h"
+#include "BuiltinNames.h"
#include "ButterflyInlines.h"
#include "CachedCall.h"
#include "CodeBlock.h"
@@ -32,11 +35,13 @@
#include "Interpreter.h"
#include "JIT.h"
#include "JSArrayIterator.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 <algorithm>
#include <wtf/Assertions.h>
@@ -44,87 +49,32 @@
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 arrayProtoFuncConcat(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 arrayProtoFuncReduce(ExecState*);
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState*);
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState*);
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncKeys(ExecState*);
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncEntries(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<ArrayPrototype>(vm.heap)) ArrayPrototype(vm, structure);
prototype->finishCreation(vm, globalObject);
+ vm.heap.addFinalizer(prototype, destroy);
return prototype;
}
@@ -139,32 +89,140 @@ void ArrayPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
Base::finishCreation(vm);
ASSERT(inherits(info()));
vm.prototypeMap.addPrototype(this);
- JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, arrayProtoFuncValues, DontEnum, 0);
+
+ putDirectWithoutTransition(vm, vm.propertyNames->values, globalObject->arrayProtoValuesFunction(), DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, globalObject->arrayProtoValuesFunction(), DontEnum);
+
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toString, arrayProtoFuncToString, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toLocaleString, arrayProtoFuncToLocaleString, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("concat", arrayProtoFuncConcat, DontEnum, 1);
+ 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_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->slice, arrayProtoFuncSlice, DontEnum, 2);
+ 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_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->entries, arrayProtoFuncEntries, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->keys, arrayProtoFuncKeys, DontEnum, 0);
+ 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);
+
+ JSObject* unscopables = constructEmptyObject(globalObject->globalExec(), globalObject->nullPrototypeObjectStructure());
+ const char* unscopableNames[] = {
+ "copyWithin",
+ "entries",
+ "fill",
+ "find",
+ "findIndex",
+ "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<JSArray>(exec, ExecState::arrayPrototypeTable(exec->vm()), jsCast<ArrayPrototype*>(object), propertyName, slot);
+ ArrayPrototype* thisObject = static_cast<ArrayPrototype*>(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))
+ if (JSValue result = object->tryGetIndexQuickly(index))
+ return result;
+ PropertySlot slot(object, PropertySlot::InternalMethodType::Get);
+ if (!object->getPropertySlot(exec, index, slot))
return JSValue();
return slot.getValue(exec, index);
}
-static void putProperty(ExecState* exec, JSObject* obj, PropertyName propertyName, JSValue value)
+static ALWAYS_INLINE unsigned getLength(ExecState* exec, JSObject* obj)
+{
+ if (isJSArray(obj))
+ return jsCast<JSArray*>(obj)->length();
+ return obj->get(exec, exec->propertyNames().length).toUInt32(exec);
+}
+
+static ALWAYS_INLINE void putLength(ExecState* exec, JSObject* obj, JSValue value)
{
PutPropertySlot slot(obj);
- obj->methodTable()->put(obj, exec, propertyName, value, slot);
+ obj->methodTable()->put(obj, exec, exec->propertyNames().length, value, slot);
+}
+
+static ALWAYS_INLINE void setLength(ExecState* exec, JSObject* obj, unsigned value)
+{
+ if (isJSArray(obj))
+ jsCast<JSArray*>(obj)->setLength(exec, value);
+ putLength(exec, obj, jsNumber(value));
+}
+
+enum class SpeciesConstructResult {
+ FastPath,
+ Exception,
+ CreatedObject
+};
+
+static ALWAYS_INLINE std::pair<SpeciesConstructResult, JSObject*> speciesConstructArray(ExecState* exec, JSObject* thisObject, unsigned length)
+{
+ // ECMA 9.4.2.3: https://tc39.github.io/ecma262/#sec-arrayspeciescreate
+ JSValue constructor = jsUndefined();
+ if (LIKELY(isJSArray(thisObject))) {
+ // 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.
+ if (LIKELY(!thisObject->hasCustomProperties()
+ && thisObject->globalObject()->arrayPrototype() == thisObject->prototype()
+ && !thisObject->globalObject()->arrayPrototype()->didChangeConstructorOrSpeciesProperties()))
+ return std::make_pair(SpeciesConstructResult::FastPath, nullptr);
+
+ constructor = thisObject->get(exec, exec->propertyNames().constructor);
+ if (exec->hadException())
+ return std::make_pair(SpeciesConstructResult::Exception, nullptr);
+ if (constructor.isConstructor()) {
+ JSObject* constructorObject = jsCast<JSObject*>(constructor);
+ if (exec->lexicalGlobalObject() != constructorObject->globalObject())
+ return std::make_pair(SpeciesConstructResult::FastPath, nullptr);;
+ }
+ if (constructor.isObject()) {
+ constructor = constructor.get(exec, exec->propertyNames().speciesSymbol);
+ if (exec->hadException())
+ return std::make_pair(SpeciesConstructResult::Exception, nullptr);
+ if (constructor.isNull())
+ return std::make_pair(SpeciesConstructResult::FastPath, nullptr);;
+ }
+ }
+ 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");
+ if (exec->hadException())
+ return std::make_pair(SpeciesConstructResult::Exception, nullptr);
+ 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 +236,6 @@ static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument
return indexDouble > length ? length : static_cast<unsigned>(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,6 +250,7 @@ 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<JSArray::ShiftCountMode shiftCountMode>
void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length)
{
@@ -204,33 +262,32 @@ void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned current
if (isJSArray(thisObj)) {
JSArray* array = asArray(thisObj);
- if (array->length() == length && asArray(thisObj)->shiftCount<shiftCountMode>(exec, header, count))
+ if (array->length() == length && array->shiftCount<shiftCountMode>(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 (JSValue value = getProperty(exec, thisObj, from)) {
if (exec->hadException())
return;
- thisObj->methodTable()->putByIndex(thisObj, exec, to, value, true);
+ thisObj->putByIndexInline(exec, to, value, true);
if (exec->hadException())
return;
- } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, to)) {
+ } else if (!thisObj->methodTable(exec->vm())->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)) {
+ if (!thisObj->methodTable(exec->vm())->deletePropertyByIndex(thisObj, exec, k - 1)) {
throwTypeError(exec, ASCIILiteral("Unable to delete property."));
return;
}
}
}
+
template<JSArray::ShiftCountMode shiftCountMode>
void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length)
{
@@ -251,17 +308,15 @@ void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned curre
if (array->length() == length && array->unshiftCount<shiftCountMode>(exec, header, count))
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 (JSValue value = getProperty(exec, thisObj, from)) {
if (exec->hadException())
return;
- thisObj->methodTable()->putByIndex(thisObj, exec, to, value, true);
- } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, to)) {
+ thisObj->putByIndexInline(exec, to, value, true);
+ } else if (!thisObj->methodTable(exec->vm())->deletePropertyByIndex(thisObj, exec, to)) {
throwTypeError(exec, ASCIILiteral("Unable to delete property."));
return;
}
@@ -272,7 +327,7 @@ void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned curre
EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode);
+ 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);
@@ -284,206 +339,359 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec)
// 3. If IsCallable(func) is false, then let func be the standard built-in method Object.prototype.toString (15.2.4.2).
if (!function.isCell())
- return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable()->className(thisObject), "]"));
+ return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable(exec->vm())->className(thisObject), "]"));
CallData callData;
CallType callType = getCallData(function, callData);
if (callType == CallTypeNone)
- return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable()->className(thisObject), "]"));
+ return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable(exec->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)
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);
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);
+ JSStringJoiner joiner(*exec, ',', length);
+ 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);
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
-
- if (element.isUndefinedOrNull())
- stringJoiner.append(String());
- else
- stringJoiner.append(element.toWTFString(exec));
-
+ joiner.append(*exec, element);
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
- return JSValue::encode(stringJoiner.join(exec));
+
+ return JSValue::encode(joiner.join(*exec));
}
EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode);
+ JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
- JSObject* thisObj = thisValue.toObject(exec);
+ JSObject* thisObject = thisValue.toObject(exec);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ unsigned length = getLength(exec, thisObject);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- StringRecursionChecker checker(exec, thisObj);
+ StringRecursionChecker checker(exec, thisObject);
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);
+ JSStringJoiner stringJoiner(*exec, ',', length);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+#if ENABLE(INTL)
+ ArgList arguments(exec);
+ for (unsigned i = 0; i < length; ++i) {
+ JSValue element = thisObject->getIndex(exec, i);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- if (!element.isUndefinedOrNull()) {
- JSObject* o = element.toObject(exec);
- JSValue conversionFunction = o->get(exec, exec->propertyNames().toLocaleString);
+ if (element.isUndefinedOrNull())
+ element = jsEmptyString(exec);
+ else {
+ JSValue conversionFunction = element.get(exec, exec->propertyNames().toLocaleString);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- String str;
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 (callType != CallTypeNone) {
+ element = call(exec, conversionFunction, callType, callData, element, arguments);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ }
+ }
+ stringJoiner.append(*exec, element);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ }
+#else // !ENABLE(INTL)
+ for (unsigned i = 0; i < length; ++i) {
+ JSValue element = thisObject->getIndex(exec, i);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (element.isUndefinedOrNull())
+ continue;
+ JSValue conversionFunction = element.get(exec, exec->propertyNames().toLocaleString);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ CallData callData;
+ CallType callType = getCallData(conversionFunction, callData);
+ if (callType != CallTypeNone) {
+ element = call(exec, conversionFunction, callType, callData, element, exec->emptyList());
if (exec->hadException())
return JSValue::encode(jsUndefined());
- stringJoiner.append(str);
}
+ stringJoiner.append(*exec, element);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
}
+#endif // !ENABLE(INTL)
- return JSValue::encode(stringJoiner.join(exec));
+ 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());
-
- StringRecursionChecker checker(exec, thisObj);
- if (JSValue earlyReturnValue = checker.earlyReturnValue())
- return JSValue::encode(earlyReturnValue);
-
- String separator;
- if (!exec->argument(0).isUndefined())
- separator = exec->argument(0).toWTFString(exec);
- if (separator.isNull())
- separator = String(",", String::ConstructFromLiteral);
+ return std::isnan(value);
+}
- JSStringJoiner stringJoiner(separator, length);
+static inline bool isHole(const WriteBarrier<Unknown>& value)
+{
+ return !value;
+}
- unsigned k = 0;
- if (isJSArray(thisObj)) {
- JSArray* array = asArray(thisObj);
+template<typename T> static inline bool containsHole(T* data, unsigned length)
+{
+ for (unsigned i = 0; i < length; ++i) {
+ if (isHole(data[i]))
+ return true;
+ }
+ return false;
+}
- for (; k < length; k++) {
- if (!array->canGetIndexQuickly(k))
- break;
+static inline bool holesMustForwardToPrototype(ExecState& state, JSObject* object)
+{
+ auto& vm = state.vm();
+ return object->structure(vm)->holesMustForwardToPrototype(vm);
+}
- JSValue element = array->getIndexQuickly(k);
- if (!element.isUndefinedOrNull())
- stringJoiner.append(element.toWTFStringInline(exec));
- else
- stringJoiner.append(String());
+static inline JSValue join(ExecState& state, JSObject* thisObject, StringView separator)
+{
+ unsigned length = getLength(&state, thisObject);
+ if (state.hadException())
+ return jsUndefined();
+
+ 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);
+ if (state.hadException())
+ return jsUndefined();
+ 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();
+ }
+ }
+ return joiner.join(state);
+ }
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ auto& butterfly = *thisObject->butterfly();
+ if (length > butterfly.publicLength())
+ break;
+ JSStringJoiner joiner(state, separator, length);
+ if (state.hadException())
+ return jsUndefined();
+ 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(state.vm())->holesMustForwardToPrototype(state.vm()))
+ goto generalCase;
+ holesKnownToBeOK = true;
+ }
+ joiner.appendEmptyString();
+ }
}
+ return joiner.join(state);
+ }
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
+ auto& storage = *thisObject->butterfly()->arrayStorage();
+ if (length > storage.vectorLength())
+ break;
+ if (storage.hasHoles() && thisObject->structure(state.vm())->holesMustForwardToPrototype(state.vm()))
+ break;
+ JSStringJoiner joiner(state, separator, length);
+ if (state.hadException())
+ return jsUndefined();
+ auto data = storage.vector().data();
+ for (unsigned i = 0; i < length; ++i) {
+ if (JSValue value = data[i].get()) {
+ if (!joiner.appendWithoutSideEffects(state, value))
+ goto generalCase;
+ } else
+ joiner.appendEmptyString();
+ }
+ return joiner.join(state);
+ }
}
- for (; k < length; k++) {
- JSValue element = thisObj->get(exec, k);
- if (!element.isUndefinedOrNull())
- stringJoiner.append(element.toWTFStringInline(exec));
- else
- stringJoiner.append(String());
+generalCase:
+ JSStringJoiner joiner(state, separator, length);
+ if (state.hadException())
+ return jsUndefined();
+ for (unsigned i = 0; i < length; ++i) {
+ JSValue element = thisObject->getIndex(&state, i);
+ if (state.hadException())
+ return jsUndefined();
+ joiner.append(state, element);
+ if (state.hadException())
+ return jsUndefined();
}
+ return joiner.join(state);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
+{
+ JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
- return JSValue::encode(stringJoiner.join(exec));
+ StringRecursionChecker checker(exec, thisObject);
+ if (JSValue earlyReturnValue = checker.earlyReturnValue())
+ return JSValue::encode(earlyReturnValue);
+
+ JSValue separatorValue = exec->argument(0);
+ if (separatorValue.isUndefined()) {
+ const LChar comma = ',';
+ return JSValue::encode(join(*exec, thisObject, { &comma, 1 }));
+ }
+
+ JSString* separator = separatorValue.toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(join(*exec, thisObject, separator->view(exec).get()));
}
EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode);
- JSArray* arr = constructEmptyArray(exec, 0);
- unsigned n = 0;
+ JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
+ unsigned argCount = exec->argumentCount();
JSValue curArg = thisValue.toObject(exec);
- if (exec->hadException())
+ Checked<unsigned, RecordOverflow> finalArraySize = 0;
+
+ // We need to do species construction before geting the rest of the elements.
+ std::pair<SpeciesConstructResult, JSObject*> speciesResult = speciesConstructArray(exec, curArg.getObject(), 0);
+ if (speciesResult.first == SpeciesConstructResult::Exception)
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);
+
+ JSArray* currentArray = nullptr;
+ JSArray* previousArray = nullptr;
+ for (unsigned i = 0; ; ++i) {
+ previousArray = currentArray;
+ currentArray = jsDynamicCast<JSArray*>(curArg);
+ if (currentArray) {
+ // Can't use JSArray::length here because this might be a RuntimeArray!
+ finalArraySize += getLength(exec, currentArray);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ } else
+ ++finalArraySize;
+ if (i == argCount)
+ break;
+ curArg = exec->uncheckedArgument(i);
+ }
+
+ if (finalArraySize.hasOverflowed())
+ return JSValue::encode(throwOutOfMemoryError(exec));
+
+ if (speciesResult.first == SpeciesConstructResult::FastPath && argCount == 1 && previousArray && currentArray && finalArraySize.unsafeGet() < MIN_SPARSE_ARRAY_INDEX) {
+ IndexingType type = JSArray::fastConcatType(exec->vm(), *previousArray, *currentArray);
+ if (type != NonArray)
+ return previousArray->fastConcatWith(*exec, *currentArray);
+ }
+
+ ASSERT(speciesResult.first != SpeciesConstructResult::Exception);
+
+ JSObject* result;
+ if (speciesResult.first == SpeciesConstructResult::CreatedObject)
+ result = speciesResult.second;
+ else {
+ // We add the newTarget because the compiler gets confused between 0 being a number and a pointer.
+ result = constructEmptyArray(exec, nullptr, 0, JSValue());
+ }
+
+ curArg = thisValue.toObject(exec);
+ unsigned n = 0;
+ for (unsigned i = 0; ; ++i) {
+ if (JSArray* currentArray = jsDynamicCast<JSArray*>(curArg)) {
+ // Can't use JSArray::length here because this might be a RuntimeArray!
+ unsigned length = getLength(exec, currentArray);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
for (unsigned k = 0; k < length; ++k) {
- JSValue v = getProperty(exec, curObject, k);
+ JSValue v = getProperty(exec, currentArray, k);
if (exec->hadException())
return JSValue::encode(jsUndefined());
if (v)
- arr->putDirectIndex(exec, n, v);
+ result->putDirectIndex(exec, n, v);
n++;
}
} else {
- arr->putDirectIndex(exec, n, curArg);
+ result->putDirectIndex(exec, n, curArg);
n++;
}
if (i == argCount)
break;
curArg = exec->uncheckedArgument(i);
- ++i;
}
- arr->setLength(exec, n);
- return JSValue::encode(arr);
+ setLength(exec, result, n);
+ return JSValue::encode(result);
}
EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode);
+ JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
if (isJSArray(thisValue))
return JSValue::encode(asArray(thisValue)->pop(exec));
JSObject* thisObj = thisValue.toObject(exec);
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ unsigned length = getLength(exec, thisObj);
if (exec->hadException())
return JSValue::encode(jsUndefined());
JSValue result;
if (length == 0) {
- putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length));
+ putLength(exec, thisObj, 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)) {
+ if (!thisObj->methodTable(exec->vm())->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));
+ putLength(exec, thisObj, jsNumber(length - 1));
}
return JSValue::encode(result);
}
EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode);
+ JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
if (isJSArray(thisValue) && exec->argumentCount() == 1) {
JSArray* array = asArray(thisValue);
@@ -492,7 +700,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
}
JSObject* thisObj = thisValue.toObject(exec);
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ unsigned length = getLength(exec, thisObj);
if (exec->hadException())
return JSValue::encode(jsUndefined());
@@ -502,7 +710,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
thisObj->methodTable()->putByIndex(thisObj, exec, length + n, exec->uncheckedArgument(n), true);
else {
PutPropertySlot slot(thisObj);
- Identifier propertyName(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toWTFString(exec));
+ Identifier propertyName = Identifier::fromString(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toWTFString(exec));
thisObj->methodTable()->put(thisObj, exec, propertyName, exec->uncheckedArgument(n), slot);
}
if (exec->hadException())
@@ -510,65 +718,100 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
}
JSValue newLength(static_cast<int64_t>(length) + static_cast<int64_t>(exec->argumentCount()));
- putProperty(exec, thisObj, exec->propertyNames().length, newLength);
+ putLength(exec, 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);
+ JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
+
+ unsigned length = getLength(exec, thisObject);
if (exec->hadException())
return JSValue::encode(jsUndefined());
+ 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);
+ JSValue obj2 = getProperty(exec, thisObject, lk1);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- JSValue obj = getProperty(exec, thisObj, k);
+ JSValue obj = getProperty(exec, thisObject, k);
if (exec->hadException())
return JSValue::encode(jsUndefined());
if (obj2) {
- thisObj->methodTable()->putByIndex(thisObj, exec, k, obj2, true);
+ thisObject->putByIndexInline(exec, k, obj2, true);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k)) {
+ } else if (!thisObject->methodTable(exec->vm())->deletePropertyByIndex(thisObject, exec, k)) {
throwTypeError(exec, ASCIILiteral("Unable to delete property."));
return JSValue::encode(jsUndefined());
}
if (obj) {
- thisObj->methodTable()->putByIndex(thisObj, exec, lk1, obj, true);
+ thisObject->putByIndexInline(exec, lk1, obj, true);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- } else if (!thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, lk1)) {
+ } else if (!thisObject->methodTable(exec->vm())->deletePropertyByIndex(thisObject, exec, lk1)) {
throwTypeError(exec, ASCIILiteral("Unable to delete property."));
return JSValue::encode(jsUndefined());
}
}
- 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);
+ JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
+ unsigned length = getLength(exec, thisObj);
if (exec->hadException())
return JSValue::encode(jsUndefined());
JSValue result;
if (length == 0) {
- putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length));
+ putLength(exec, thisObj, jsNumber(length));
result = jsUndefined();
} else {
- result = thisObj->get(exec, 0);
+ result = thisObj->getIndex(exec, 0);
shift<JSArray::ShiftCountForShift>(exec, thisObj, 0, 1, 0, length);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1));
+ putLength(exec, thisObj, jsNumber(length - 1));
}
return JSValue::encode(result);
}
@@ -576,198 +819,67 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec)
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);
+ JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
+ unsigned length = getLength(exec, thisObj);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- // We return a new array
- JSArray* resObj = constructEmptyArray(exec, 0);
- JSValue result = resObj;
-
unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, length, length);
+ std::pair<SpeciesConstructResult, JSObject*> speciesResult = speciesConstructArray(exec, thisObj, end - begin);
+ // We can only get an exception if we call some user function.
+ if (UNLIKELY(speciesResult.first == SpeciesConstructResult::Exception))
+ return JSValue::encode(jsUndefined());
+
+ if (LIKELY(speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj))) {
+ 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);
+
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);
+ result->putDirectIndex(exec, n, v);
}
- resObj->setLength(exec, n);
+ setLength(exec, 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)
-{
- 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;
-}
-
-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;
- }
- }
- }
- return true;
-}
-
-EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(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);
+ // 15.4.4.12
- JSValue function = exec->argument(0);
- CallData callData;
- CallType callType = getCallData(function, callData);
+ VM& vm = exec->vm();
- 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);
+ JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
+ unsigned length = getLength(exec, thisObj);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- Vector<uint32_t, 0, UnsafeVectorOverflow> 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());
- }
-
- 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())
+ if (!exec->argumentCount()) {
+ std::pair<SpeciesConstructResult, JSObject*> speciesResult = speciesConstructArray(exec, thisObj, 0);
+ if (speciesResult.first == SpeciesConstructResult::Exception)
return JSValue::encode(jsUndefined());
- }
-
- return JSValue::encode(thisObj);
-}
-EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
-{
- // 15.4.4.12
+ JSObject* result;
+ if (speciesResult.first == SpeciesConstructResult::CreatedObject)
+ result = speciesResult.second;
+ else
+ result = constructEmptyArray(exec, nullptr);
- 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));
+ setLength(exec, result, 0);
+ return JSValue::encode(result);
+ }
unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
@@ -782,17 +894,38 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
deleteCount = static_cast<unsigned>(deleteDouble);
}
- JSArray* resObj = JSArray::tryCreateUninitialized(exec->vm(), exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), deleteCount);
- if (!resObj)
- return JSValue::encode(throwOutOfMemoryError(exec));
+ std::pair<SpeciesConstructResult, JSObject*> speciesResult = speciesConstructArray(exec, thisObj, deleteCount);
+ if (speciesResult.first == SpeciesConstructResult::Exception)
+ return JSValue::encode(jsUndefined());
- 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);
+ JSObject* result = nullptr;
+ if (speciesResult.first == SpeciesConstructResult::FastPath && isJSArray(thisObj))
+ result = asArray(thisObj)->fastSlice(*exec, begin, deleteCount);
+
+ if (!result) {
+ if (speciesResult.first == SpeciesConstructResult::CreatedObject) {
+ result = speciesResult.second;
+
+ for (unsigned k = 0; k < deleteCount; ++k) {
+ JSValue v = getProperty(exec, thisObj, k + begin);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ result->putByIndexInline(exec, k, v, true);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ }
+ } else {
+ result = JSArray::tryCreateUninitialized(vm, exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), deleteCount);
+ if (!result)
+ return JSValue::encode(throwOutOfMemoryError(exec));
+
+ for (unsigned k = 0; k < deleteCount; ++k) {
+ JSValue v = getProperty(exec, thisObj, k + begin);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ result->initializeIndex(vm, k, v);
+ }
+ }
}
unsigned additionalArgs = std::max<int>(exec->argumentCount() - 2, 0);
@@ -806,12 +939,12 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
return JSValue::encode(jsUndefined());
}
for (unsigned k = 0; k < additionalArgs; ++k) {
- thisObj->methodTable()->putByIndex(thisObj, exec, k + begin, exec->uncheckedArgument(k + 2), true);
+ thisObj->putByIndexInline(exec, k + begin, exec->uncheckedArgument(k + 2), true);
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
- putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - deleteCount + additionalArgs));
+ setLength(exec, thisObj, length - deleteCount + additionalArgs);
return JSValue::encode(result);
}
@@ -819,8 +952,8 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec)
{
// 15.4.4.13
- JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
- unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
+ unsigned length = getLength(exec, thisObj);
if (exec->hadException())
return JSValue::encode(jsUndefined());
@@ -831,459 +964,20 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec)
return JSValue::encode(jsUndefined());
}
for (unsigned k = 0; k < nrArgs; ++k) {
- thisObj->methodTable()->putByIndex(thisObj, exec, k, exec->uncheckedArgument(k), true);
+ thisObj->putByIndexInline(exec, k, exec->uncheckedArgument(k), true);
if (exec->hadException())
return JSValue::encode(jsUndefined());
}
JSValue result = jsNumber(length + nrArgs);
- putProperty(exec, thisObj, exec->propertyNames().length, result);
+ putLength(exec, thisObj, result);
return JSValue::encode(result);
}
-EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(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);
- JSArray* resultArray = constructEmptyArray(exec, 0);
-
- unsigned filterIndex = 0;
- unsigned k = 0;
- if (callType == CallTypeJS && isJSArray(thisObj)) {
- JSFunction* f = jsCast<JSFunction*>(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))
- 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);
- }
- return JSValue::encode(resultArray);
-}
-
-EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(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);
-
- JSArray* resultArray = constructEmptyArray(exec, 0, length);
- unsigned k = 0;
- if (callType == CallTypeJS && isJSArray(thisObj)) {
- JSFunction* f = jsCast<JSFunction*>(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);
-
- resultArray->putDirectIndex(exec, k, cachedCall.call());
- }
- }
- for (; k < length && !exec->hadException(); ++k) {
- PropertySlot slot(thisObj);
- if (!thisObj->getPropertySlot(exec, k, slot))
- 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);
-
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- JSValue result = call(exec, function, callType, callData, applyThis, eachArguments);
- resultArray->putDirectIndex(exec, k, result);
- }
-
- return JSValue::encode(resultArray);
-}
-
-// 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)
-{
- 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);
-
- JSValue result = jsBoolean(true);
-
- unsigned k = 0;
- if (callType == CallTypeJS && isJSArray(thisObj)) {
- JSFunction* f = jsCast<JSFunction*>(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));
- }
- }
- 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);
-
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec);
- if (!predicateResult) {
- result = jsBoolean(false);
- break;
- }
- }
-
- return JSValue::encode(result);
-}
-
-EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(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<JSFunction*>(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);
-
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- call(exec, function, callType, callData, applyThis, eachArguments);
- }
- 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);
-
- JSValue applyThis = exec->argument(1);
-
- JSValue result = jsBoolean(false);
-
- unsigned k = 0;
- if (callType == CallTypeJS && isJSArray(thisObj)) {
- JSFunction* f = jsCast<JSFunction*>(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;
-
- MarkedArgumentBuffer eachArguments;
- eachArguments.append(slot.getValue(exec, k));
- eachArguments.append(jsNumber(k));
- eachArguments.append(thisObj);
-
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec);
- if (predicateResult) {
- result = jsBoolean(true);
- break;
- }
- }
- return JSValue::encode(result);
-}
-
-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());
-
- 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 (callType == CallTypeJS && array) {
- CachedCall cachedCall(exec, jsCast<JSFunction*>(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);
- }
-
- 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);
-}
-
-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());
-
- 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<JSFunction*>(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);
- }
- 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);
+ JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
+ unsigned length = getLength(exec, thisObj);
if (exec->hadException())
return JSValue::encode(jsUndefined());
@@ -1305,8 +999,8 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec)
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);
+ JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
+ unsigned length = getLength(exec, thisObj);
if (!length)
return JSValue::encode(jsNumber(-1));
@@ -1340,20 +1034,77 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec)
EncodedJSValue JSC_HOST_CALL arrayProtoFuncValues(ExecState* exec)
{
- JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
+ JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateValue, thisObj));
}
EncodedJSValue JSC_HOST_CALL arrayProtoFuncEntries(ExecState* exec)
{
- JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
+ JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateKeyValue, thisObj));
}
EncodedJSValue JSC_HOST_CALL arrayProtoFuncKeys(ExecState* exec)
{
- JSObject* thisObj = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
+ JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateKey, thisObj));
}
+// -------------------- ArrayPrototype.constructor Watchpoint ------------------
+
+class ArrayPrototypeAdaptiveInferredPropertyWatchpoint : public AdaptiveInferredPropertyValueWatchpointBase {
+public:
+ typedef AdaptiveInferredPropertyValueWatchpointBase Base;
+ ArrayPrototypeAdaptiveInferredPropertyWatchpoint(const ObjectPropertyCondition&, ArrayPrototype*);
+
+private:
+ virtual void handleFire(const FireDetail&) override;
+
+ ArrayPrototype* m_arrayPrototype;
+};
+
+void ArrayPrototype::setConstructor(VM& vm, JSObject* constructorProperty, unsigned attributes)
+{
+ putDirectWithoutTransition(vm, vm.propertyNames->constructor, constructorProperty, attributes);
+
+ // Do the watchpoint on our constructor property
+ PropertyOffset offset = this->structure()->get(vm, vm.propertyNames->constructor);
+ ASSERT(isValidOffset(offset));
+ this->structure()->startWatchingPropertyForReplacements(vm, offset);
+
+ ObjectPropertyCondition condition = ObjectPropertyCondition::equivalence(vm, this, this, vm.propertyNames->constructor.impl(), constructorProperty);
+ ASSERT(condition.isWatchable());
+
+ m_constructorWatchpoint = std::make_unique<ArrayPrototypeAdaptiveInferredPropertyWatchpoint>(condition, this);
+ m_constructorWatchpoint->install();
+
+ // Do the watchpoint on the constructor's Symbol.species property
+ offset = constructorProperty->structure()->get(vm, vm.propertyNames->speciesSymbol);
+ ASSERT(isValidOffset(offset));
+ constructorProperty->structure()->startWatchingPropertyForReplacements(vm, offset);
+
+ ASSERT(constructorProperty->getDirect(offset).isGetterSetter());
+ condition = ObjectPropertyCondition::equivalence(vm, this, constructorProperty, vm.propertyNames->speciesSymbol.impl(), constructorProperty->getDirect(offset));
+ ASSERT(condition.isWatchable());
+
+ m_constructorSpeciesWatchpoint = std::make_unique<ArrayPrototypeAdaptiveInferredPropertyWatchpoint>(condition, this);
+ m_constructorSpeciesWatchpoint->install();
+}
+
+ArrayPrototypeAdaptiveInferredPropertyWatchpoint::ArrayPrototypeAdaptiveInferredPropertyWatchpoint(const ObjectPropertyCondition& key, ArrayPrototype* prototype)
+ : Base(key)
+ , m_arrayPrototype(prototype)
+{
+}
+
+void ArrayPrototypeAdaptiveInferredPropertyWatchpoint::handleFire(const FireDetail& detail)
+{
+ StringPrintStream out;
+ out.print("ArrayPrototype adaption of ", key(), " failed: ", detail);
+
+ StringFireDetail stringDetail(out.toCString().data());
+
+ m_arrayPrototype->m_didChangeConstructorOrSpeciesProperties = true;
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.h b/Source/JavaScriptCore/runtime/ArrayPrototype.h
index 472a1dd9c..64d2163d4 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
@@ -26,6 +26,8 @@
namespace JSC {
+class ArrayPrototypeAdaptiveInferredPropertyWatchpoint;
+
class ArrayPrototype : public JSArray {
private:
ArrayPrototype(VM&, Structure*);
@@ -35,8 +37,6 @@ public:
static ArrayPrototype* create(VM&, JSGlobalObject*, Structure*);
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
-
DECLARE_INFO;
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
@@ -44,10 +44,28 @@ public:
return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), ArrayClass);
}
+ void setConstructor(VM&, JSObject* constructorProperty, unsigned attributes);
+
+ bool didChangeConstructorOrSpeciesProperties() const { return m_didChangeConstructorOrSpeciesProperties; }
+
+ 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<ArrayPrototypeAdaptiveInferredPropertyWatchpoint> m_constructorWatchpoint;
+ std::unique_ptr<ArrayPrototypeAdaptiveInferredPropertyWatchpoint> m_constructorSpeciesWatchpoint;
+ bool m_didChangeConstructorOrSpeciesProperties = false;
};
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*);
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncValues(ExecState*);
+
} // namespace JSC
#endif // ArrayPrototype_h
diff --git a/Source/JavaScriptCore/runtime/ArrayStorage.h b/Source/JavaScriptCore/runtime/ArrayStorage.h
index a0287c921..c93dc3bfd 100644
--- a/Source/JavaScriptCore/runtime/ArrayStorage.h
+++ b/Source/JavaScriptCore/runtime/ArrayStorage.h
@@ -32,7 +32,6 @@
#include "SparseArrayValueMap.h"
#include "WriteBarrier.h"
#include <wtf/Noncopyable.h>
-#include <wtf/Platform.h>
namespace JSC {
@@ -54,9 +53,10 @@ public:
Butterfly* butterfly() { return reinterpret_cast<Butterfly*>(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(); }
void setVectorLength(unsigned length) { indexingHeader()->setVectorLength(length); }
@@ -68,6 +68,11 @@ public:
m_numValuesInVector = other.m_numValuesInVector;
}
+ bool hasHoles() const
+ {
+ return m_numValuesInVector != length();
+ }
+
bool inSparseMode()
{
return m_sparseMap && m_sparseMap->sparseMode();
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. <saambarati1@gmail.com>
+ *
+ * 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 <climits>
+#include <wtf/DataLog.h>
+
+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<int, int> gap(startOffset, endOffset);
+ if (!m_gaps.contains(gap))
+ m_gaps.append(gap);
+}
+
+Vector<std::pair<int, int>> BasicBlockLocation::getExecutedRanges() const
+{
+ Vector<Gap> result;
+ Vector<Gap> gaps = m_gaps;
+ int nextRangeStart = m_startOffset;
+ while (gaps.size()) {
+ Gap minGap(INT_MAX, 0);
+ unsigned minIdx = std::numeric_limits<unsigned>::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<Gap> 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<void*>(&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..a910f8911
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/BasicBlockLocation.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 Saam Barati. <saambarati1@gmail.com>
+ *
+ * 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 BasicBlockLocation_h
+#define BasicBlockLocation_h
+
+#include "MacroAssembler.h"
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+class CCallHelpers;
+class LLIntOffsetsExtractor;
+
+class BasicBlockLocation {
+public:
+ typedef std::pair<int, int> 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<Gap> 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<Gap> m_gaps;
+};
+
+} // namespace JSC
+
+#endif // BasicBlockLocation_h
diff --git a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
index 76def7138..951a3286c 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
@@ -38,6 +38,8 @@ public:
: m_vm(&vm)
, m_object(object)
{
+ if (!m_object->structure(vm)->isDictionary())
+ m_object->convertToDictionary(vm);
}
~BatchedTransitionOptimizer()
diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp
index 09fa26096..c39ff7281 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,17 +46,13 @@ 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));
+ JSValue boolean = jsBoolean(exec->argument(0).toBoolean(exec));
+ Structure* booleanStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), asInternalFunction(exec->callee())->globalObject()->booleanObjectStructure());
+ BooleanObject* obj = BooleanObject::create(exec->vm(), booleanStructure);
+ obj->setInternalValue(exec->vm(), boolean);
+ return JSValue::encode(obj);
}
ConstructType BooleanConstructor::getConstructData(JSCell*, ConstructData& constructData)
diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.h b/Source/JavaScriptCore/runtime/BooleanConstructor.h
index 177f69e5c..e49b9f9a2 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
@@ -26,12 +26,13 @@
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<BooleanConstructor>(vm.heap)) BooleanConstructor(vm, structure);
constructor->finishCreation(vm, booleanPrototype);
@@ -55,7 +56,6 @@ private:
};
JSObject* constructBooleanFromImmediateBoolean(ExecState*, JSGlobalObject*, JSValue);
-JSObject* constructBoolean(ExecState*, const ArgList&);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/BooleanObject.cpp b/Source/JavaScriptCore/runtime/BooleanObject.cpp
index 2c6092aa3..28cad6ae7 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)
diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp
index c73ead8be..be737ae5a 100644
--- a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp
@@ -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
@@ -65,7 +65,7 @@ void BooleanPrototype::finishCreation(VM& vm, JSGlobalObject*)
bool BooleanPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
{
- return getStaticFunctionSlot<BooleanObject>(exec, ExecState::booleanPrototypeTable(exec->vm()), jsCast<BooleanPrototype*>(object), propertyName, slot);
+ return getStaticFunctionSlot<BooleanObject>(exec, booleanPrototypeTable, jsCast<BooleanPrototype*>(object), propertyName, slot);
}
// ------------------------------ Functions ---------------------------
@@ -73,7 +73,7 @@ bool BooleanPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, Pro
EncodedJSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState* exec)
{
VM* vm = &exec->vm();
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (thisValue == jsBoolean(false))
return JSValue::encode(vm->smallStrings.falseString());
@@ -92,7 +92,7 @@ EncodedJSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState* exec)
EncodedJSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (thisValue.isBoolean())
return JSValue::encode(thisValue);
diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.h b/Source/JavaScriptCore/runtime/BooleanPrototype.h
index 35ece4bd3..6d8fc5e81 100644
--- a/Source/JavaScriptCore/runtime/BooleanPrototype.h
+++ b/Source/JavaScriptCore/runtime/BooleanPrototype.h
@@ -28,6 +28,7 @@ namespace JSC {
class BooleanPrototype : public BooleanObject {
public:
typedef BooleanObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
static BooleanPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
{
@@ -45,7 +46,6 @@ public:
protected:
void finishCreation(VM&, JSGlobalObject*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | BooleanObject::StructureFlags;
private:
BooleanPrototype(VM&, Structure*);
diff --git a/Source/JavaScriptCore/runtime/BundlePath.h b/Source/JavaScriptCore/runtime/BundlePath.h
new file mode 100644
index 000000000..c8c694832
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/BundlePath.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef BundlePath_h
+#define BundlePath_h
+
+#include <string>
+#include <wtf/text/CString.h>
+
+namespace JSC {
+
+const CString& bundlePath();
+
+} // namespace JSC
+
+#endif // BundlePath_h
+
diff --git a/Source/JavaScriptCore/runtime/Butterfly.h b/Source/JavaScriptCore/runtime/Butterfly.h
index 04554ab71..20dccd9b6 100644
--- a/Source/JavaScriptCore/runtime/Butterfly.h
+++ b/Source/JavaScriptCore/runtime/Butterfly.h
@@ -30,7 +30,6 @@
#include "PropertyOffset.h"
#include "PropertyStorage.h"
#include <wtf/Noncopyable.h>
-#include <wtf/Platform.h>
namespace JSC {
@@ -158,9 +157,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);
diff --git a/Source/JavaScriptCore/runtime/ButterflyInlines.h b/Source/JavaScriptCore/runtime/ButterflyInlines.h
index f5439bb02..3fd8dc139 100644
--- a/Source/JavaScriptCore/runtime/ButterflyInlines.h
+++ b/Source/JavaScriptCore/runtime/ButterflyInlines.h
@@ -75,39 +75,25 @@ 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));
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,
@@ -181,7 +167,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 +186,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(
diff --git a/Source/JavaScriptCore/runtime/CallData.cpp b/Source/JavaScriptCore/runtime/CallData.cpp
index cf0ba7992..42c80ddb6 100644
--- a/Source/JavaScriptCore/runtime/CallData.cpp
+++ b/Source/JavaScriptCore/runtime/CallData.cpp
@@ -28,8 +28,9 @@
#include "Executable.h"
#include "Interpreter.h"
+#include "JSCInlines.h"
#include "JSFunction.h"
-#include "Operations.h"
+#include "ScriptProfilingScope.h"
namespace JSC {
@@ -39,4 +40,28 @@ JSValue call(ExecState* exec, JSValue functionObject, CallType callType, const C
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<Exception>& returnedException)
+{
+ JSValue result = call(exec, functionObject, callType, callData, thisValue, args);
+ if (exec->hadException()) {
+ returnedException = exec->exception();
+ exec->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<Exception>& 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..45dbfbcc3 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.
*
@@ -30,10 +30,12 @@
#define CallData_h
#include "JSCJSValue.h"
+#include <wtf/NakedPtr.h>
namespace JSC {
class ArgList;
+class Exception;
class ExecState;
class FunctionExecutable;
class JSObject;
@@ -57,7 +59,17 @@ union CallData {
} 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<Exception>& returnedException);
+
+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<Exception>& returnedException);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ClassInfo.h b/Source/JavaScriptCore/runtime/ClassInfo.h
index 8ff75f4eb..84fc11a3c 100644
--- a/Source/JavaScriptCore/runtime/ClassInfo.h
+++ b/Source/JavaScriptCore/runtime/ClassInfo.h
@@ -30,7 +30,6 @@
namespace JSC {
-class HashEntry;
class JSArrayBufferView;
struct HashTable;
@@ -83,6 +82,12 @@ 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;
@@ -97,6 +102,12 @@ struct MethodTable {
typedef PassRefPtr<ArrayBufferView> (*GetTypedArrayImpl)(JSArrayBufferView*);
GetTypedArrayImpl getTypedArrayImpl;
+
+ typedef void (*DumpToStreamFunctionPtr)(const JSCell*, PrintStream&);
+ DumpToStreamFunctionPtr dumpToStream;
+
+ typedef size_t (*EstimatedSizeFunctionPtr)(JSCell*);
+ EstimatedSizeFunctionPtr estimatedSize;
};
#define CREATE_MEMBER_CHECKER(member) \
@@ -135,11 +146,16 @@ struct MethodTable {
&ClassName::getOwnPropertyNames, \
&ClassName::getOwnNonIndexPropertyNames, \
&ClassName::getPropertyNames, \
+ &ClassName::getEnumerableLength, \
+ &ClassName::getStructurePropertyNames, \
+ &ClassName::getGenericPropertyNames, \
&ClassName::className, \
&ClassName::customHasInstance, \
&ClassName::defineOwnProperty, \
&ClassName::slowDownAndWasteMemory, \
- &ClassName::getTypedArrayImpl \
+ &ClassName::getTypedArrayImpl, \
+ &ClassName::dumpToStream, \
+ &ClassName::estimatedSize \
}, \
ClassName::TypedArrayStorageType
@@ -151,25 +167,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) {
@@ -182,17 +179,15 @@ struct ClassInfo {
bool hasStaticProperties() const
{
for (const ClassInfo* ci = this; ci; ci = ci->parentClass) {
- if (ci->staticPropHashTable || ci->classPropHashTableGetterFunction)
+ if (ci->staticPropHashTable)
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;
diff --git a/Source/JavaScriptCore/runtime/ClonedArguments.cpp b/Source/JavaScriptCore/runtime/ClonedArguments.cpp
new file mode 100644
index 000000000..8241d6e0c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ClonedArguments.cpp
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ */
+
+#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)
+ : Base(vm, structure, nullptr)
+{
+}
+
+ClonedArguments* ClonedArguments::createEmpty(
+ VM& vm, Structure* structure, JSFunction* callee)
+{
+ ClonedArguments* result =
+ new (NotNull, allocateCell<ClonedArguments>(vm.heap))
+ ClonedArguments(vm, structure);
+ result->finishCreation(vm);
+ result->m_callee.set(vm, result, callee);
+ return result;
+}
+
+ClonedArguments* ClonedArguments::createEmpty(ExecState* exec, JSFunction* callee)
+{
+ // 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.
+ return createEmpty(
+ exec->vm(), exec->lexicalGlobalObject()->outOfBandArgumentsStructure(), callee);
+}
+
+ClonedArguments* ClonedArguments::createWithInlineFrame(ExecState* myFrame, ExecState* targetFrame, InlineCallFrame* inlineCallFrame, ArgumentsMode mode)
+{
+ VM& vm = myFrame->vm();
+
+ JSFunction* callee;
+
+ if (inlineCallFrame)
+ callee = jsCast<JSFunction*>(inlineCallFrame->calleeRecovery.recover(targetFrame));
+ else
+ callee = jsCast<JSFunction*>(targetFrame->callee());
+
+ ClonedArguments* result = createEmpty(myFrame, callee);
+
+ 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--;
+
+ for (unsigned i = length; i--;)
+ result->putDirectIndex(myFrame, i, inlineCallFrame->arguments[i + 1].recover(targetFrame));
+ } else {
+ length = targetFrame->argumentCount();
+
+ for (unsigned i = length; i--;)
+ result->putDirectIndex(myFrame, i, targetFrame->uncheckedArgument(i));
+ }
+ break;
+ }
+
+ case ArgumentsMode::FakeValues: {
+ length = 0;
+ break;
+ } }
+
+ result->putDirect(vm, vm.propertyNames->length, jsNumber(length), DontEnum);
+
+ return result;
+}
+
+ClonedArguments* ClonedArguments::createWithMachineFrame(ExecState* myFrame, ExecState* targetFrame, ArgumentsMode mode)
+{
+ return createWithInlineFrame(myFrame, targetFrame, nullptr, mode);
+}
+
+ClonedArguments* ClonedArguments::createByCopyingFrom(
+ ExecState* exec, Structure* structure, Register* argumentStart, unsigned length,
+ JSFunction* callee)
+{
+ VM& vm = exec->vm();
+ ClonedArguments* result = createEmpty(vm, structure, callee);
+
+ for (unsigned i = length; i--;)
+ result->putDirectIndex(exec, i, argumentStart[i].jsValue());
+
+ result->putDirect(vm, vm.propertyNames->length, jsNumber(length), DontEnum);
+ return result;
+}
+
+Structure* ClonedArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+bool ClonedArguments::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName ident, PropertySlot& slot)
+{
+ ClonedArguments* thisObject = jsCast<ClonedArguments*>(object);
+ VM& vm = exec->vm();
+
+ if (!thisObject->specialsMaterialized()) {
+ FunctionExecutable* executable = jsCast<FunctionExecutable*>(thisObject->m_callee->executable());
+ bool isStrictMode = executable->isStrictMode();
+
+ if (isStrictMode) {
+ if (ident == vm.propertyNames->callee) {
+ slot.setGetterSlot(thisObject, DontDelete | DontEnum | Accessor, thisObject->globalObject()->throwTypeErrorGetterSetter(vm));
+ return true;
+ }
+ if (ident == vm.propertyNames->caller) {
+ slot.setGetterSlot(thisObject, DontDelete | DontEnum | Accessor, thisObject->globalObject()->throwTypeErrorGetterSetter(vm));
+ return true;
+ }
+
+ } else if (ident == vm.propertyNames->callee) {
+ 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<ClonedArguments*>(object);
+ thisObject->materializeSpecialsIfNecessary(exec);
+ Base::getOwnPropertyNames(thisObject, exec, array, mode);
+}
+
+void ClonedArguments::put(JSCell* cell, ExecState* exec, PropertyName ident, JSValue value, PutPropertySlot& slot)
+{
+ ClonedArguments* thisObject = jsCast<ClonedArguments*>(cell);
+ VM& vm = exec->vm();
+
+ if (ident == vm.propertyNames->callee
+ || ident == vm.propertyNames->caller
+ || ident == vm.propertyNames->iteratorSymbol) {
+ thisObject->materializeSpecialsIfNecessary(exec);
+ PutPropertySlot dummy = slot; // Shadow the given PutPropertySlot to prevent caching.
+ 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<ClonedArguments*>(cell);
+ VM& vm = exec->vm();
+
+ if (ident == vm.propertyNames->callee
+ || ident == vm.propertyNames->caller
+ || 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<ClonedArguments*>(object);
+ VM& vm = exec->vm();
+
+ if (ident == vm.propertyNames->callee
+ || ident == vm.propertyNames->caller
+ || 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<FunctionExecutable*>(m_callee->executable());
+ bool isStrictMode = executable->isStrictMode();
+
+ if (isStrictMode) {
+ putDirectAccessor(exec, vm.propertyNames->callee, globalObject()->throwTypeErrorGetterSetter(vm), DontDelete | DontEnum | Accessor);
+ putDirectAccessor(exec, vm.propertyNames->caller, globalObject()->throwTypeErrorGetterSetter(vm), 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<ClonedArguments*>(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..8e713d5c6
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ClonedArguments.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#ifndef ClonedArguments_h
+#define ClonedArguments_h
+
+#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*);
+
+public:
+ static ClonedArguments* createEmpty(VM&, Structure*, JSFunction* callee);
+ static ClonedArguments* createEmpty(ExecState*, JSFunction* callee);
+ 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 void visitChildren(JSCell*, SlotVisitor&);
+
+ DECLARE_INFO;
+
+private:
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static void 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<JSFunction> m_callee; // Set to nullptr when we materialize all of our special properties.
+};
+
+} // namespace JSC
+
+#endif // ClonedArguments_h
+
diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp
index 510e383fa..cd9caf7ff 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
@@ -29,7 +29,7 @@
#include "BytecodeGenerator.h"
#include "CodeSpecializationKind.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "Parser.h"
#include "StrongInlines.h"
#include "UnlinkedCodeBlock.h"
@@ -67,21 +67,31 @@ template <typename T> struct CacheTypes { };
template <> struct CacheTypes<UnlinkedProgramCodeBlock> {
typedef JSC::ProgramNode RootNode;
static const SourceCodeKey::CodeType codeType = SourceCodeKey::ProgramType;
+ static const SourceParseMode parseMode = SourceParseMode::ProgramMode;
};
template <> struct CacheTypes<UnlinkedEvalCodeBlock> {
typedef JSC::EvalNode RootNode;
static const SourceCodeKey::CodeType codeType = SourceCodeKey::EvalType;
+ static const SourceParseMode parseMode = SourceParseMode::ProgramMode;
+};
+
+template <> struct CacheTypes<UnlinkedModuleProgramCodeBlock> {
+ typedef JSC::ModuleProgramNode RootNode;
+ static const SourceCodeKey::CodeType codeType = SourceCodeKey::ModuleType;
+ static const SourceParseMode parseMode = SourceParseMode::ModuleEvaluateMode;
};
template <class UnlinkedCodeBlockType, class ExecutableType>
-UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
+UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, ThisTDZMode thisTDZMode, bool, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error, const VariableEnvironment* variablesUnderTDZ)
{
- SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, strictness);
- CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue());
- bool canCache = debuggerMode == DebuggerOff && profilerMode == ProfilerOff;
- if (!addResult.isNewEntry && canCache) {
- UnlinkedCodeBlockType* unlinkedCodeBlock = jsCast<UnlinkedCodeBlockType*>(addResult.iterator->value.cell.get());
+ SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, builtinMode, strictMode, thisTDZMode);
+ SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key);
+ // FIXME: We should do something smart for TDZ instead of just disabling caching.
+ // https://bugs.webkit.org/show_bug.cgi?id=154010
+ bool canCache = debuggerMode == DebuggerOff && profilerMode == ProfilerOff && !vm.typeProfiler() && !vm.controlFlowProfiler() && !variablesUnderTDZ->size();
+ if (cache && canCache) {
+ UnlinkedCodeBlockType* unlinkedCodeBlock = jsCast<UnlinkedCodeBlockType*>(cache->cell.get());
unsigned firstLine = source.firstLine() + unlinkedCodeBlock->firstLine();
unsigned lineCount = unlinkedCodeBlock->lineCount();
unsigned startColumn = unlinkedCodeBlock->startColumn() + source.startColumn();
@@ -92,79 +102,99 @@ UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* exe
}
typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode;
- RefPtr<RootNode> rootNode = parse<RootNode>(&vm, source, 0, Identifier(), strictness, JSParseProgramCode, error);
- if (!rootNode) {
- m_sourceCode.remove(addResult.iterator);
- return 0;
- }
- unsigned lineCount = rootNode->lastLine() - rootNode->lineNo();
+ std::unique_ptr<RootNode> rootNode = parse<RootNode>(
+ &vm, source, Identifier(), builtinMode, strictMode,
+ CacheTypes<UnlinkedCodeBlockType>::parseMode, SuperBinding::NotNeeded, error, nullptr, ConstructorKind::None, thisTDZMode);
+ if (!rootNode)
+ return nullptr;
+
+ unsigned lineCount = rootNode->lastLine() - rootNode->firstLine();
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);
+ unsigned arrowContextFeature = executable->isArrowFunctionContext() ? ArrowFunctionContextFeature : 0;
+ executable->recordParse(rootNode->features() | arrowContextFeature, rootNode->hasCapturedVariables(), rootNode->firstLine(), rootNode->lastLine(), startColumn, endColumn);
UnlinkedCodeBlockType* unlinkedCodeBlock = UnlinkedCodeBlockType::create(&vm, executable->executableInfo());
- unlinkedCodeBlock->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->lineNo() - source.firstLine(), lineCount, unlinkedEndColumn);
+ unlinkedCodeBlock->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->firstLine() - source.firstLine(), lineCount, unlinkedEndColumn);
- OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(vm, rootNode.get(), unlinkedCodeBlock, debuggerMode, profilerMode)));
+ auto generator = std::make_unique<BytecodeGenerator>(vm, rootNode.get(), unlinkedCodeBlock, debuggerMode, profilerMode, variablesUnderTDZ);
error = generator->generate();
- rootNode->destroyData();
- if (error.m_type != ParserError::ErrorNone) {
- m_sourceCode.remove(addResult.iterator);
- return 0;
- }
+ if (error.isValid())
+ return nullptr;
- if (!canCache) {
- m_sourceCode.remove(addResult.iterator);
+ if (!canCache)
return unlinkedCodeBlock;
- }
- addResult.iterator->value = SourceCodeValue(vm, unlinkedCodeBlock, m_sourceCode.age());
+ m_sourceCode.addCache(key, 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::getProgramCodeBlock(VM& vm, ProgramExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
{
- return getGlobalCodeBlock<UnlinkedProgramCodeBlock>(vm, executable, source, strictness, debuggerMode, profilerMode, error);
+ VariableEnvironment emptyParentTDZVariables;
+ return getGlobalCodeBlock<UnlinkedProgramCodeBlock>(vm, executable, source, builtinMode, strictMode, ThisTDZMode::CheckIfNeeded, false, debuggerMode, profilerMode, error, &emptyParentTDZVariables);
}
-UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, EvalExecutable* executable, const SourceCode& source, JSParserStrictness strictness, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
+UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, EvalExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, ThisTDZMode thisTDZMode, bool isArrowFunctionContext, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error, const VariableEnvironment* variablesUnderTDZ)
{
- return getGlobalCodeBlock<UnlinkedEvalCodeBlock>(vm, executable, source, strictness, debuggerMode, profilerMode, error);
+ return getGlobalCodeBlock<UnlinkedEvalCodeBlock>(vm, executable, source, builtinMode, strictMode, thisTDZMode, isArrowFunctionContext, debuggerMode, profilerMode, error, variablesUnderTDZ);
}
+UnlinkedModuleProgramCodeBlock* CodeCache::getModuleProgramCodeBlock(VM& vm, ModuleProgramExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
+{
+ VariableEnvironment emptyParentTDZVariables;
+ return getGlobalCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, executable, source, builtinMode, JSParserStrictMode::Strict, ThisTDZMode::CheckIfNeeded, false, debuggerMode, profilerMode, error, &emptyParentTDZVariables);
+}
+
+// FIXME: There's no need to add the function's name to the key here. It's already in the source code.
UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& vm, const Identifier& name, const SourceCode& source, ParserError& error)
{
- SourceCodeKey key = SourceCodeKey(source, name.string(), SourceCodeKey::FunctionType, JSParseNormal);
- CodeCacheMap::AddResult addResult = m_sourceCode.add(key, SourceCodeValue());
- if (!addResult.isNewEntry)
- return jsCast<UnlinkedFunctionExecutable*>(addResult.iterator->value.cell.get());
+ SourceCodeKey key = SourceCodeKey(
+ source, name.string(), SourceCodeKey::FunctionType,
+ JSParserBuiltinMode::NotBuiltin,
+ JSParserStrictMode::NotStrict);
+ SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key);
+ if (cache)
+ return jsCast<UnlinkedFunctionExecutable*>(cache->cell.get());
JSTextPosition positionBeforeLastNewline;
- RefPtr<ProgramNode> program = parse<ProgramNode>(&vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error, &positionBeforeLastNewline);
+ std::unique_ptr<ProgramNode> program = parse<ProgramNode>(
+ &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
+ JSParserStrictMode::NotStrict, 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<ExprStatementNode*>(exprStatement)->expr();
- ASSERT(funcExpr);
- RELEASE_ASSERT(funcExpr->isFuncExprNode());
- FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body();
- body->setEndPosition(positionBeforeLastNewline);
- ASSERT(body);
- ASSERT(body->ident().isNull());
-
- UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, body, true);
+ // This function assumes an input string that would result in a single function declaration.
+ StatementNode* statement = program->singleStatement();
+ ASSERT(statement);
+ ASSERT(statement->isBlock());
+ if (!statement || !statement->isBlock())
+ return nullptr;
+
+ StatementNode* funcDecl = static_cast<BlockNode*>(statement)->singleStatement();
+ ASSERT(funcDecl);
+ ASSERT(funcDecl->isFuncDeclNode());
+ if (!funcDecl || !funcDecl->isFuncDeclNode())
+ return nullptr;
+
+ FunctionMetadataNode* metadata = static_cast<FuncDeclNode*>(funcDecl)->metadata();
+ ASSERT(metadata);
+ if (!metadata)
+ return nullptr;
+
+ metadata->setEndPosition(positionBeforeLastNewline);
+ // The Function constructor only has access to global variables, so no variables will be under TDZ.
+ VariableEnvironment emptyTDZVariables;
+ UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, ConstructAbility::CanConstruct, emptyTDZVariables, DerivedContextType::None);
+
functionExecutable->m_nameValue.set(vm, functionExecutable, jsString(&vm, name.string()));
- addResult.iterator->value = SourceCodeValue(vm, functionExecutable, m_sourceCode.age());
+ 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..2132f0c19 100644
--- a/Source/JavaScriptCore/runtime/CodeCache.h
+++ b/Source/JavaScriptCore/runtime/CodeCache.h
@@ -29,91 +29,34 @@
#include "CodeSpecializationKind.h"
#include "ParserModes.h"
#include "SourceCode.h"
+#include "SourceCodeKey.h"
#include "Strong.h"
-#include "WeakRandom.h"
+#include "VariableEnvironment.h"
#include <wtf/CurrentTime.h>
#include <wtf/Forward.h>
-#include <wtf/PassOwnPtr.h>
#include <wtf/RandomNumber.h>
+#include <wtf/WeakRandom.h>
#include <wtf/text/WTFString.h>
namespace JSC {
class EvalExecutable;
-class FunctionBodyNode;
+class FunctionMetadataNode;
class Identifier;
class JSScope;
+class ParserError;
class ProgramExecutable;
+class ModuleProgramExecutable;
class UnlinkedCodeBlock;
class UnlinkedEvalCodeBlock;
+class UnlinkedModuleProgramCodeBlock;
class UnlinkedFunctionCodeBlock;
class UnlinkedFunctionExecutable;
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<SourceCodeKey> {
- static const bool hasIsEmptyValueFunction = true;
- static bool isEmptyValue(const SourceCodeKey& sourceCodeKey) { return sourceCodeKey.isNull(); }
-};
-
struct SourceCodeValue {
SourceCodeValue()
{
@@ -145,18 +88,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 +111,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;
}
@@ -235,13 +188,15 @@ private:
// Caches top-level code such as <script>, eval(), new Function, and JSEvaluateScript().
class CodeCache {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- static PassOwnPtr<CodeCache> create() { return adoptPtr(new CodeCache); }
+ CodeCache();
+ ~CodeCache();
- UnlinkedProgramCodeBlock* getProgramCodeBlock(VM&, ProgramExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
- UnlinkedEvalCodeBlock* getEvalCodeBlock(VM&, EvalExecutable*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
+ UnlinkedProgramCodeBlock* getProgramCodeBlock(VM&, ProgramExecutable*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, DebuggerMode, ProfilerMode, ParserError&);
+ UnlinkedEvalCodeBlock* getEvalCodeBlock(VM&, EvalExecutable*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, ThisTDZMode, bool, DebuggerMode, ProfilerMode, ParserError&, const VariableEnvironment*);
+ UnlinkedModuleProgramCodeBlock* getModuleProgramCodeBlock(VM&, ModuleProgramExecutable*, const SourceCode&, JSParserBuiltinMode, DebuggerMode, ProfilerMode, ParserError&);
UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(VM&, const Identifier&, const SourceCode&, ParserError&);
- ~CodeCache();
void clear()
{
@@ -249,10 +204,8 @@ public:
}
private:
- CodeCache();
-
template <class UnlinkedCodeBlockType, class ExecutableType>
- UnlinkedCodeBlockType* getGlobalCodeBlock(VM&, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
+ UnlinkedCodeBlockType* getGlobalCodeBlock(VM&, ExecutableType*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, ThisTDZMode, bool, DebuggerMode, ProfilerMode, ParserError&, const VariableEnvironment*);
CodeCacheMap m_sourceCode;
};
diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp b/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp
index 3f5c645c0..475df2586 100644
--- a/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp
+++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp
@@ -21,25 +21,65 @@
#include "config.h"
#include "CommonIdentifiers.h"
+#include "BuiltinNames.h"
+#include "IdentifierInlines.h"
+#include "JSCBuiltins.h"
#include "PrivateName.h"
namespace JSC {
-#define INITIALIZE_PROPERTY_NAME(name) , name(vm, #name)
-#define INITIALIZE_KEYWORD(name) , name##Keyword(vm, #name)
-#define INITIALIZE_PRIVATE_NAME(name) , name##PrivateName(Identifier::from(PrivateName()))
+#define INITIALIZE_PROPERTY_NAME(name) , name(Identifier::fromString(vm, #name))
+#define INITIALIZE_KEYWORD(name) , name##Keyword(Identifier::fromString(vm, #name))
+#define INITIALIZE_PRIVATE_NAME(name) , name##PrivateName(m_builtinNames->name##PrivateName())
+#define INITIALIZE_SYMBOL(name) , name##Symbol(m_builtinNames->name##Symbol())
CommonIdentifiers::CommonIdentifiers(VM* vm)
: nullIdentifier()
, emptyIdentifier(Identifier::EmptyIdentifier)
- , underscoreProto(vm, "__proto__")
- , thisIdentifier(vm, "this")
- , useStrictIdentifier(vm, "use strict")
- , hasNextIdentifier(vm, "hasNext")
+ , underscoreProto(Identifier::fromString(vm, "__proto__"))
+ , thisIdentifier(Identifier::fromString(vm, "this"))
+ , useStrictIdentifier(Identifier::fromString(vm, "use strict"))
+ , timesIdentifier(Identifier::fromString(vm, "*"))
+ , m_builtinNames(new BuiltinNames(vm, this))
JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(INITIALIZE_KEYWORD)
JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME)
JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PRIVATE_NAME)
+ JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALIZE_SYMBOL)
{
}
+CommonIdentifiers::~CommonIdentifiers()
+{
+}
+
+bool CommonIdentifiers::isPrivateName(SymbolImpl& uid) const
+{
+ return m_builtinNames->isPrivateName(uid);
+}
+
+bool CommonIdentifiers::isPrivateName(UniquedStringImpl& uid) const
+{
+ return m_builtinNames->isPrivateName(uid);
+}
+
+bool CommonIdentifiers::isPrivateName(const Identifier& ident) const
+{
+ return m_builtinNames->isPrivateName(ident);
+}
+
+const Identifier* CommonIdentifiers::lookUpPrivateName(const Identifier& ident) const
+{
+ return m_builtinNames->lookUpPrivateName(ident);
+}
+
+Identifier CommonIdentifiers::lookUpPublicName(const Identifier& ident) const
+{
+ return m_builtinNames->lookUpPublicName(ident);
+}
+
+void CommonIdentifiers::appendExternalName(const Identifier& publicName, const Identifier& privateName)
+{
+ m_builtinNames->appendExternalName(publicName, privateName);
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.h b/Source/JavaScriptCore/runtime/CommonIdentifiers.h
index e8f9ed82b..2ca665fc3 100644
--- a/Source/JavaScriptCore/runtime/CommonIdentifiers.h
+++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.h
@@ -21,51 +21,65 @@
#ifndef CommonIdentifiers_h
#define CommonIdentifiers_h
+#include "BytecodeIntrinsicRegistry.h"
#include "Identifier.h"
#include <wtf/Noncopyable.h>
// MarkedArgumentBuffer of property names, passed to a macro so we can do set them up various
// ways without repeating the list.
#define JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(macro) \
- macro(ArgumentsIterator) \
macro(Array) \
macro(ArrayBuffer) \
macro(ArrayIterator) \
macro(BYTES_PER_ELEMENT) \
macro(Boolean) \
+ macro(Collator) \
macro(Date) \
+ macro(DateTimeFormat) \
macro(Error) \
macro(EvalError) \
macro(Function) \
+ macro(GeneratorFunction) \
macro(Infinity) \
+ macro(Intl) \
macro(JSON) \
+ macro(Loader) \
macro(Map)\
macro(MapIterator)\
macro(Math) \
macro(NaN) \
macro(Number) \
+ macro(NumberFormat) \
macro(Object) \
macro(Promise) \
+ macro(Proxy) \
macro(RangeError) \
macro(ReferenceError) \
+ macro(Reflect) \
macro(RegExp) \
macro(Set)\
macro(SetIterator)\
macro(String) \
+ macro(Symbol) \
macro(SyntaxError) \
macro(TypeError) \
macro(URIError) \
macro(UTC) \
macro(WeakMap)\
+ macro(WeakSet)\
macro(__defineGetter__) \
macro(__defineSetter__) \
macro(__lookupGetter__) \
macro(__lookupSetter__) \
macro(add) \
+ macro(additionalJettisonReason) \
macro(anonymous) \
- macro(apply) \
macro(arguments) \
+ macro(as) \
+ macro(assign) \
+ macro(back) \
macro(bind) \
+ macro(blur) \
macro(buffer) \
macro(byteLength) \
macro(byteOffset) \
@@ -73,11 +87,15 @@
macro(bytecodeIndex) \
macro(bytecodes) \
macro(bytecodesID) \
- macro(call) \
+ macro(calendar) \
macro(callee) \
macro(caller) \
- macro(cast) \
+ macro(caseFirst) \
macro(clear) \
+ macro(close) \
+ macro(closed) \
+ macro(collation) \
+ macro(column) \
macro(compilationKind) \
macro(compilations) \
macro(compile) \
@@ -85,6 +103,8 @@
macro(constructor) \
macro(count) \
macro(counters) \
+ macro(day) \
+ macro(defineProperty) \
macro(description) \
macro(descriptions) \
macro(displayName) \
@@ -92,33 +112,54 @@
macro(done) \
macro(entries) \
macro(enumerable) \
+ macro(era) \
macro(eval) \
macro(exec) \
macro(executionCount) \
macro(exitKind) \
+ macro(flags) \
+ macro(focus) \
macro(forEach) \
+ macro(formatMatcher) \
+ macro(forward) \
+ macro(frames) \
+ macro(from) \
macro(fromCharCode) \
macro(get) \
macro(global) \
+ macro(go) \
macro(has) \
macro(hasOwnProperty) \
macro(hash) \
macro(header) \
+ macro(hour) \
+ macro(hour12) \
+ macro(href) \
macro(id) \
macro(ignoreCase) \
+ macro(ignorePunctuation) \
macro(index) \
+ macro(indexedDB) \
macro(inferredName) \
macro(input) \
macro(instructionCount) \
macro(isArray) \
+ macro(isEnabled) \
macro(isPrototypeOf) \
macro(isView) \
macro(isWatchpoint) \
+ macro(jettisonReason) \
macro(join) \
macro(keys) \
macro(lastIndex) \
macro(length) \
+ macro(line) \
+ macro(locale) \
+ macro(localeMatcher) \
+ macro(location) \
macro(message) \
+ macro(minute) \
+ macro(month) \
macro(multiline) \
macro(name) \
macro(next) \
@@ -126,24 +167,42 @@
macro(numInlinedCalls) \
macro(numInlinedGetByIds) \
macro(numInlinedPutByIds) \
+ macro(numberingSystem) \
+ macro(numeric) \
macro(of) \
macro(opcode) \
+ macro(opener) \
macro(origin) \
macro(osrExitSites) \
macro(osrExits) \
+ macro(parent) \
macro(parse) \
+ macro(parseInt) \
+ macro(postMessage) \
macro(profiledBytecodes) \
macro(propertyIsEnumerable) \
macro(prototype) \
+ macro(raw) \
+ macro(reload) \
+ macro(replace) \
+ macro(resolve) \
+ macro(second) \
+ macro(self) \
+ macro(sensitivity) \
macro(set) \
+ macro(showModalDialog) \
macro(size) \
macro(slice) \
macro(source) \
macro(sourceCode) \
+ macro(sourceURL) \
macro(stack) \
macro(subarray) \
+ macro(target) \
macro(test) \
macro(then) \
+ macro(timeZone) \
+ macro(timeZoneName) \
macro(toExponential) \
macro(toFixed) \
macro(toISOString) \
@@ -151,11 +210,17 @@
macro(toLocaleString) \
macro(toPrecision) \
macro(toString) \
+ macro(top) \
+ macro(usage) \
macro(value) \
- macro(values) \
macro(valueOf) \
+ macro(values) \
+ macro(webkit) \
+ macro(webkitIndexedDB) \
+ macro(weekday) \
macro(window) \
- macro(writable)
+ macro(writable) \
+ macro(year)
#define JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(macro) \
macro(break) \
@@ -205,34 +270,129 @@
macro(with) \
macro(yield)
-#define JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(macro) \
+#define JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL_NOT_IMPLEMENTED_YET(macro)\
+ macro(isConcatSpreadable) \
+ macro(match) \
+ macro(replace) \
+ macro(split) \
+ macro(toPrimitive)
+
+#define JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(macro) \
+ macro(hasInstance) \
macro(iterator) \
- macro(iteratorNext) \
- macro(resolve) \
- macro(reject) \
+ macro(search) \
+ macro(species) \
+ macro(toStringTag) \
+ macro(unscopables)
+
+#define JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(macro) \
+ JSC_COMMON_BYTECODE_INTRINSIC_FUNCTIONS_EACH_NAME(macro) \
+ JSC_COMMON_BYTECODE_INTRINSIC_CONSTANTS_EACH_NAME(macro) \
+ macro(iteratedObject) \
+ macro(arrayIteratorNextIndex) \
+ macro(arrayIterationKind) \
+ macro(charCodeAt) \
+ macro(iteratedString) \
+ macro(stringIteratorNextIndex) \
macro(promise) \
macro(fulfillmentHandler) \
macro(rejectionHandler) \
macro(index) \
macro(values) \
macro(deferred) \
- macro(countdownHolder)
+ macro(countdownHolder) \
+ macro(Object) \
+ macro(ownEnumerablePropertyKeys) \
+ macro(Number) \
+ macro(Array) \
+ macro(String) \
+ macro(RegExp) \
+ macro(Map) \
+ macro(Promise) \
+ macro(InternalPromise) \
+ macro(abs) \
+ macro(floor) \
+ macro(isFinite) \
+ macro(isNaN) \
+ macro(getPrototypeOf) \
+ macro(getOwnPropertyNames) \
+ macro(RangeError) \
+ macro(TypeError) \
+ macro(typedArrayLength) \
+ macro(typedArraySort) \
+ macro(BuiltinLog) \
+ macro(homeObject) \
+ macro(getTemplateObject) \
+ macro(enqueueJob) \
+ macro(handler) \
+ macro(promiseState) \
+ macro(promiseFulfillReactions) \
+ macro(promiseRejectReactions) \
+ macro(promiseResult) \
+ macro(push) \
+ macro(capabilities) \
+ macro(starDefault) \
+ macro(InspectorInstrumentation) \
+ macro(get) \
+ macro(set) \
+ macro(shift) \
+ macro(allocateTypedArray) \
+ macro(Int8Array) \
+ macro(Int16Array) \
+ macro(Int32Array) \
+ macro(Uint8Array) \
+ macro(Uint8ClampedArray) \
+ macro(Uint16Array) \
+ macro(Uint32Array) \
+ macro(Float32Array) \
+ macro(Float64Array) \
+ macro(generator) \
+ macro(generatorNext) \
+ macro(generatorState) \
+ macro(generatorFrame) \
+ macro(generatorValue) \
+ macro(generatorThis) \
+ macro(generatorResumeMode) \
+ macro(Collator) \
+ macro(DateTimeFormat) \
+ macro(NumberFormat) \
+ macro(thisTimeValue) \
+ macro(newTargetLocal) \
+ macro(derivedConstructor) \
+ macro(isBoundFunction) \
+ macro(hasInstanceBoundFunction) \
+ macro(instanceOf) \
+ macro(isSet) \
+ macro(isMap) \
+ macro(SetIterator) \
+ macro(setIteratorNext) \
+ macro(MapIterator) \
+ macro(mapIteratorNext) \
-namespace JSC {
+namespace JSC {
+
+ class BuiltinNames;
+
class CommonIdentifiers {
WTF_MAKE_NONCOPYABLE(CommonIdentifiers); WTF_MAKE_FAST_ALLOCATED;
private:
CommonIdentifiers(VM*);
+ ~CommonIdentifiers();
friend class VM;
-
+
public:
+ const BuiltinNames& builtinNames() const { return *m_builtinNames; }
const Identifier nullIdentifier;
const Identifier emptyIdentifier;
const Identifier underscoreProto;
const Identifier thisIdentifier;
const Identifier useStrictIdentifier;
- const Identifier hasNextIdentifier;
+ const Identifier timesIdentifier;
+ private:
+ std::unique_ptr<BuiltinNames> m_builtinNames;
+
+ public:
#define JSC_IDENTIFIER_DECLARE_KEYWORD_NAME_GLOBAL(name) const Identifier name##Keyword;
JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(JSC_IDENTIFIER_DECLARE_KEYWORD_NAME_GLOBAL)
@@ -245,6 +405,21 @@ namespace JSC {
#define JSC_IDENTIFIER_DECLARE_PRIVATE_PROPERTY_NAME_GLOBAL(name) const Identifier name##PrivateName;
JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(JSC_IDENTIFIER_DECLARE_PRIVATE_PROPERTY_NAME_GLOBAL)
#undef JSC_IDENTIFIER_DECLARE_PRIVATE_PROPERTY_NAME_GLOBAL
+
+#define JSC_IDENTIFIER_DECLARE_PRIVATE_WELL_KNOWN_SYMBOL_GLOBAL(name) const Identifier name##Symbol;
+ JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(JSC_IDENTIFIER_DECLARE_PRIVATE_WELL_KNOWN_SYMBOL_GLOBAL)
+#undef JSC_IDENTIFIER_DECLARE_PRIVATE_WELL_KNOWN_SYMBOL_GLOBAL
+
+ bool isPrivateName(SymbolImpl& uid) const;
+ bool isPrivateName(UniquedStringImpl& uid) const;
+ bool isPrivateName(const Identifier&) const;
+
+ const Identifier* lookUpPrivateName(const Identifier&) const;
+ Identifier lookUpPublicName(const Identifier&) const;
+
+ // Callers of this method should make sure that identifiers given to this method
+ // survive the lifetime of CommonIdentifiers and related VM.
+ JS_EXPORT_PRIVATE void appendExternalName(const Identifier& publicName, const Identifier& privateName);
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
index f6a142e6d..78b43c4d3 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-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
@@ -25,32 +25,34 @@
#include "config.h"
#include "CommonSlowPaths.h"
-
-#if ENABLE(JIT) || ENABLE(LLINT)
-
-#include "Arguments.h"
#include "ArrayConstructor.h"
#include "CallFrame.h"
+#include "ClonedArguments.h"
#include "CodeProfiling.h"
#include "CommonSlowPathsExceptions.h"
+#include "DirectArguments.h"
+#include "Error.h"
+#include "ErrorHandlingScope.h"
+#include "ExceptionFuzz.h"
+#include "GeneratorFrame.h"
#include "GetterSetter.h"
#include "HostCallReturnValue.h"
#include "Interpreter.h"
#include "JIT.h"
-#include "JITStubs.h"
-#include "JSActivation.h"
+#include "JSCInlines.h"
#include "JSCJSValue.h"
#include "JSGlobalObjectFunctions.h"
-#include "JSNameScope.h"
-#include "JSPropertyNameIterator.h"
+#include "JSLexicalEnvironment.h"
+#include "JSPropertyNameEnumerator.h"
#include "JSString.h"
#include "JSWithScope.h"
#include "LLIntCommon.h"
#include "LLIntExceptions.h"
#include "LowLevelInterpreter.h"
#include "ObjectConstructor.h"
-#include "Operations.h"
+#include "ScopedArguments.h"
#include "StructureRareDataInlines.h"
+#include "TypeProfilerLog.h"
#include <wtf/StringPrintStream.h>
namespace JSC {
@@ -70,11 +72,7 @@ namespace JSC {
} while (false)
#endif
-#if ENABLE(LLINT)
#define RETURN_TO_THROW(exec, pc) pc = LLInt::returnToThrow(exec)
-#else
-#define RETURN_TO_THROW(exec, pc)
-#endif
#define BEGIN() \
BEGIN_NO_SET_PC(); \
@@ -96,6 +94,7 @@ namespace JSC {
} while (false)
#define CHECK_EXCEPTION() do { \
+ doExceptionFuzzingIfEnabled(exec, "CommonSlowPaths", pc); \
if (UNLIKELY(vm.exception())) { \
RETURN_TO_THROW(exec, pc); \
END_IMPL(); \
@@ -117,20 +116,19 @@ namespace JSC {
END_IMPL(); \
} while (false)
-#define RETURN(value) do { \
- JSValue rReturnValue = (value); \
- CHECK_EXCEPTION(); \
- OP(1) = rReturnValue; \
- END_IMPL(); \
+#define RETURN_WITH_PROFILING(value__, profilingAction__) do { \
+ JSValue returnValue__ = (value__); \
+ CHECK_EXCEPTION(); \
+ OP(1) = returnValue__; \
+ profilingAction__; \
+ END_IMPL(); \
} while (false)
-#define RETURN_PROFILED(opcode, value) do { \
- JSValue rpPeturnValue = (value); \
- CHECK_EXCEPTION(); \
- OP(1) = rpPeturnValue; \
- PROFILE_VALUE(opcode, rpPeturnValue); \
- END_IMPL(); \
- } while (false)
+#define RETURN(value) \
+ RETURN_WITH_PROFILING(value, { })
+
+#define RETURN_PROFILED(opcode__, value__) \
+ RETURN_WITH_PROFILING(value__, PROFILE_VALUE(opcode__, returnValue__))
#define PROFILE_VALUE(opcode, value) do { \
pc[OPCODE_LENGTH(opcode) - 1].u.profile->m_buckets[0] = \
@@ -161,67 +159,78 @@ namespace JSC {
CALL_END_IMPL(crExec, crCallTarget); \
} while (false)
+static CommonSlowPaths::ArityCheckData* setupArityCheckData(VM& vm, int slotsToAdd)
+{
+ CommonSlowPaths::ArityCheckData* result = vm.arityCheckData.get();
+ result->paddedStackSpace = slotsToAdd;
+#if ENABLE(JIT)
+ if (vm.canUseJIT())
+ result->thunkToCall = vm.getCTIStub(arityFixupGenerator).code().executableAddress();
+ else
+#endif
+ result->thunkToCall = 0;
+ return result;
+}
+
SLOW_PATH_DECL(slow_path_call_arityCheck)
{
BEGIN();
- int SlotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForCall);
- if (SlotsToAdd < 0) {
+ int slotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForCall);
+ if (slotsToAdd < 0) {
exec = exec->callerFrame();
+ ErrorHandlingScope errorScope(exec->vm());
CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec));
RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec);
}
- RETURN_TWO(0, reinterpret_cast<ExecState*>(SlotsToAdd));
+ RETURN_TWO(0, setupArityCheckData(vm, slotsToAdd));
}
SLOW_PATH_DECL(slow_path_construct_arityCheck)
{
BEGIN();
- int SlotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForConstruct);
- if (SlotsToAdd < 0) {
+ int slotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForConstruct);
+ if (slotsToAdd < 0) {
exec = exec->callerFrame();
+ ErrorHandlingScope errorScope(exec->vm());
CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec));
RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec);
}
- RETURN_TWO(0, reinterpret_cast<ExecState*>(SlotsToAdd));
+ RETURN_TWO(0, setupArityCheckData(vm, slotsToAdd));
}
-SLOW_PATH_DECL(slow_path_touch_entry)
+SLOW_PATH_DECL(slow_path_create_direct_arguments)
{
BEGIN();
- exec->codeBlock()->symbolTable()->m_functionEnteredOnce.touch();
- END();
+ RETURN(DirectArguments::createByCopying(exec));
}
-SLOW_PATH_DECL(slow_path_get_callee)
+SLOW_PATH_DECL(slow_path_create_scoped_arguments)
{
BEGIN();
- JSFunction* callee = jsCast<JSFunction*>(exec->callee());
- pc[2].u.jsCell.set(exec->vm(), exec->codeBlock()->ownerExecutable(), callee);
- RETURN(callee);
+ JSLexicalEnvironment* scope = jsCast<JSLexicalEnvironment*>(OP(2).jsValue());
+ ScopedArgumentsTable* table = scope->symbolTable()->arguments();
+ RETURN(ScopedArguments::createByCopying(exec, table, scope));
}
-SLOW_PATH_DECL(slow_path_create_arguments)
+SLOW_PATH_DECL(slow_path_create_out_of_band_arguments)
{
BEGIN();
- JSValue arguments = JSValue(Arguments::create(vm, exec));
- CHECK_EXCEPTION();
- exec->uncheckedR(pc[1].u.operand) = arguments;
- exec->uncheckedR(unmodifiedArgumentsRegister(VirtualRegister(pc[1].u.operand)).offset()) = arguments;
- END();
+ RETURN(ClonedArguments::createWithMachineFrame(exec, exec, ArgumentsMode::Cloned));
}
SLOW_PATH_DECL(slow_path_create_this)
{
BEGIN();
JSFunction* constructor = jsCast<JSFunction*>(OP(2).jsValue().asCell());
-
-#if !ASSERT_DISABLED
- ConstructData constructData;
- ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS);
-#endif
+
+ auto& cacheWriteBarrier = pc[4].u.jsCell;
+ if (!cacheWriteBarrier)
+ cacheWriteBarrier.set(exec->vm(), exec->codeBlock(), constructor);
+ else if (cacheWriteBarrier.unvalidatedGet() != JSCell::seenMultipleCalleeObjects() && cacheWriteBarrier.get() != constructor)
+ cacheWriteBarrier.setWithoutWriteBarrier(JSCell::seenMultipleCalleeObjects());
size_t inlineCapacity = pc[3].u.operand;
- Structure* structure = constructor->allocationProfile(exec, inlineCapacity)->structure();
+ Structure* structure = constructor->rareData(exec, inlineCapacity)->objectAllocationProfile()->structure();
RETURN(constructEmptyObject(exec, structure));
}
@@ -229,34 +238,31 @@ SLOW_PATH_DECL(slow_path_to_this)
{
BEGIN();
JSValue v1 = OP(1).jsValue();
- if (v1.isCell())
- pc[2].u.structure.set(exec->vm(), exec->codeBlock()->ownerExecutable(), v1.asCell()->structure());
- else
+ if (v1.isCell()) {
+ Structure* myStructure = v1.asCell()->structure(vm);
+ Structure* otherStructure = pc[2].u.structure.get();
+ if (myStructure != otherStructure) {
+ if (otherStructure)
+ pc[3].u.toThisStatus = ToThisConflicted;
+ pc[2].u.structure.set(vm, exec->codeBlock(), myStructure);
+ }
+ } else {
+ pc[3].u.toThisStatus = ToThisConflicted;
pc[2].u.structure.clear();
+ }
RETURN(v1.toThis(exec, exec->codeBlock()->isStrictMode() ? StrictMode : NotStrictMode));
}
-SLOW_PATH_DECL(slow_path_captured_mov)
+SLOW_PATH_DECL(slow_path_throw_tdz_error)
{
BEGIN();
- JSValue value = OP_C(2).jsValue();
- if (VariableWatchpointSet* set = pc[3].u.watchpointSet)
- set->notifyWrite(value);
- RETURN(value);
+ THROW(createTDZError(exec));
}
-SLOW_PATH_DECL(slow_path_new_captured_func)
+SLOW_PATH_DECL(slow_path_throw_strict_mode_readonly_property_write_error)
{
BEGIN();
- CodeBlock* codeBlock = exec->codeBlock();
- ASSERT(
- codeBlock->codeType() != FunctionCode
- || !codeBlock->needsFullScopeChain()
- || exec->uncheckedR(codeBlock->activationRegister().offset()).jsValue());
- JSValue value = JSFunction::create(vm, codeBlock->functionDecl(pc[2].u.operand), exec->scope());
- if (VariableWatchpointSet* set = pc[3].u.watchpointSet)
- set->notifyWrite(value);
- RETURN(value);
+ THROW(createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)));
}
SLOW_PATH_DECL(slow_path_not)
@@ -331,25 +337,69 @@ SLOW_PATH_DECL(slow_path_to_number)
RETURN(jsNumber(OP_C(2).jsValue().toNumber(exec)));
}
+SLOW_PATH_DECL(slow_path_to_string)
+{
+ BEGIN();
+ RETURN(OP_C(2).jsValue().toString(exec));
+}
+
SLOW_PATH_DECL(slow_path_negate)
{
BEGIN();
RETURN(jsNumber(-OP_C(2).jsValue().toNumber(exec)));
}
+#if ENABLE(DFG_JIT)
+static void updateResultProfileForBinaryArithOp(ExecState* exec, Instruction* pc, JSValue result, JSValue left, JSValue right)
+{
+ CodeBlock* codeBlock = exec->codeBlock();
+ unsigned bytecodeOffset = codeBlock->bytecodeOffset(pc);
+ ResultProfile* profile = codeBlock->ensureResultProfile(bytecodeOffset);
+
+ if (result.isNumber()) {
+ if (!result.isInt32()) {
+ if (left.isInt32() && right.isInt32())
+ profile->setObservedInt32Overflow();
+
+ double doubleVal = result.asNumber();
+ if (!doubleVal && std::signbit(doubleVal))
+ profile->setObservedNegZeroDouble();
+ else {
+ profile->setObservedNonNegZeroDouble();
+
+ // The Int52 overflow check here intentionally omits 1ll << 51 as a valid negative Int52 value.
+ // Therefore, we will get a false positive if the result is that value. This is intentionally
+ // done to simplify the checking algorithm.
+ static const int64_t int52OverflowPoint = (1ll << 51);
+ int64_t int64Val = static_cast<int64_t>(std::abs(doubleVal));
+ if (int64Val >= int52OverflowPoint)
+ profile->setObservedInt52Overflow();
+ }
+ }
+ } else
+ profile->setObservedNonNumber();
+}
+#else
+static void updateResultProfileForBinaryArithOp(ExecState*, Instruction*, JSValue, JSValue, JSValue) { }
+#endif
+
SLOW_PATH_DECL(slow_path_add)
{
BEGIN();
JSValue v1 = OP_C(2).jsValue();
JSValue v2 = OP_C(3).jsValue();
-
+ JSValue result;
+
if (v1.isString() && !v2.isObject())
- RETURN(jsString(exec, asString(v1), v2.toString(exec)));
-
- if (v1.isNumber() && v2.isNumber())
- RETURN(jsNumber(v1.asNumber() + v2.asNumber()));
-
- RETURN(jsAddSlowCase(exec, v1, v2));
+ result = jsString(exec, asString(v1), v2.toString(exec));
+ else if (v1.isNumber() && v2.isNumber())
+ result = jsNumber(v1.asNumber() + v2.asNumber());
+ else
+ result = jsAddSlowCase(exec, v1, v2);
+
+ RETURN_WITH_PROFILING(result, {
+ updateResultProfileForBinaryArithOp(exec, pc, result, v1, v2);
+ });
}
// The following arithmetic and bitwise operations need to be sure to run
@@ -359,25 +409,40 @@ SLOW_PATH_DECL(slow_path_add)
SLOW_PATH_DECL(slow_path_mul)
{
BEGIN();
- double a = OP_C(2).jsValue().toNumber(exec);
- double b = OP_C(3).jsValue().toNumber(exec);
- RETURN(jsNumber(a * b));
+ JSValue left = OP_C(2).jsValue();
+ JSValue right = OP_C(3).jsValue();
+ double a = left.toNumber(exec);
+ double b = right.toNumber(exec);
+ JSValue result = jsNumber(a * b);
+ RETURN_WITH_PROFILING(result, {
+ updateResultProfileForBinaryArithOp(exec, pc, result, left, right);
+ });
}
SLOW_PATH_DECL(slow_path_sub)
{
BEGIN();
- double a = OP_C(2).jsValue().toNumber(exec);
- double b = OP_C(3).jsValue().toNumber(exec);
- RETURN(jsNumber(a - b));
+ JSValue left = OP_C(2).jsValue();
+ JSValue right = OP_C(3).jsValue();
+ double a = left.toNumber(exec);
+ double b = right.toNumber(exec);
+ JSValue result = jsNumber(a - b);
+ RETURN_WITH_PROFILING(result, {
+ updateResultProfileForBinaryArithOp(exec, pc, result, left, right);
+ });
}
SLOW_PATH_DECL(slow_path_div)
{
BEGIN();
- double a = OP_C(2).jsValue().toNumber(exec);
- double b = OP_C(3).jsValue().toNumber(exec);
- RETURN(jsNumber(a / b));
+ JSValue left = OP_C(2).jsValue();
+ JSValue right = OP_C(3).jsValue();
+ double a = left.toNumber(exec);
+ double b = right.toNumber(exec);
+ JSValue result = jsNumber(a / b);
+ RETURN_WITH_PROFILING(result, {
+ updateResultProfileForBinaryArithOp(exec, pc, result, left, right);
+ });
}
SLOW_PATH_DECL(slow_path_mod)
@@ -449,10 +514,10 @@ SLOW_PATH_DECL(slow_path_typeof)
RETURN(jsTypeStringForValue(exec, OP_C(2).jsValue()));
}
-SLOW_PATH_DECL(slow_path_is_object)
+SLOW_PATH_DECL(slow_path_is_object_or_null)
{
BEGIN();
- RETURN(jsBoolean(jsIsObjectType(exec, OP_C(2).jsValue())));
+ RETURN(jsBoolean(jsIsObjectTypeOrNull(exec, OP_C(2).jsValue())));
}
SLOW_PATH_DECL(slow_path_is_function)
@@ -480,11 +545,9 @@ SLOW_PATH_DECL(slow_path_del_by_val)
uint32_t i;
if (subscript.getUInt32(i))
couldDelete = baseObject->methodTable()->deletePropertyByIndex(baseObject, exec, i);
- else if (isName(subscript))
- couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, jsCast<NameInstance*>(subscript.asCell())->privateName());
else {
CHECK_EXCEPTION();
- Identifier property(exec, subscript.toString(exec)->value(exec));
+ auto property = subscript.toPropertyKey(exec);
CHECK_EXCEPTION();
couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, property);
}
@@ -510,11 +573,228 @@ SLOW_PATH_DECL(slow_path_to_primitive)
SLOW_PATH_DECL(slow_path_enter)
{
BEGIN();
- ScriptExecutable* ownerExecutable = exec->codeBlock()->ownerExecutable();
- Heap::heap(ownerExecutable)->writeBarrier(ownerExecutable);
+ CodeBlock* codeBlock = exec->codeBlock();
+ Heap::heap(codeBlock)->writeBarrier(codeBlock);
END();
}
-} // namespace JSC
+SLOW_PATH_DECL(slow_path_get_enumerable_length)
+{
+ BEGIN();
+ JSValue enumeratorValue = OP(2).jsValue();
+ if (enumeratorValue.isUndefinedOrNull())
+ RETURN(jsNumber(0));
+
+ JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(enumeratorValue.asCell());
+
+ RETURN(jsNumber(enumerator->indexedLength()));
+}
+
+SLOW_PATH_DECL(slow_path_has_indexed_property)
+{
+ BEGIN();
+ JSObject* base = OP(2).jsValue().toObject(exec);
+ JSValue property = OP(3).jsValue();
+ pc[4].u.arrayProfile->observeStructure(base->structure(vm));
+ ASSERT(property.isUInt32());
+ RETURN(jsBoolean(base->hasProperty(exec, property.asUInt32())));
+}
+
+SLOW_PATH_DECL(slow_path_has_structure_property)
+{
+ BEGIN();
+ JSObject* base = OP(2).jsValue().toObject(exec);
+ JSValue property = OP(3).jsValue();
+ ASSERT(property.isString());
+ JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(OP(4).jsValue().asCell());
+ if (base->structure(vm)->id() == enumerator->cachedStructureID())
+ RETURN(jsBoolean(true));
+ RETURN(jsBoolean(base->hasProperty(exec, asString(property.asCell())->toIdentifier(exec))));
+}
+
+SLOW_PATH_DECL(slow_path_has_generic_property)
+{
+ BEGIN();
+ JSObject* base = OP(2).jsValue().toObject(exec);
+ JSValue property = OP(3).jsValue();
+ bool result;
+ if (property.isString())
+ result = base->hasProperty(exec, asString(property.asCell())->toIdentifier(exec));
+ else {
+ ASSERT(property.isUInt32());
+ result = base->hasProperty(exec, property.asUInt32());
+ }
+ RETURN(jsBoolean(result));
+}
+
+SLOW_PATH_DECL(slow_path_get_direct_pname)
+{
+ BEGIN();
+ JSValue baseValue = OP_C(2).jsValue();
+ JSValue property = OP(3).jsValue();
+ ASSERT(property.isString());
+ RETURN(baseValue.get(exec, asString(property)->toIdentifier(exec)));
+}
-#endif // ENABLE(JIT) || ENABLE(LLINT)
+SLOW_PATH_DECL(slow_path_get_property_enumerator)
+{
+ BEGIN();
+ JSValue baseValue = OP(2).jsValue();
+ if (baseValue.isUndefinedOrNull())
+ RETURN(JSPropertyNameEnumerator::create(vm));
+
+ JSObject* base = baseValue.toObject(exec);
+
+ RETURN(propertyNameEnumerator(exec, base));
+}
+
+SLOW_PATH_DECL(slow_path_next_structure_enumerator_pname)
+{
+ BEGIN();
+ JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(OP(2).jsValue().asCell());
+ uint32_t index = OP(3).jsValue().asUInt32();
+
+ JSString* propertyName = nullptr;
+ if (index < enumerator->endStructurePropertyIndex())
+ propertyName = enumerator->propertyNameAtIndex(index);
+ RETURN(propertyName ? propertyName : jsNull());
+}
+
+SLOW_PATH_DECL(slow_path_next_generic_enumerator_pname)
+{
+ BEGIN();
+ JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(OP(2).jsValue().asCell());
+ uint32_t index = OP(3).jsValue().asUInt32();
+
+ JSString* propertyName = nullptr;
+ if (enumerator->endStructurePropertyIndex() <= index && index < enumerator->endGenericPropertyIndex())
+ propertyName = enumerator->propertyNameAtIndex(index);
+ RETURN(propertyName ? propertyName : jsNull());
+}
+
+SLOW_PATH_DECL(slow_path_to_index_string)
+{
+ BEGIN();
+ RETURN(jsString(exec, Identifier::from(exec, OP(2).jsValue().asUInt32()).string()));
+}
+
+SLOW_PATH_DECL(slow_path_profile_type_clear_log)
+{
+ BEGIN();
+ vm.typeProfilerLog()->processLogEntries(ASCIILiteral("LLInt log full."));
+ END();
+}
+
+SLOW_PATH_DECL(slow_path_assert)
+{
+ BEGIN();
+ ASSERT_WITH_MESSAGE(OP(1).jsValue().asBoolean(), "JS assertion failed at line %d in:\n%s\n", pc[2].u.operand, exec->codeBlock()->sourceCodeForTools().data());
+ END();
+}
+
+SLOW_PATH_DECL(slow_path_save)
+{
+ // Only save variables and temporary registers. The scope registers are included in them.
+ // But parameters are not included. Because the generator implementation replaces the values of parameters on each generator.next() call.
+ BEGIN();
+ JSValue generator = OP(1).jsValue();
+ GeneratorFrame* frame = nullptr;
+ JSValue value = generator.get(exec, exec->propertyNames().generatorFramePrivateName);
+ if (!value.isNull())
+ frame = jsCast<GeneratorFrame*>(value);
+ else {
+ // FIXME: Once JSGenerator specialized object is introduced, this GeneratorFrame should be embeded into it to avoid allocations.
+ // https://bugs.webkit.org/show_bug.cgi?id=151545
+ frame = GeneratorFrame::create(exec->vm(), exec->codeBlock()->numCalleeLocals());
+ PutPropertySlot slot(generator, true, PutPropertySlot::PutById);
+ asObject(generator)->methodTable(exec->vm())->put(asObject(generator), exec, exec->propertyNames().generatorFramePrivateName, frame, slot);
+ }
+ unsigned liveCalleeLocalsIndex = pc[2].u.unsignedValue;
+ frame->save(exec, exec->codeBlock()->liveCalleeLocalsAtYield(liveCalleeLocalsIndex));
+ END();
+}
+
+SLOW_PATH_DECL(slow_path_resume)
+{
+ BEGIN();
+ JSValue generator = OP(1).jsValue();
+ GeneratorFrame* frame = jsCast<GeneratorFrame*>(generator.get(exec, exec->propertyNames().generatorFramePrivateName));
+ unsigned liveCalleeLocalsIndex = pc[2].u.unsignedValue;
+ frame->resume(exec, exec->codeBlock()->liveCalleeLocalsAtYield(liveCalleeLocalsIndex));
+ END();
+}
+
+SLOW_PATH_DECL(slow_path_create_lexical_environment)
+{
+ BEGIN();
+ int scopeReg = pc[2].u.operand;
+ JSScope* currentScope = exec->uncheckedR(scopeReg).Register::scope();
+ SymbolTable* symbolTable = jsCast<SymbolTable*>(OP_C(3).jsValue());
+ JSValue initialValue = OP_C(4).jsValue();
+ ASSERT(initialValue == jsUndefined() || initialValue == jsTDZValue());
+ JSScope* newScope = JSLexicalEnvironment::create(vm, exec->lexicalGlobalObject(), currentScope, symbolTable, initialValue);
+ RETURN(newScope);
+}
+
+SLOW_PATH_DECL(slow_path_push_with_scope)
+{
+ BEGIN();
+ JSObject* newScope = OP_C(2).jsValue().toObject(exec);
+ CHECK_EXCEPTION();
+
+ int scopeReg = pc[3].u.operand;
+ JSScope* currentScope = exec->uncheckedR(scopeReg).Register::scope();
+ RETURN(JSWithScope::create(exec, newScope, currentScope));
+}
+
+SLOW_PATH_DECL(slow_path_resolve_scope)
+{
+ BEGIN();
+ const Identifier& ident = exec->codeBlock()->identifier(pc[3].u.operand);
+ JSScope* scope = exec->uncheckedR(pc[2].u.operand).Register::scope();
+ JSValue resolvedScope = JSScope::resolve(exec, scope, ident);
+
+ ResolveType resolveType = static_cast<ResolveType>(pc[4].u.operand);
+
+ // ModuleVar does not keep the scope register value alive in DFG.
+ ASSERT(resolveType != ModuleVar);
+
+ if (resolveType == UnresolvedProperty || resolveType == UnresolvedPropertyWithVarInjectionChecks) {
+ if (JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsDynamicCast<JSGlobalLexicalEnvironment*>(resolvedScope)) {
+ if (resolveType == UnresolvedProperty)
+ pc[4].u.operand = GlobalLexicalVar;
+ else
+ pc[4].u.operand = GlobalLexicalVarWithVarInjectionChecks;
+ pc[6].u.pointer = globalLexicalEnvironment;
+ } else if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(resolvedScope)) {
+ if (globalObject->hasProperty(exec, ident)) {
+ if (resolveType == UnresolvedProperty)
+ pc[4].u.operand = GlobalProperty;
+ else
+ pc[4].u.operand = GlobalPropertyWithVarInjectionChecks;
+
+ pc[6].u.pointer = globalObject;
+ }
+ }
+ }
+
+ RETURN(resolvedScope);
+}
+
+SLOW_PATH_DECL(slow_path_copy_rest)
+{
+ BEGIN();
+ unsigned arraySize = OP_C(2).jsValue().asUInt32();
+ if (!arraySize) {
+ ASSERT(!jsCast<JSArray*>(OP(1).jsValue())->length());
+ END();
+ }
+ JSArray* array = jsCast<JSArray*>(OP(1).jsValue());
+ ASSERT(arraySize == array->length());
+ unsigned numParamsToSkip = pc[3].u.unsignedValue;
+ for (unsigned i = 0; i < arraySize; i++)
+ array->putDirectIndex(exec, i, exec->uncheckedArgument(i + numParamsToSkip));
+ END();
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
index cfc8bdbb7..98fe5db26 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2013, 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
@@ -30,14 +30,12 @@
#include "CodeSpecializationKind.h"
#include "ExceptionHelpers.h"
#include "JSStackInlines.h"
-#include "NameInstance.h"
+#include "SlowPathReturnType.h"
#include "StackAlignment.h"
+#include "Symbol.h"
#include "VM.h"
-#include <wtf/Platform.h>
#include <wtf/StdLibExtras.h>
-#if ENABLE(JIT) || ENABLE(LLINT)
-
namespace JSC {
// The purpose of this namespace is to include slow paths that are shared
@@ -49,6 +47,11 @@ namespace JSC {
namespace CommonSlowPaths {
+struct ArityCheckData {
+ unsigned paddedStackSpace;
+ void* thunkToCall;
+};
+
ALWAYS_INLINE int arityCheckFor(ExecState* exec, JSStack* stack, CodeSpecializationKind kind)
{
JSFunction* callee = jsCast<JSFunction*>(exec->callee());
@@ -57,25 +60,20 @@ ALWAYS_INLINE int arityCheckFor(ExecState* exec, JSStack* stack, CodeSpecializat
int argumentCountIncludingThis = exec->argumentCountIncludingThis();
ASSERT(argumentCountIncludingThis < newCodeBlock->numParameters());
- int missingArgumentCount = newCodeBlock->numParameters() - argumentCountIncludingThis;
- int paddedMissingArgumentCount = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), missingArgumentCount);
+ int frameSize = argumentCountIncludingThis + JSStack::CallFrameHeaderSize;
+ int alignedFrameSizeForParameters = WTF::roundUpToMultipleOf(stackAlignmentRegisters(),
+ newCodeBlock->numParameters() + JSStack::CallFrameHeaderSize);
+ int paddedStackSpace = alignedFrameSizeForParameters - frameSize;
-#if USE(SEPARATE_C_AND_JS_STACK)
- if (!stack->grow(exec->registers() - paddedMissingArgumentCount))
- return -1;
-#else
- UNUSED_PARAM(stack);
- if (!exec->vm().isSafeToRecurse(paddedMissingArgumentCount * sizeof(Register)))
+ if (!stack->ensureCapacityFor(exec->registers() - paddedStackSpace % stackAlignmentRegisters()))
return -1;
-#endif // USE(SEPARATE_C_AND_JS_STACK)
-
- return paddedMissingArgumentCount;
+ return paddedStackSpace;
}
inline bool opIn(ExecState* exec, JSValue propName, JSValue baseVal)
{
if (!baseVal.isObject()) {
- exec->vm().throwException(exec, createInvalidParameterError(exec, "in", baseVal));
+ exec->vm().throwException(exec, createInvalidInParameterError(exec, baseVal));
return false;
}
@@ -85,71 +83,99 @@ inline bool opIn(ExecState* exec, JSValue propName, JSValue baseVal)
if (propName.getUInt32(i))
return baseObj->hasProperty(exec, i);
- if (isName(propName))
- return baseObj->hasProperty(exec, jsCast<NameInstance*>(propName.asCell())->privateName());
-
- Identifier property(exec, propName.toString(exec)->value(exec));
+ auto property = propName.toPropertyKey(exec);
if (exec->vm().exception())
return false;
return baseObj->hasProperty(exec, property);
}
-} // namespace CommonSlowPaths
-
-class ExecState;
-struct Instruction;
-
-#if USE(JSVALUE64)
-// According to C++ rules, a type used for the return signature of function with C linkage (i.e.
-// 'extern "C"') needs to be POD; hence putting any constructors into it could cause either compiler
-// warnings, or worse, a change in the ABI used to return these types.
-struct SlowPathReturnType {
- void* a;
- void* b;
-};
-
-inline SlowPathReturnType encodeResult(void* a, void* b)
+inline void tryCachePutToScopeGlobal(
+ ExecState* exec, CodeBlock* codeBlock, Instruction* pc, JSObject* scope,
+ GetPutInfo getPutInfo, PutPropertySlot& slot, const Identifier& ident)
{
- SlowPathReturnType result;
- result.a = a;
- result.b = b;
- return result;
+ // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
+ ResolveType resolveType = getPutInfo.resolveType();
+ if (resolveType != GlobalProperty && resolveType != GlobalPropertyWithVarInjectionChecks
+ && resolveType != UnresolvedProperty && resolveType != UnresolvedPropertyWithVarInjectionChecks)
+ return;
+
+ if (resolveType == UnresolvedProperty || resolveType == UnresolvedPropertyWithVarInjectionChecks) {
+ if (JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsDynamicCast<JSGlobalLexicalEnvironment*>(scope)) {
+ ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalLexicalVar : GlobalLexicalVarWithVarInjectionChecks;
+ pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand();
+ SymbolTableEntry entry = globalLexicalEnvironment->symbolTable()->get(ident.impl());
+ ASSERT(!entry.isNull());
+ pc[5].u.watchpointSet = entry.watchpointSet();
+ pc[6].u.pointer = static_cast<void*>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot());
+ } else if (jsDynamicCast<JSGlobalObject*>(scope)) {
+ ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalProperty : GlobalPropertyWithVarInjectionChecks;
+ resolveType = newResolveType;
+ getPutInfo = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode());
+ pc[4].u.operand = getPutInfo.operand();
+ }
+ }
+
+ if (resolveType == GlobalProperty || resolveType == GlobalPropertyWithVarInjectionChecks) {
+ if (!slot.isCacheablePut()
+ || slot.base() != scope
+ || !scope->structure()->propertyAccessesAreCacheable())
+ return;
+
+ if (slot.type() == PutPropertySlot::NewProperty) {
+ // Don't cache if we've done a transition. We want to detect the first replace so that we
+ // can invalidate the watchpoint.
+ return;
+ }
+
+ scope->structure()->didCachePropertyReplacement(exec->vm(), slot.cachedOffset());
+
+ ConcurrentJITLocker locker(codeBlock->m_lock);
+ pc[5].u.structure.set(exec->vm(), codeBlock, scope->structure());
+ pc[6].u.operand = slot.cachedOffset();
+ }
}
-inline void decodeResult(SlowPathReturnType result, void*& a, void*& b)
+inline void tryCacheGetFromScopeGlobal(
+ ExecState* exec, VM& vm, Instruction* pc, JSObject* scope, PropertySlot& slot, const Identifier& ident)
{
- a = result.a;
- b = result.b;
-}
+ GetPutInfo getPutInfo(pc[4].u.operand);
+ ResolveType resolveType = getPutInfo.resolveType();
+
+ if (resolveType == UnresolvedProperty || resolveType == UnresolvedPropertyWithVarInjectionChecks) {
+ if (JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsDynamicCast<JSGlobalLexicalEnvironment*>(scope)) {
+ ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalLexicalVar : GlobalLexicalVarWithVarInjectionChecks;
+ pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand();
+ SymbolTableEntry entry = globalLexicalEnvironment->symbolTable()->get(ident.impl());
+ ASSERT(!entry.isNull());
+ pc[5].u.watchpointSet = entry.watchpointSet();
+ pc[6].u.pointer = static_cast<void*>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot());
+ } else if (jsDynamicCast<JSGlobalObject*>(scope)) {
+ ResolveType newResolveType = resolveType == UnresolvedProperty ? GlobalProperty : GlobalPropertyWithVarInjectionChecks;
+ resolveType = newResolveType; // Allow below caching mechanism to kick in.
+ pc[4].u.operand = GetPutInfo(getPutInfo.resolveMode(), newResolveType, getPutInfo.initializationMode()).operand();
+ }
+ }
-#else // USE(JSVALUE32_64)
-typedef int64_t SlowPathReturnType;
+ // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
+ if (slot.isCacheableValue() && slot.slotBase() == scope && scope->structure()->propertyAccessesAreCacheable()) {
+ if (resolveType == GlobalProperty || resolveType == GlobalPropertyWithVarInjectionChecks) {
+ CodeBlock* codeBlock = exec->codeBlock();
+ Structure* structure = scope->structure(vm);
+ {
+ ConcurrentJITLocker locker(codeBlock->m_lock);
+ pc[5].u.structure.set(exec->vm(), codeBlock, structure);
+ pc[6].u.operand = slot.cachedOffset();
+ }
+ structure->startWatchingPropertyForReplacements(vm, slot.cachedOffset());
+ }
+ }
+}
-typedef union {
- struct {
- void* a;
- void* b;
- } pair;
- int64_t i;
-} SlowPathReturnTypeEncoding;
+} // namespace CommonSlowPaths
-inline SlowPathReturnType encodeResult(void* a, void* b)
-{
- SlowPathReturnTypeEncoding u;
- u.pair.a = a;
- u.pair.b = b;
- return u.i;
-}
+class ExecState;
+struct Instruction;
-inline void decodeResult(SlowPathReturnType result, void*& a, void*& b)
-{
- SlowPathReturnTypeEncoding u;
- u.i = result;
- a = u.pair.a;
- b = u.pair.b;
-}
-#endif // USE(JSVALUE32_64)
-
#define SLOW_PATH
#define SLOW_PATH_DECL(name) \
@@ -160,14 +186,15 @@ SLOW_PATH_DECL(name) WTF_INTERNAL
SLOW_PATH_HIDDEN_DECL(slow_path_call_arityCheck);
SLOW_PATH_HIDDEN_DECL(slow_path_construct_arityCheck);
-SLOW_PATH_HIDDEN_DECL(slow_path_touch_entry);
-SLOW_PATH_HIDDEN_DECL(slow_path_create_arguments);
+SLOW_PATH_HIDDEN_DECL(slow_path_create_direct_arguments);
+SLOW_PATH_HIDDEN_DECL(slow_path_create_scoped_arguments);
+SLOW_PATH_HIDDEN_DECL(slow_path_create_out_of_band_arguments);
SLOW_PATH_HIDDEN_DECL(slow_path_create_this);
SLOW_PATH_HIDDEN_DECL(slow_path_enter);
SLOW_PATH_HIDDEN_DECL(slow_path_get_callee);
SLOW_PATH_HIDDEN_DECL(slow_path_to_this);
-SLOW_PATH_HIDDEN_DECL(slow_path_captured_mov);
-SLOW_PATH_HIDDEN_DECL(slow_path_new_captured_func);
+SLOW_PATH_HIDDEN_DECL(slow_path_throw_tdz_error);
+SLOW_PATH_HIDDEN_DECL(slow_path_throw_strict_mode_readonly_property_write_error);
SLOW_PATH_HIDDEN_DECL(slow_path_not);
SLOW_PATH_HIDDEN_DECL(slow_path_eq);
SLOW_PATH_HIDDEN_DECL(slow_path_neq);
@@ -180,6 +207,7 @@ SLOW_PATH_HIDDEN_DECL(slow_path_greatereq);
SLOW_PATH_HIDDEN_DECL(slow_path_inc);
SLOW_PATH_HIDDEN_DECL(slow_path_dec);
SLOW_PATH_HIDDEN_DECL(slow_path_to_number);
+SLOW_PATH_HIDDEN_DECL(slow_path_to_string);
SLOW_PATH_HIDDEN_DECL(slow_path_negate);
SLOW_PATH_HIDDEN_DECL(slow_path_add);
SLOW_PATH_HIDDEN_DECL(slow_path_mul);
@@ -195,14 +223,30 @@ SLOW_PATH_HIDDEN_DECL(slow_path_bitor);
SLOW_PATH_HIDDEN_DECL(slow_path_bitxor);
SLOW_PATH_HIDDEN_DECL(slow_path_typeof);
SLOW_PATH_HIDDEN_DECL(slow_path_is_object);
+SLOW_PATH_HIDDEN_DECL(slow_path_is_object_or_null);
SLOW_PATH_HIDDEN_DECL(slow_path_is_function);
SLOW_PATH_HIDDEN_DECL(slow_path_in);
SLOW_PATH_HIDDEN_DECL(slow_path_del_by_val);
SLOW_PATH_HIDDEN_DECL(slow_path_strcat);
SLOW_PATH_HIDDEN_DECL(slow_path_to_primitive);
+SLOW_PATH_HIDDEN_DECL(slow_path_get_enumerable_length);
+SLOW_PATH_HIDDEN_DECL(slow_path_has_generic_property);
+SLOW_PATH_HIDDEN_DECL(slow_path_has_structure_property);
+SLOW_PATH_HIDDEN_DECL(slow_path_has_indexed_property);
+SLOW_PATH_HIDDEN_DECL(slow_path_get_direct_pname);
+SLOW_PATH_HIDDEN_DECL(slow_path_get_property_enumerator);
+SLOW_PATH_HIDDEN_DECL(slow_path_next_structure_enumerator_pname);
+SLOW_PATH_HIDDEN_DECL(slow_path_next_generic_enumerator_pname);
+SLOW_PATH_HIDDEN_DECL(slow_path_to_index_string);
+SLOW_PATH_HIDDEN_DECL(slow_path_profile_type_clear_log);
+SLOW_PATH_HIDDEN_DECL(slow_path_assert);
+SLOW_PATH_HIDDEN_DECL(slow_path_save);
+SLOW_PATH_HIDDEN_DECL(slow_path_resume);
+SLOW_PATH_HIDDEN_DECL(slow_path_create_lexical_environment);
+SLOW_PATH_HIDDEN_DECL(slow_path_push_with_scope);
+SLOW_PATH_HIDDEN_DECL(slow_path_resolve_scope);
+SLOW_PATH_HIDDEN_DECL(slow_path_copy_rest);
} // namespace JSC
-#endif // ENABLE(JIT) || ENABLE(LLINT)
-
#endif // CommonSlowPaths_h
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.cpp b/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.cpp
index 55334be2f..f586ed089 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.cpp
+++ b/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.cpp
@@ -30,6 +30,7 @@
#include "CodeBlock.h"
#include "JITExceptions.h"
#include "LLIntCommon.h"
+#include "JSCInlines.h"
namespace JSC { namespace CommonSlowPaths {
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.h b/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.h
index 25d683c11..adcbfd47d 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.h
+++ b/Source/JavaScriptCore/runtime/CommonSlowPathsExceptions.h
@@ -26,8 +26,6 @@
#ifndef CommonSlowPathExceptions_h
#define CommonSlowPathExceptions_h
-#include <wtf/Platform.h>
-
#include "MacroAssemblerCodeRef.h"
namespace JSC {
diff --git a/Source/JavaScriptCore/runtime/Completion.cpp b/Source/JavaScriptCore/runtime/Completion.cpp
index 9d7fd1a74..c178a4a52 100644
--- a/Source/JavaScriptCore/runtime/Completion.cpp
+++ b/Source/JavaScriptCore/runtime/Completion.cpp
@@ -26,11 +26,19 @@
#include "CallFrame.h"
#include "CodeProfiling.h"
#include "Debugger.h"
+#include "Exception.h"
+#include "IdentifierInlines.h"
#include "Interpreter.h"
+#include "JSCInlines.h"
#include "JSGlobalObject.h"
+#include "JSInternalPromise.h"
+#include "JSInternalPromiseDeferred.h"
#include "JSLock.h"
-#include "Operations.h"
+#include "JSModuleRecord.h"
+#include "ModuleAnalyzer.h"
+#include "ModuleLoaderObject.h"
#include "Parser.h"
+#include "ScriptProfilingScope.h"
#include <wtf/WTFThreadData.h>
namespace JSC {
@@ -38,7 +46,7 @@ namespace JSC {
bool checkSyntax(ExecState* exec, const SourceCode& source, JSValue* returnedException)
{
JSLockHolder lock(exec);
- RELEASE_ASSERT(exec->vm().identifierTable == wtfThreadData().currentIdentifierTable());
+ RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
ProgramExecutable* program = ProgramExecutable::create(exec, source);
JSObject* error = program->checkSyntax(exec);
@@ -54,24 +62,40 @@ bool checkSyntax(ExecState* exec, const SourceCode& source, JSValue* returnedExc
bool checkSyntax(VM& vm, const SourceCode& source, ParserError& error)
{
JSLockHolder lock(vm);
- RELEASE_ASSERT(vm.identifierTable == wtfThreadData().currentIdentifierTable());
- RefPtr<ProgramNode> programNode = parse<ProgramNode>(&vm, source, 0, Identifier(), JSParseNormal, JSParseProgramCode, error);
- return programNode;
+ RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable());
+ return !!parse<ProgramNode>(
+ &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
+ JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error);
}
-JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, JSValue* returnedException)
+bool checkModuleSyntax(ExecState* exec, const SourceCode& source, ParserError& error)
+{
+ VM& vm = exec->vm();
+ JSLockHolder lock(vm);
+ RELEASE_ASSERT(vm.atomicStringTable() == wtfThreadData().atomicStringTable());
+ std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>(
+ &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
+ JSParserStrictMode::Strict, SourceParseMode::ModuleAnalyzeMode, SuperBinding::NotNeeded, error);
+ if (!moduleProgramNode)
+ return false;
+
+ PrivateName privateName(PrivateName::Description, "EntryPointModule");
+ ModuleAnalyzer moduleAnalyzer(exec, Identifier::fromUid(privateName), source, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables());
+ moduleAnalyzer.analyze(*moduleProgramNode);
+ return true;
+}
+
+JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, NakedPtr<Exception>& returnedException)
{
JSLockHolder lock(exec);
- RELEASE_ASSERT(exec->vm().identifierTable == wtfThreadData().currentIdentifierTable());
+ RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
RELEASE_ASSERT(!exec->vm().isCollectorBusy());
CodeProfiling profile(source);
ProgramExecutable* program = ProgramExecutable::create(exec, source);
if (!program) {
- if (returnedException)
- *returnedException = exec->vm().exception();
-
+ returnedException = exec->vm().exception();
exec->vm().clearException();
return jsUndefined();
}
@@ -82,9 +106,7 @@ JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, J
JSValue result = exec->interpreter()->execute(program, exec, thisObj);
if (exec->hadException()) {
- if (returnedException)
- *returnedException = exec->exception();
-
+ returnedException = exec->exception();
exec->clearException();
return jsUndefined();
}
@@ -93,4 +115,111 @@ JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, J
return result;
}
+JSValue profiledEvaluate(ExecState* exec, ProfilingReason reason, const SourceCode& source, JSValue thisValue, NakedPtr<Exception>& returnedException)
+{
+ ScriptProfilingScope profilingScope(exec->vmEntryGlobalObject(), reason);
+ return evaluate(exec, source, thisValue, returnedException);
+}
+
+static Symbol* createSymbolForEntryPointModule(VM& vm)
+{
+ // Generate the unique key for the source-provided module.
+ PrivateName privateName(PrivateName::Description, "EntryPointModule");
+ return Symbol::create(vm, *privateName.uid());
+}
+
+static JSInternalPromise* rejectPromise(ExecState* exec, JSGlobalObject* globalObject)
+{
+ ASSERT(exec->hadException());
+ JSValue exception = exec->exception()->value();
+ exec->clearException();
+ JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
+ deferred->reject(exec, exception);
+ return deferred->promise();
+}
+
+static JSInternalPromise* loadAndEvaluateModule(const JSLockHolder&, ExecState* exec, JSGlobalObject* globalObject, JSValue moduleName, JSValue referrer)
+{
+ return globalObject->moduleLoader()->loadAndEvaluateModule(exec, moduleName, referrer);
+}
+
+static JSInternalPromise* loadAndEvaluateModule(const JSLockHolder& lock, ExecState* exec, JSGlobalObject* globalObject, const Identifier& moduleName)
+{
+ return loadAndEvaluateModule(lock, exec, globalObject, identifierToJSValue(exec->vm(), moduleName), jsUndefined());
+}
+
+JSInternalPromise* loadAndEvaluateModule(ExecState* exec, const String& moduleName)
+{
+ JSLockHolder lock(exec);
+ RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
+ RELEASE_ASSERT(!exec->vm().isCollectorBusy());
+
+ return loadAndEvaluateModule(lock, exec, exec->vmEntryGlobalObject(), Identifier::fromString(exec, moduleName));
+}
+
+JSInternalPromise* loadAndEvaluateModule(ExecState* exec, const SourceCode& source)
+{
+ JSLockHolder lock(exec);
+ RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
+ RELEASE_ASSERT(!exec->vm().isCollectorBusy());
+
+ Symbol* key = createSymbolForEntryPointModule(exec->vm());
+
+ JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
+
+ // Insert the given source code to the ModuleLoader registry as the fetched registry entry.
+ globalObject->moduleLoader()->provide(exec, key, ModuleLoaderObject::Status::Fetch, source.view().toString());
+ if (exec->hadException())
+ return rejectPromise(exec, globalObject);
+
+ return loadAndEvaluateModule(lock, exec, globalObject, key, jsUndefined());
+}
+
+static JSInternalPromise* loadModule(const JSLockHolder&, ExecState* exec, JSGlobalObject* globalObject, JSValue moduleName, JSValue referrer)
+{
+ return globalObject->moduleLoader()->loadModule(exec, moduleName, referrer);
+}
+
+static JSInternalPromise* loadModule(const JSLockHolder& lock, ExecState* exec, JSGlobalObject* globalObject, const Identifier& moduleName)
+{
+ return loadModule(lock, exec, globalObject, identifierToJSValue(exec->vm(), moduleName), jsUndefined());
+}
+
+JSInternalPromise* loadModule(ExecState* exec, const String& moduleName)
+{
+ JSLockHolder lock(exec);
+ RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
+ RELEASE_ASSERT(!exec->vm().isCollectorBusy());
+
+ return loadModule(lock, exec, exec->vmEntryGlobalObject(), Identifier::fromString(exec, moduleName));
+}
+
+JSInternalPromise* loadModule(ExecState* exec, const SourceCode& source)
+{
+ JSLockHolder lock(exec);
+ RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
+ RELEASE_ASSERT(!exec->vm().isCollectorBusy());
+
+ Symbol* key = createSymbolForEntryPointModule(exec->vm());
+
+ JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
+
+ // Insert the given source code to the ModuleLoader registry as the fetched registry entry.
+ globalObject->moduleLoader()->provide(exec, key, ModuleLoaderObject::Status::Fetch, source.view().toString());
+ if (exec->hadException())
+ return rejectPromise(exec, globalObject);
+
+ return loadModule(lock, exec, globalObject, key, jsUndefined());
+}
+
+JSInternalPromise* linkAndEvaluateModule(ExecState* exec, const Identifier& moduleKey)
+{
+ JSLockHolder lock(exec);
+ RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
+ RELEASE_ASSERT(!exec->vm().isCollectorBusy());
+
+ JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
+ return globalObject->moduleLoader()->linkAndEvaluateModule(exec, identifierToJSValue(exec->vm(), moduleKey));
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Completion.h b/Source/JavaScriptCore/runtime/Completion.h
index 78f8ac795..53ba195fd 100644
--- a/Source/JavaScriptCore/runtime/Completion.h
+++ b/Source/JavaScriptCore/runtime/Completion.h
@@ -23,19 +23,48 @@
#ifndef Completion_h
#define Completion_h
+#include "CallData.h"
#include "JSCJSValue.h"
+#include <wtf/NakedPtr.h>
namespace JSC {
-
- struct ParserError;
- class ExecState;
- class JSScope;
- class SourceCode;
- class VM;
-
- JS_EXPORT_PRIVATE bool checkSyntax(VM&, const SourceCode&, ParserError&);
- JS_EXPORT_PRIVATE bool checkSyntax(ExecState*, const SourceCode&, JSValue* exception = 0);
- JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, const SourceCode&, JSValue thisValue = JSValue(), JSValue* exception = 0);
+
+class Exception;
+class ExecState;
+class JSScope;
+class ParserError;
+class SourceCode;
+class VM;
+class JSInternalPromise;
+
+JS_EXPORT_PRIVATE bool checkSyntax(VM&, const SourceCode&, ParserError&);
+JS_EXPORT_PRIVATE bool checkSyntax(ExecState*, const SourceCode&, JSValue* exception = 0);
+JS_EXPORT_PRIVATE bool checkModuleSyntax(ExecState*, const SourceCode&, ParserError&);
+
+JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, const SourceCode&, JSValue thisValue, NakedPtr<Exception>& returnedException);
+inline JSValue evaluate(ExecState* exec, const SourceCode& sourceCode, JSValue thisValue = JSValue())
+{
+ NakedPtr<Exception> unused;
+ return evaluate(exec, sourceCode, thisValue, unused);
+}
+
+JS_EXPORT_PRIVATE JSValue profiledEvaluate(ExecState*, ProfilingReason, const SourceCode&, JSValue thisValue, NakedPtr<Exception>& returnedException);
+inline JSValue profiledEvaluate(ExecState* exec, ProfilingReason reason, const SourceCode& sourceCode, JSValue thisValue = JSValue())
+{
+ NakedPtr<Exception> unused;
+ return profiledEvaluate(exec, reason, sourceCode, thisValue, unused);
+}
+
+// Load the module source and evaluate it.
+JS_EXPORT_PRIVATE JSInternalPromise* loadAndEvaluateModule(ExecState*, const String& moduleName);
+JS_EXPORT_PRIVATE JSInternalPromise* loadAndEvaluateModule(ExecState*, const SourceCode&);
+
+// Fetch the module source, and instantiate the module record.
+JS_EXPORT_PRIVATE JSInternalPromise* loadModule(ExecState*, const String& moduleName);
+JS_EXPORT_PRIVATE JSInternalPromise* loadModule(ExecState*, const SourceCode&);
+
+// Link and evaluate the already linked module.
+JS_EXPORT_PRIVATE JSInternalPromise* linkAndEvaluateModule(ExecState*, const Identifier& moduleKey);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ConcurrentJITLock.h b/Source/JavaScriptCore/runtime/ConcurrentJITLock.h
index 84233d035..9a26876fc 100644
--- a/Source/JavaScriptCore/runtime/ConcurrentJITLock.h
+++ b/Source/JavaScriptCore/runtime/ConcurrentJITLock.h
@@ -27,14 +27,14 @@
#define ConcurrentJITLock_h
#include "DeferGC.h"
-#include <wtf/ByteSpinLock.h>
+#include <wtf/Lock.h>
#include <wtf/NoLock.h>
namespace JSC {
#if ENABLE(CONCURRENT_JIT)
-typedef ByteSpinLock ConcurrentJITLock;
-typedef ByteSpinLocker ConcurrentJITLockerImpl;
+typedef Lock ConcurrentJITLock;
+typedef LockHolder ConcurrentJITLockerImpl;
#else
typedef NoLock ConcurrentJITLock;
typedef NoLockLocker ConcurrentJITLockerImpl;
diff --git a/Source/JavaScriptCore/runtime/ConsoleClient.cpp b/Source/JavaScriptCore/runtime/ConsoleClient.cpp
new file mode 100644
index 000000000..059fd335e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ConsoleClient.cpp
@@ -0,0 +1,254 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "ConsoleClient.h"
+
+#include "JSCInlines.h"
+#include "ScriptArguments.h"
+#include "ScriptCallStack.h"
+#include "ScriptCallStackFactory.h"
+#include "ScriptValue.h"
+#include <wtf/Assertions.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/WTFString.h>
+
+using namespace Inspector;
+
+namespace JSC {
+
+static void appendURLAndPosition(StringBuilder& builder, const String& url, unsigned lineNumber, unsigned columnNumber)
+{
+ if (url.isEmpty())
+ return;
+
+ builder.append(url);
+
+ if (lineNumber > 0) {
+ builder.append(':');
+ builder.appendNumber(lineNumber);
+ }
+
+ if (columnNumber > 0) {
+ builder.append(':');
+ builder.appendNumber(columnNumber);
+ }
+}
+
+static void appendMessagePrefix(StringBuilder& builder, MessageSource source, MessageType type, MessageLevel level)
+{
+ const char* sourceString;
+ switch (source) {
+ case MessageSource::XML:
+ sourceString = "XML";
+ break;
+ case MessageSource::JS:
+ sourceString = "JS";
+ break;
+ case MessageSource::Network:
+ sourceString = "NETWORK";
+ break;
+ case MessageSource::ConsoleAPI:
+ sourceString = "CONSOLE";
+ break;
+ case MessageSource::Storage:
+ sourceString = "STORAGE";
+ break;
+ case MessageSource::AppCache:
+ sourceString = "APPCACHE";
+ break;
+ case MessageSource::Rendering:
+ sourceString = "RENDERING";
+ break;
+ case MessageSource::CSS:
+ sourceString = "CSS";
+ break;
+ case MessageSource::Security:
+ sourceString = "SECURITY";
+ break;
+ case MessageSource::Other:
+ sourceString = "OTHER";
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ sourceString = "UNKNOWN";
+ break;
+ }
+
+ const char* levelString;
+ switch (level) {
+ case MessageLevel::Debug:
+ levelString = "DEBUG";
+ break;
+ case MessageLevel::Log:
+ levelString = "LOG";
+ break;
+ case MessageLevel::Info:
+ levelString = "INFO";
+ break;
+ case MessageLevel::Warning:
+ levelString = "WARN";
+ break;
+ case MessageLevel::Error:
+ levelString = "ERROR";
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ levelString = "UNKNOWN";
+ break;
+ }
+
+ if (type == MessageType::Trace)
+ levelString = "TRACE";
+ else if (type == MessageType::Table)
+ levelString = "TABLE";
+
+ builder.append(sourceString);
+ builder.append(' ');
+ builder.append(levelString);
+}
+
+void ConsoleClient::printConsoleMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, const String& url, unsigned lineNumber, unsigned columnNumber)
+{
+ StringBuilder builder;
+
+ if (!url.isEmpty()) {
+ appendURLAndPosition(builder, url, lineNumber, columnNumber);
+ builder.appendLiteral(": ");
+ }
+
+ appendMessagePrefix(builder, source, type, level);
+ builder.append(' ');
+ builder.append(message);
+
+ WTFLogAlways("%s", builder.toString().utf8().data());
+}
+
+void ConsoleClient::printConsoleMessageWithArguments(MessageSource source, MessageType type, MessageLevel level, JSC::ExecState* exec, RefPtr<ScriptArguments>&& arguments)
+{
+ bool isTraceMessage = type == MessageType::Trace;
+ size_t stackSize = isTraceMessage ? ScriptCallStack::maxCallStackSizeToCapture : 1;
+ RefPtr<ScriptCallStack> callStack(createScriptCallStackForConsole(exec, stackSize));
+ const ScriptCallFrame& lastCaller = callStack->at(0);
+
+ StringBuilder builder;
+
+ if (!lastCaller.sourceURL().isEmpty()) {
+ appendURLAndPosition(builder, lastCaller.sourceURL(), lastCaller.lineNumber(), lastCaller.columnNumber());
+ builder.appendLiteral(": ");
+ }
+
+ appendMessagePrefix(builder, source, type, level);
+ for (size_t i = 0; i < arguments->argumentCount(); ++i) {
+ String argAsString = arguments->argumentAt(i).toString(arguments->globalState());
+ builder.append(' ');
+ builder.append(argAsString.utf8().data());
+ }
+
+ WTFLogAlways("%s", builder.toString().utf8().data());
+
+ if (isTraceMessage) {
+ for (size_t i = 0; i < callStack->size(); ++i) {
+ const ScriptCallFrame& callFrame = callStack->at(i);
+ String functionName = String(callFrame.functionName());
+ if (functionName.isEmpty())
+ functionName = ASCIILiteral("(unknown)");
+
+ StringBuilder callFrameBuilder;
+ callFrameBuilder.appendNumber(static_cast<unsigned long>(i));
+ callFrameBuilder.appendLiteral(": ");
+ callFrameBuilder.append(functionName);
+ callFrameBuilder.append('(');
+ appendURLAndPosition(callFrameBuilder, callFrame.sourceURL(), callFrame.lineNumber(), callFrame.columnNumber());
+ callFrameBuilder.append(')');
+
+ WTFLogAlways("%s", callFrameBuilder.toString().utf8().data());
+ }
+ }
+}
+
+void ConsoleClient::internalMessageWithTypeAndLevel(MessageType type, MessageLevel level, JSC::ExecState* exec, RefPtr<ScriptArguments>&& arguments, ArgumentRequirement argumentRequirement)
+{
+ if (argumentRequirement == ArgumentRequired && !arguments->argumentCount())
+ return;
+
+ messageWithTypeAndLevel(type, level, exec, WTFMove(arguments));
+}
+
+void ConsoleClient::logWithLevel(ExecState* exec, RefPtr<ScriptArguments>&& arguments, MessageLevel level)
+{
+ internalMessageWithTypeAndLevel(MessageType::Log, level, exec, WTFMove(arguments), ArgumentRequired);
+}
+
+void ConsoleClient::clear(ExecState* exec, RefPtr<ScriptArguments>&& arguments)
+{
+ internalMessageWithTypeAndLevel(MessageType::Clear, MessageLevel::Log, exec, WTFMove(arguments), ArgumentNotRequired);
+}
+
+void ConsoleClient::dir(ExecState* exec, RefPtr<ScriptArguments>&& arguments)
+{
+ internalMessageWithTypeAndLevel(MessageType::Dir, MessageLevel::Log, exec, WTFMove(arguments), ArgumentRequired);
+}
+
+void ConsoleClient::dirXML(ExecState* exec, RefPtr<ScriptArguments>&& arguments)
+{
+ internalMessageWithTypeAndLevel(MessageType::DirXML, MessageLevel::Log, exec, WTFMove(arguments), ArgumentRequired);
+}
+
+void ConsoleClient::table(ExecState* exec, RefPtr<ScriptArguments>&& arguments)
+{
+ internalMessageWithTypeAndLevel(MessageType::Table, MessageLevel::Log, exec, WTFMove(arguments), ArgumentRequired);
+}
+
+void ConsoleClient::trace(ExecState* exec, RefPtr<ScriptArguments>&& arguments)
+{
+ internalMessageWithTypeAndLevel(MessageType::Trace, MessageLevel::Log, exec, WTFMove(arguments), ArgumentNotRequired);
+}
+
+void ConsoleClient::assertCondition(ExecState* exec, RefPtr<ScriptArguments>&& arguments, bool condition)
+{
+ if (condition)
+ return;
+
+ internalMessageWithTypeAndLevel(MessageType::Assert, MessageLevel::Error, exec, WTFMove(arguments), ArgumentNotRequired);
+}
+
+void ConsoleClient::group(ExecState* exec, RefPtr<ScriptArguments>&& arguments)
+{
+ internalMessageWithTypeAndLevel(MessageType::StartGroup, MessageLevel::Log, exec, WTFMove(arguments), ArgumentNotRequired);
+}
+
+void ConsoleClient::groupCollapsed(ExecState* exec, RefPtr<ScriptArguments>&& arguments)
+{
+ internalMessageWithTypeAndLevel(MessageType::StartGroupCollapsed, MessageLevel::Log, exec, WTFMove(arguments), ArgumentNotRequired);
+}
+
+void ConsoleClient::groupEnd(ExecState* exec, RefPtr<ScriptArguments>&& arguments)
+{
+ internalMessageWithTypeAndLevel(MessageType::EndGroup, MessageLevel::Log, exec, WTFMove(arguments), ArgumentNotRequired);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ConsoleClient.h b/Source/JavaScriptCore/runtime/ConsoleClient.h
new file mode 100644
index 000000000..a16b85bb4
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ConsoleClient.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ConsoleClient_h
+#define ConsoleClient_h
+
+#include "ConsoleTypes.h"
+#include <wtf/Forward.h>
+
+namespace Inspector {
+class ScriptArguments;
+}
+
+namespace JSC {
+
+class ExecState;
+
+class ConsoleClient {
+public:
+ virtual ~ConsoleClient() { }
+
+ JS_EXPORT_PRIVATE static void printConsoleMessage(MessageSource, MessageType, MessageLevel, const String& message, const String& url, unsigned lineNumber, unsigned columnNumber);
+ JS_EXPORT_PRIVATE static void printConsoleMessageWithArguments(MessageSource, MessageType, MessageLevel, JSC::ExecState*, RefPtr<Inspector::ScriptArguments>&&);
+
+ void logWithLevel(ExecState*, RefPtr<Inspector::ScriptArguments>&&, MessageLevel);
+ void clear(ExecState*, RefPtr<Inspector::ScriptArguments>&&);
+ void dir(ExecState*, RefPtr<Inspector::ScriptArguments>&&);
+ void dirXML(ExecState*, RefPtr<Inspector::ScriptArguments>&&);
+ void table(ExecState*, RefPtr<Inspector::ScriptArguments>&&);
+ void trace(ExecState*, RefPtr<Inspector::ScriptArguments>&&);
+ void assertCondition(ExecState*, RefPtr<Inspector::ScriptArguments>&&, bool condition);
+ void group(ExecState*, RefPtr<Inspector::ScriptArguments>&&);
+ void groupCollapsed(ExecState*, RefPtr<Inspector::ScriptArguments>&&);
+ void groupEnd(ExecState*, RefPtr<Inspector::ScriptArguments>&&);
+
+ virtual void messageWithTypeAndLevel(MessageType, MessageLevel, JSC::ExecState*, RefPtr<Inspector::ScriptArguments>&&) = 0;
+ virtual void count(ExecState*, RefPtr<Inspector::ScriptArguments>&&) = 0;
+ virtual void profile(ExecState*, const String& title) = 0;
+ virtual void profileEnd(ExecState*, const String& title) = 0;
+ virtual void time(ExecState*, const String& title) = 0;
+ virtual void timeEnd(ExecState*, const String& title) = 0;
+ virtual void timeStamp(ExecState*, RefPtr<Inspector::ScriptArguments>&&) = 0;
+
+private:
+ enum ArgumentRequirement { ArgumentRequired, ArgumentNotRequired };
+ void internalMessageWithTypeAndLevel(MessageType, MessageLevel, JSC::ExecState*, RefPtr<Inspector::ScriptArguments>&&, ArgumentRequirement);
+};
+
+} // namespace JSC
+
+#endif // ConsoleClient_h
diff --git a/Source/JavaScriptCore/runtime/ConsolePrototype.cpp b/Source/JavaScriptCore/runtime/ConsolePrototype.cpp
new file mode 100644
index 000000000..c8db068df
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ConsolePrototype.cpp
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+#include "ConsolePrototype.h"
+
+#include "ConsoleClient.h"
+#include "Error.h"
+#include "ExceptionHelpers.h"
+#include "JSCInlines.h"
+#include "JSConsole.h"
+#include "ScriptArguments.h"
+#include "ScriptCallStackFactory.h"
+
+namespace JSC {
+
+const ClassInfo ConsolePrototype::s_info = { "ConsolePrototype", &Base::s_info, 0, CREATE_METHOD_TABLE(ConsolePrototype) };
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDebug(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncError(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncLog(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncInfo(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncWarn(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncClear(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDir(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDirXML(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTable(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTrace(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncAssert(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncCount(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfile(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfileEnd(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTime(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTimeEnd(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTimeStamp(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroup(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupCollapsed(ExecState*);
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupEnd(ExecState*);
+
+void ConsolePrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+ vm.prototypeMap.addPrototype(this);
+
+ // For legacy reasons, console properties are enumerable, writable, deleteable,
+ // and all have a length of 0. This may change if Console is standardized.
+
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("debug", consoleProtoFuncDebug, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("error", consoleProtoFuncError, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("log", consoleProtoFuncLog, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("info", consoleProtoFuncInfo, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("warn", consoleProtoFuncWarn, None, 0);
+
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("clear", consoleProtoFuncClear, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("dir", consoleProtoFuncDir, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("dirxml", consoleProtoFuncDirXML, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("table", consoleProtoFuncTable, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("trace", consoleProtoFuncTrace, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("assert", consoleProtoFuncAssert, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("count", consoleProtoFuncCount, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("profile", consoleProtoFuncProfile, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("profileEnd", consoleProtoFuncProfileEnd, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("time", consoleProtoFuncTime, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("timeEnd", consoleProtoFuncTimeEnd, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("timeStamp", consoleProtoFuncTimeStamp, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("group", consoleProtoFuncGroup, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("groupCollapsed", consoleProtoFuncGroupCollapsed, None, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("groupEnd", consoleProtoFuncGroupEnd, None, 0);
+}
+
+static String valueToStringWithUndefinedOrNullCheck(ExecState* exec, JSValue value)
+{
+ if (value.isUndefinedOrNull())
+ return String();
+ return value.toString(exec)->value(exec);
+}
+
+static EncodedJSValue consoleLogWithLevel(ExecState* exec, MessageLevel level)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
+ client->logWithLevel(exec, arguments.release(), level);
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDebug(ExecState* exec)
+{
+ return consoleLogWithLevel(exec, MessageLevel::Debug);
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncError(ExecState* exec)
+{
+ return consoleLogWithLevel(exec, MessageLevel::Error);
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncLog(ExecState* exec)
+{
+ return consoleLogWithLevel(exec, MessageLevel::Log);
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncInfo(ExecState* exec)
+{
+ return consoleLogWithLevel(exec, MessageLevel::Info);
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncWarn(ExecState* exec)
+{
+ return consoleLogWithLevel(exec, MessageLevel::Warning);
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncClear(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
+ client->clear(exec, arguments.release());
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDir(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
+ client->dir(exec, arguments.release());
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDirXML(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
+ client->dirXML(exec, arguments.release());
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTable(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
+ client->table(exec, arguments.release());
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTrace(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
+ client->trace(exec, arguments.release());
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncAssert(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ bool condition(exec->argument(0).toBoolean(exec));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 1));
+ client->assertCondition(exec, arguments.release(), condition);
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncCount(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
+ client->count(exec, arguments.release());
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfile(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ size_t argsCount = exec->argumentCount();
+ if (argsCount <= 0) {
+ client->profile(exec, String());
+ return JSValue::encode(jsUndefined());
+ }
+
+ const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ client->profile(exec, title);
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfileEnd(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ size_t argsCount = exec->argumentCount();
+ if (argsCount <= 0) {
+ client->profileEnd(exec, String());
+ return JSValue::encode(jsUndefined());
+ }
+
+ const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ client->profileEnd(exec, title);
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTime(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ if (exec->argumentCount() < 1)
+ return throwVMError(exec, createNotEnoughArgumentsError(exec));
+
+ const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ client->time(exec, title);
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTimeEnd(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ if (exec->argumentCount() < 1)
+ return throwVMError(exec, createNotEnoughArgumentsError(exec));
+
+ const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ client->timeEnd(exec, title);
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTimeStamp(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
+ client->timeStamp(exec, arguments.release());
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroup(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
+ client->group(exec, arguments.release());
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupCollapsed(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
+ client->groupCollapsed(exec, arguments.release());
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupEnd(ExecState* exec)
+{
+ JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
+ if (!castedThis)
+ return throwVMTypeError(exec);
+ ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
+ ConsoleClient* client = castedThis->globalObject()->consoleClient();
+ if (!client)
+ return JSValue::encode(jsUndefined());
+
+ RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
+ client->groupEnd(exec, arguments.release());
+ return JSValue::encode(jsUndefined());
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/SetIteratorConstructor.h b/Source/JavaScriptCore/runtime/ConsolePrototype.h
index cfd954ee7..a27ad24ad 100644
--- a/Source/JavaScriptCore/runtime/SetIteratorConstructor.h
+++ b/Source/JavaScriptCore/runtime/ConsolePrototype.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple, Inc. All rights reserved.
+ * Copyright (C) 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
@@ -20,44 +20,42 @@
* 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.
*/
-#ifndef SetIteratorConstructor_h
-#define SetIteratorConstructor_h
+#ifndef ConsolePrototype_h
+#define ConsolePrototype_h
#include "JSObject.h"
namespace JSC {
-class SetIteratorPrototype;
-
-class SetIteratorConstructor : public JSNonFinalObject {
+class ConsolePrototype : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
- static SetIteratorConstructor* create(VM& vm, Structure* structure, SetIteratorPrototype* prototype)
+ DECLARE_INFO;
+
+ static ConsolePrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
{
- SetIteratorConstructor* constructor = new (NotNull, allocateCell<SetIteratorConstructor>(vm.heap)) SetIteratorConstructor(vm, structure);
- constructor->finishCreation(vm, prototype);
- return constructor;
+ ConsolePrototype* prototype = new (NotNull, allocateCell<ConsolePrototype>(vm.heap)) ConsolePrototype(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:
- SetIteratorConstructor(VM& vm, Structure* structure)
+ ConsolePrototype(VM& vm, Structure* structure)
: Base(vm, structure)
{
}
- void finishCreation(VM&, SetIteratorPrototype*);
+ void finishCreation(VM&, JSGlobalObject*);
};
}
-#endif // !defined(SetConstructor_h)
+#endif // !defined(ConsolePrototype_h)
diff --git a/Source/JavaScriptCore/runtime/ConsoleTypes.h b/Source/JavaScriptCore/runtime/ConsoleTypes.h
new file mode 100644
index 000000000..c6ecabda9
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ConsoleTypes.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 Google 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.
+ */
+
+#ifndef ConsoleTypes_h
+#define ConsoleTypes_h
+
+namespace JSC {
+
+enum class MessageSource {
+ XML,
+ JS,
+ Network,
+ ConsoleAPI,
+ Storage,
+ AppCache,
+ Rendering,
+ CSS,
+ Security,
+ ContentBlocker,
+ Other,
+};
+
+enum class MessageType {
+ Log,
+ Dir,
+ DirXML,
+ Table,
+ Trace,
+ StartGroup,
+ StartGroupCollapsed,
+ EndGroup,
+ Clear,
+ Assert,
+ Timing,
+ Profile,
+ ProfileEnd,
+};
+
+enum class MessageLevel {
+ Log = 1,
+ Warning = 2,
+ Error = 3,
+ Debug = 4,
+ Info = 5,
+};
+
+} // namespace JSC
+
+using JSC::MessageSource;
+using JSC::MessageType;
+using JSC::MessageLevel;
+
+#endif // ConsoleTypes_h
diff --git a/Source/JavaScriptCore/runtime/ConstantMode.cpp b/Source/JavaScriptCore/runtime/ConstantMode.cpp
new file mode 100644
index 000000000..58ba79475
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ConstantMode.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "ConstantMode.h"
+
+namespace WTF {
+
+using namespace JSC;
+
+void printInternal(PrintStream& out, ConstantMode mode)
+{
+ switch (mode) {
+ case IsConstant:
+ out.print("Constant");
+ return;
+ case IsVariable:
+ out.print("Variable");
+ return;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace WTF
diff --git a/Source/JavaScriptCore/runtime/ConstantMode.h b/Source/JavaScriptCore/runtime/ConstantMode.h
index 389a074f9..a0496278a 100644
--- a/Source/JavaScriptCore/runtime/ConstantMode.h
+++ b/Source/JavaScriptCore/runtime/ConstantMode.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 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
@@ -26,11 +26,24 @@
#ifndef ConstantMode_h
#define ConstantMode_h
+#include <wtf/PrintStream.h>
+
namespace JSC {
enum ConstantMode { IsConstant, IsVariable };
+inline ConstantMode modeForIsConstant(bool isConstant)
+{
+ return isConstant ? IsConstant : IsVariable;
+}
+
} // namespace JSC
+namespace WTF {
+
+void printInternal(PrintStream&, JSC::ConstantMode);
+
+} // namespace WTF
+
#endif // ConstantMode_h
diff --git a/Source/JavaScriptCore/runtime/ConstructAbility.h b/Source/JavaScriptCore/runtime/ConstructAbility.h
new file mode 100644
index 000000000..3af880b60
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ConstructAbility.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#ifndef ConstructAbility_h
+#define ConstructAbility_h
+
+namespace JSC {
+
+enum class ConstructAbility : unsigned {
+ CanConstruct,
+ CannotConstruct,
+};
+
+}
+
+#endif // ConstructAbility_h
diff --git a/Source/JavaScriptCore/runtime/ConstructData.cpp b/Source/JavaScriptCore/runtime/ConstructData.cpp
index 3dc46180c..0a4eecbff 100644
--- a/Source/JavaScriptCore/runtime/ConstructData.cpp
+++ b/Source/JavaScriptCore/runtime/ConstructData.cpp
@@ -28,16 +28,34 @@
#include "Executable.h"
#include "Interpreter.h"
+#include "JSCInlines.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
-#include "Operations.h"
+#include "ScriptProfilingScope.h"
namespace JSC {
-JSObject* construct(ExecState* exec, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
+JSObject* construct(ExecState* exec, JSValue constructorObject, const ArgList& args, const String& errorMessage)
+{
+ ConstructData constructData;
+ ConstructType constructType = getConstructData(constructorObject, constructData);
+ if (constructType == ConstructTypeNone)
+ return throwTypeError(exec, errorMessage);
+
+ return construct(exec, constructorObject, constructType, constructData, args, constructorObject);
+}
+
+
+JSObject* construct(ExecState* exec, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args, JSValue newTarget)
{
ASSERT(constructType == ConstructTypeJS || constructType == ConstructTypeHost);
- return exec->interpreter()->executeConstruct(exec, asObject(constructorObject), constructType, constructData, args);
+ return exec->interpreter()->executeConstruct(exec, asObject(constructorObject), constructType, constructData, args, newTarget);
+}
+
+JSObject* profiledConstruct(ExecState* exec, ProfilingReason reason, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args, JSValue newTarget)
+{
+ ScriptProfilingScope profilingScope(exec->vmEntryGlobalObject(), reason);
+ return construct(exec, constructorObject, constructType, constructData, args, newTarget);
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ConstructData.h b/Source/JavaScriptCore/runtime/ConstructData.h
index 10317a2f9..7e9d55d8f 100644
--- a/Source/JavaScriptCore/runtime/ConstructData.h
+++ b/Source/JavaScriptCore/runtime/ConstructData.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.
*
@@ -34,29 +34,43 @@
namespace JSC {
- class ArgList;
- class ExecState;
- class FunctionExecutable;
- class JSObject;
- class JSScope;
-
- enum ConstructType {
- ConstructTypeNone,
- ConstructTypeHost,
- ConstructTypeJS
- };
-
- union ConstructData {
- struct {
- NativeFunction function;
- } native;
- struct {
- FunctionExecutable* functionExecutable;
- JSScope* scope;
- } js;
- };
-
- JS_EXPORT_PRIVATE JSObject* construct(ExecState*, JSValue constructor, ConstructType, const ConstructData&, const ArgList&);
+class ArgList;
+class ExecState;
+class FunctionExecutable;
+class JSObject;
+class JSScope;
+
+enum ConstructType {
+ ConstructTypeNone,
+ ConstructTypeHost,
+ ConstructTypeJS
+};
+
+union ConstructData {
+ struct {
+ NativeFunction function;
+ } native;
+ struct {
+ FunctionExecutable* functionExecutable;
+ JSScope* scope;
+ } js;
+};
+
+// Convenience wrapper so you don't need to deal with CallData and CallType unless you are going to use them.
+JSObject* construct(ExecState*, JSValue functionObject, const ArgList&, const String& errorMessage);
+JS_EXPORT_PRIVATE JSObject* construct(ExecState*, JSValue constructor, ConstructType, const ConstructData&, const ArgList&, JSValue newTarget);
+
+ALWAYS_INLINE JSObject* construct(ExecState* exec, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
+{
+ return construct(exec, constructorObject, constructType, constructData, args, constructorObject);
+}
+
+JS_EXPORT_PRIVATE JSObject* profiledConstruct(ExecState*, ProfilingReason, JSValue constructor, ConstructType, const ConstructData&, const ArgList&, JSValue newTarget);
+
+ALWAYS_INLINE JSObject* profiledConstruct(ExecState* exec, ProfilingReason reason, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
+{
+ return profiledConstruct(exec, reason, constructorObject, constructType, constructData, args, constructorObject);
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ControlFlowProfiler.cpp b/Source/JavaScriptCore/runtime/ControlFlowProfiler.cpp
new file mode 100644
index 000000000..ebb42992d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ControlFlowProfiler.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 Saam Barati. <saambarati1@gmail.com>
+ *
+ * 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 "ControlFlowProfiler.h"
+
+#include "VM.h"
+
+namespace JSC {
+
+ControlFlowProfiler::ControlFlowProfiler()
+ : m_dummyBasicBlock(BasicBlockLocation(-1, -1))
+{
+}
+
+ControlFlowProfiler::~ControlFlowProfiler()
+{
+ for (const BlockLocationCache& cache : m_sourceIDBuckets.values()) {
+ for (BasicBlockLocation* block : cache.values())
+ delete block;
+ }
+}
+
+BasicBlockLocation* ControlFlowProfiler::getBasicBlockLocation(intptr_t sourceID, int startOffset, int endOffset)
+{
+ auto addResult = m_sourceIDBuckets.add(sourceID, BlockLocationCache());
+ BlockLocationCache& blockLocationCache = addResult.iterator->value;
+ BasicBlockKey key(startOffset, endOffset);
+ auto addResultForBasicBlock = blockLocationCache.add(key, nullptr);
+ if (addResultForBasicBlock.isNewEntry)
+ addResultForBasicBlock.iterator->value = new BasicBlockLocation(startOffset, endOffset);
+ return addResultForBasicBlock.iterator->value;
+}
+
+void ControlFlowProfiler::dumpData() const
+{
+ auto iter = m_sourceIDBuckets.begin();
+ auto end = m_sourceIDBuckets.end();
+ for (; iter != end; ++iter) {
+ dataLog("SourceID: ", iter->key, "\n");
+ for (const BasicBlockLocation* block : iter->value.values())
+ block->dumpData();
+ }
+}
+
+Vector<BasicBlockRange> ControlFlowProfiler::getBasicBlocksForSourceID(intptr_t sourceID, VM& vm) const
+{
+ Vector<BasicBlockRange> result(0);
+ auto bucketFindResult = m_sourceIDBuckets.find(sourceID);
+ if (bucketFindResult == m_sourceIDBuckets.end())
+ return result;
+
+ const BlockLocationCache& cache = bucketFindResult->value;
+ for (const BasicBlockLocation* block : cache.values()) {
+ bool hasExecuted = block->hasExecuted();
+ size_t executionCount = block->executionCount();
+ const Vector<BasicBlockLocation::Gap>& blockRanges = block->getExecutedRanges();
+ for (BasicBlockLocation::Gap gap : blockRanges) {
+ BasicBlockRange range;
+ range.m_hasExecuted = hasExecuted;
+ range.m_executionCount = executionCount;
+ range.m_startOffset = gap.first;
+ range.m_endOffset = gap.second;
+ result.append(range);
+ }
+ }
+
+ const Vector<std::tuple<bool, unsigned, unsigned>>& functionRanges = vm.functionHasExecutedCache()->getFunctionRanges(sourceID);
+ for (const auto& functionRange : functionRanges) {
+ BasicBlockRange range;
+ range.m_hasExecuted = std::get<0>(functionRange);
+ range.m_startOffset = static_cast<int>(std::get<1>(functionRange));
+ range.m_endOffset = static_cast<int>(std::get<2>(functionRange));
+ range.m_executionCount = range.m_hasExecuted ? 1 : 0; // This is a hack. We don't actually count this.
+ result.append(range);
+ }
+
+ return result;
+}
+
+static BasicBlockRange findBasicBlockAtTextOffset(int offset, const Vector<BasicBlockRange>& blocks)
+{
+ int bestDistance = INT_MAX;
+ BasicBlockRange bestRange;
+ bestRange.m_startOffset = bestRange.m_endOffset = -1;
+ bestRange.m_hasExecuted = false; // Suppress MSVC warning.
+ // Because some ranges may overlap because of function boundaries, make sure to find the smallest range enclosing the offset.
+ for (BasicBlockRange range : blocks) {
+ if (range.m_startOffset <= offset && offset <= range.m_endOffset && (range.m_endOffset - range.m_startOffset) < bestDistance) {
+ RELEASE_ASSERT(range.m_endOffset - range.m_startOffset >= 0);
+ bestDistance = range.m_endOffset - range.m_startOffset;
+ bestRange = range;
+ }
+ }
+
+ RELEASE_ASSERT(bestRange.m_startOffset != -1 && bestRange.m_endOffset != -1);
+ return bestRange;
+}
+
+bool ControlFlowProfiler::hasBasicBlockAtTextOffsetBeenExecuted(int offset, intptr_t sourceID, VM& vm)
+{
+ const Vector<BasicBlockRange>& blocks = getBasicBlocksForSourceID(sourceID, vm);
+ BasicBlockRange range = findBasicBlockAtTextOffset(offset, blocks);
+ return range.m_hasExecuted;
+}
+
+size_t ControlFlowProfiler::basicBlockExecutionCountAtTextOffset(int offset, intptr_t sourceID, VM& vm)
+{
+ const Vector<BasicBlockRange>& blocks = getBasicBlocksForSourceID(sourceID, vm);
+ BasicBlockRange range = findBasicBlockAtTextOffset(offset, blocks);
+ return range.m_executionCount;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ControlFlowProfiler.h b/Source/JavaScriptCore/runtime/ControlFlowProfiler.h
new file mode 100644
index 000000000..84a45f9cd
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ControlFlowProfiler.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 Saam Barati. <saambarati1@gmail.com>
+ *
+ * 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 ControlFlowProfiler_h
+#define ControlFlowProfiler_h
+
+#include "BasicBlockLocation.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashMethod.h>
+
+namespace JSC {
+
+class VM;
+
+struct BasicBlockKey {
+ BasicBlockKey()
+ : m_startOffset(-3)
+ , m_endOffset(-3)
+ { }
+
+ BasicBlockKey(int startOffset, int endOffset)
+ : m_startOffset(startOffset)
+ , m_endOffset(endOffset)
+ { }
+
+ BasicBlockKey(WTF::HashTableDeletedValueType)
+ : m_startOffset(-2)
+ , m_endOffset(-2)
+ { }
+
+ bool isHashTableDeletedValue() const { return m_startOffset == -2 && m_endOffset == -2; }
+ bool operator==(const BasicBlockKey& other) const { return m_startOffset == other.m_startOffset && m_endOffset == other.m_endOffset; }
+ unsigned hash() const { return m_startOffset + m_endOffset + 1; }
+
+ int m_startOffset;
+ int m_endOffset;
+};
+
+struct BasicBlockKeyHash {
+ static unsigned hash(const BasicBlockKey& key) { return key.hash(); }
+ static bool equal(const BasicBlockKey& a, const BasicBlockKey& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+} // namespace JSC
+
+namespace WTF {
+
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::BasicBlockKey> {
+ typedef JSC::BasicBlockKeyHash Hash;
+};
+
+template<typename T> struct HashTraits;
+template<> struct HashTraits<JSC::BasicBlockKey> : SimpleClassHashTraits<JSC::BasicBlockKey> {
+ static const bool emptyValueIsZero = false;
+};
+
+} // namespace WTF
+
+namespace JSC {
+
+struct BasicBlockRange {
+ int m_startOffset;
+ int m_endOffset;
+ bool m_hasExecuted;
+ size_t m_executionCount;
+};
+
+class ControlFlowProfiler {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ ControlFlowProfiler();
+ ~ControlFlowProfiler();
+ BasicBlockLocation* getBasicBlockLocation(intptr_t sourceID, int startOffset, int endOffset);
+ JS_EXPORT_PRIVATE void dumpData() const;
+ Vector<BasicBlockRange> getBasicBlocksForSourceID(intptr_t sourceID, VM&) const;
+ BasicBlockLocation* dummyBasicBlock() { return &m_dummyBasicBlock; }
+ JS_EXPORT_PRIVATE bool hasBasicBlockAtTextOffsetBeenExecuted(int, intptr_t, VM&); // This function exists for testing.
+ JS_EXPORT_PRIVATE size_t basicBlockExecutionCountAtTextOffset(int, intptr_t, VM&); // This function exists for testing.
+
+private:
+ typedef HashMap<BasicBlockKey, BasicBlockLocation*> BlockLocationCache;
+ typedef HashMap<intptr_t, BlockLocationCache> SourceIDBuckets;
+
+ SourceIDBuckets m_sourceIDBuckets;
+ BasicBlockLocation m_dummyBasicBlock;
+};
+
+} // namespace JSC
+
+#endif // ControlFlowProfiler_h
diff --git a/Source/JavaScriptCore/runtime/CustomGetterSetter.cpp b/Source/JavaScriptCore/runtime/CustomGetterSetter.cpp
new file mode 100644
index 000000000..5ce3a3692
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/CustomGetterSetter.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 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. 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 "CustomGetterSetter.h"
+
+#include "JSCJSValueInlines.h"
+#include "JSObject.h"
+#include "SlotVisitorInlines.h"
+#include <wtf/Assertions.h>
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(CustomGetterSetter);
+
+const ClassInfo CustomGetterSetter::s_info = { "CustomGetterSetter", 0, 0, CREATE_METHOD_TABLE(CustomGetterSetter) };
+
+void callCustomSetter(ExecState* exec, JSValue customGetterSetter, bool isAccessor, JSObject* base, JSValue thisValue, JSValue value)
+{
+ CustomGetterSetter::CustomSetter setter = jsCast<CustomGetterSetter*>(customGetterSetter)->setter();
+ if (!setter)
+ return;
+ if (!isAccessor)
+ thisValue = base;
+ setter(exec, JSValue::encode(thisValue), JSValue::encode(value));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CustomGetterSetter.h b/Source/JavaScriptCore/runtime/CustomGetterSetter.h
new file mode 100644
index 000000000..dddd8c6fb
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/CustomGetterSetter.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 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. 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.
+ */
+
+#ifndef CustomGetterSetter_h
+#define CustomGetterSetter_h
+
+#include "JSCell.h"
+#include "PropertySlot.h"
+#include "PutPropertySlot.h"
+#include "Structure.h"
+
+namespace JSC {
+
+class CustomGetterSetter final : public JSCell {
+public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+ typedef PropertySlot::GetValueFunc CustomGetter;
+ typedef PutPropertySlot::PutValueFunc CustomSetter;
+
+ static CustomGetterSetter* create(VM& vm, CustomGetter customGetter, CustomSetter customSetter)
+ {
+ CustomGetterSetter* customGetterSetter = new (NotNull, allocateCell<CustomGetterSetter>(vm.heap)) CustomGetterSetter(vm, customGetter, customSetter);
+ customGetterSetter->finishCreation(vm);
+ return customGetterSetter;
+ }
+
+ CustomGetterSetter::CustomGetter getter() const { return m_getter; }
+ CustomGetterSetter::CustomSetter setter() const { return m_setter; }
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CustomGetterSetterType, StructureFlags), info());
+ }
+
+ DECLARE_EXPORT_INFO;
+
+private:
+ CustomGetterSetter(VM& vm, CustomGetter getter, CustomSetter setter)
+ : JSCell(vm, vm.customGetterSetterStructure.get())
+ , m_getter(getter)
+ , m_setter(setter)
+ {
+ }
+
+ CustomGetter m_getter;
+ CustomSetter m_setter;
+};
+
+JS_EXPORT_PRIVATE void callCustomSetter(ExecState*, JSValue customGetterSetter, bool isAccessor, JSObject* slotBase, JSValue thisValue, JSValue);
+
+} // namespace JSC
+
+#endif // CustomGetterSetter_h
diff --git a/Source/JavaScriptCore/runtime/DataView.cpp b/Source/JavaScriptCore/runtime/DataView.cpp
index 0c83d6e95..78e743fc1 100644
--- a/Source/JavaScriptCore/runtime/DataView.cpp
+++ b/Source/JavaScriptCore/runtime/DataView.cpp
@@ -37,13 +37,13 @@ DataView::DataView(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned
{
}
-PassRefPtr<DataView> DataView::create(
+Ref<DataView> DataView::create(
PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned byteLength)
{
- return adoptRef(new DataView(buffer, byteOffset, byteLength));
+ return adoptRef(*new DataView(buffer, byteOffset, byteLength));
}
-PassRefPtr<DataView> DataView::create(PassRefPtr<ArrayBuffer> passedBuffer)
+Ref<DataView> DataView::create(PassRefPtr<ArrayBuffer> passedBuffer)
{
RefPtr<ArrayBuffer> buffer = passedBuffer;
return create(buffer, 0, buffer->byteLength());
diff --git a/Source/JavaScriptCore/runtime/DataView.h b/Source/JavaScriptCore/runtime/DataView.h
index 4a8aa9258..a01d13506 100644
--- a/Source/JavaScriptCore/runtime/DataView.h
+++ b/Source/JavaScriptCore/runtime/DataView.h
@@ -37,8 +37,8 @@ protected:
DataView(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned byteLength);
public:
- JS_EXPORT_PRIVATE static PassRefPtr<DataView> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length);
- static PassRefPtr<DataView> create(PassRefPtr<ArrayBuffer>);
+ JS_EXPORT_PRIVATE static Ref<DataView> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length);
+ static Ref<DataView> create(PassRefPtr<ArrayBuffer>);
virtual unsigned byteLength() const override
{
diff --git a/Source/JavaScriptCore/runtime/DateConstructor.cpp b/Source/JavaScriptCore/runtime/DateConstructor.cpp
index 7cbea6407..4fcc8a34e 100644
--- a/Source/JavaScriptCore/runtime/DateConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/DateConstructor.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 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
@@ -29,15 +29,15 @@
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "JSString.h"
-#include "JSStringBuilder.h"
#include "ObjectPrototype.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include <math.h>
#include <time.h>
#include <wtf/MathExtras.h>
-#if OS(WINCE)
-extern "C" time_t time(time_t* timer); // Provided by libce.
+#if ENABLE(WEB_REPLAY)
+#include "InputCursor.h"
+#include "JSReplayInputs.h"
#endif
#if HAVE(SYS_TIME_H)
@@ -52,9 +52,8 @@ using namespace WTF;
namespace JSC {
-static EncodedJSValue JSC_HOST_CALL dateParse(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateNow(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateUTC(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateParse(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateUTC(ExecState*);
}
@@ -62,7 +61,7 @@ static EncodedJSValue JSC_HOST_CALL dateUTC(ExecState*);
namespace JSC {
-const ClassInfo DateConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::dateConstructorTable, CREATE_METHOD_TABLE(DateConstructor) };
+const ClassInfo DateConstructor::s_info = { "Function", &InternalFunction::s_info, &dateConstructorTable, CREATE_METHOD_TABLE(DateConstructor) };
/* Source for DateConstructor.lut.h
@begin dateConstructorTable
@@ -72,6 +71,28 @@ const ClassInfo DateConstructor::s_info = { "Function", &InternalFunction::s_inf
@end
*/
+#if ENABLE(WEB_REPLAY)
+static double deterministicCurrentTime(JSGlobalObject* globalObject)
+{
+ double currentTime = jsCurrentTime();
+ InputCursor& cursor = globalObject->inputCursor();
+ if (cursor.isCapturing())
+ cursor.appendInput<GetCurrentTime>(currentTime);
+
+ if (cursor.isReplaying()) {
+ if (GetCurrentTime* input = cursor.fetchInput<GetCurrentTime>())
+ currentTime = input->currentTime();
+ }
+ return currentTime;
+}
+#endif
+
+#if ENABLE(WEB_REPLAY)
+#define NORMAL_OR_DETERMINISTIC_FUNCTION(a, b) (b)
+#else
+#define NORMAL_OR_DETERMINISTIC_FUNCTION(a, b) (a)
+#endif
+
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DateConstructor);
DateConstructor::DateConstructor(VM& vm, Structure* structure)
@@ -81,18 +102,54 @@ DateConstructor::DateConstructor(VM& vm, Structure* structure)
void DateConstructor::finishCreation(VM& vm, DatePrototype* datePrototype)
{
- Base::finishCreation(vm, datePrototype->classInfo()->className);
+ Base::finishCreation(vm, "Date");
putDirectWithoutTransition(vm, vm.propertyNames->prototype, datePrototype, DontEnum | DontDelete | ReadOnly);
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(7), ReadOnly | DontEnum | DontDelete);
}
bool DateConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
{
- return getStaticFunctionSlot<InternalFunction>(exec, ExecState::dateConstructorTable(exec->vm()), jsCast<DateConstructor*>(object), propertyName, slot);
+ return getStaticFunctionSlot<InternalFunction>(exec, dateConstructorTable, jsCast<DateConstructor*>(object), propertyName, slot);
+}
+
+static double millisecondsFromComponents(ExecState* exec, const ArgList& args, WTF::TimeType timeType)
+{
+ double doubleArguments[] = {
+ args.at(0).toNumber(exec),
+ args.at(1).toNumber(exec),
+ args.at(2).toNumber(exec),
+ args.at(3).toNumber(exec),
+ args.at(4).toNumber(exec),
+ args.at(5).toNumber(exec),
+ args.at(6).toNumber(exec)
+ };
+
+ int numArgs = args.size();
+
+ if ((!std::isfinite(doubleArguments[0]) || (doubleArguments[0] > INT_MAX) || (doubleArguments[0] < INT_MIN))
+ || (!std::isfinite(doubleArguments[1]) || (doubleArguments[1] > INT_MAX) || (doubleArguments[1] < INT_MIN))
+ || (numArgs >= 3 && (!std::isfinite(doubleArguments[2]) || (doubleArguments[2] > INT_MAX) || (doubleArguments[2] < INT_MIN)))
+ || (numArgs >= 4 && (!std::isfinite(doubleArguments[3]) || (doubleArguments[3] > INT_MAX) || (doubleArguments[3] < INT_MIN)))
+ || (numArgs >= 5 && (!std::isfinite(doubleArguments[4]) || (doubleArguments[4] > INT_MAX) || (doubleArguments[4] < INT_MIN)))
+ || (numArgs >= 6 && (!std::isfinite(doubleArguments[5]) || (doubleArguments[5] > INT_MAX) || (doubleArguments[5] < INT_MIN)))
+ || (numArgs >= 7 && (!std::isfinite(doubleArguments[6]) || (doubleArguments[6] > INT_MAX) || (doubleArguments[6] < INT_MIN))))
+ return PNaN;
+
+ GregorianDateTime t;
+ int year = JSC::toInt32(doubleArguments[0]);
+ t.setYear((year >= 0 && year <= 99) ? (year + 1900) : year);
+ t.setMonth(JSC::toInt32(doubleArguments[1]));
+ t.setMonthDay((numArgs >= 3) ? JSC::toInt32(doubleArguments[2]) : 1);
+ t.setHour(JSC::toInt32(doubleArguments[3]));
+ t.setMinute(JSC::toInt32(doubleArguments[4]));
+ t.setSecond(JSC::toInt32(doubleArguments[5]));
+ t.setIsDST(-1);
+ double ms = (numArgs >= 7) ? doubleArguments[6] : 0;
+ return gregorianDateTimeToMS(exec->vm(), t, ms, timeType);
}
// ECMA 15.9.3
-JSObject* constructDate(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args)
+JSObject* constructDate(ExecState* exec, JSGlobalObject* globalObject, JSValue newTarget, const ArgList& args)
{
VM& vm = exec->vm();
int numArgs = args.size();
@@ -100,7 +157,7 @@ JSObject* constructDate(ExecState* exec, JSGlobalObject* globalObject, const Arg
double value;
if (numArgs == 0) // new Date() ECMA 15.9.3.3
- value = jsCurrentTime();
+ value = NORMAL_OR_DETERMINISTIC_FUNCTION(jsCurrentTime(), deterministicCurrentTime(globalObject));
else if (numArgs == 1) {
if (args.at(0).inherits(DateInstance::info()))
value = asDateInstance(args.at(0))->internalNumber();
@@ -111,46 +168,18 @@ JSObject* constructDate(ExecState* exec, JSGlobalObject* globalObject, const Arg
else
value = primitive.toNumber(exec);
}
- } else {
- double doubleArguments[7] = {
- args.at(0).toNumber(exec),
- args.at(1).toNumber(exec),
- args.at(2).toNumber(exec),
- args.at(3).toNumber(exec),
- args.at(4).toNumber(exec),
- args.at(5).toNumber(exec),
- args.at(6).toNumber(exec)
- };
- if (!std::isfinite(doubleArguments[0])
- || !std::isfinite(doubleArguments[1])
- || (numArgs >= 3 && !std::isfinite(doubleArguments[2]))
- || (numArgs >= 4 && !std::isfinite(doubleArguments[3]))
- || (numArgs >= 5 && !std::isfinite(doubleArguments[4]))
- || (numArgs >= 6 && !std::isfinite(doubleArguments[5]))
- || (numArgs >= 7 && !std::isfinite(doubleArguments[6])))
- value = QNaN;
- else {
- GregorianDateTime t;
- int year = JSC::toInt32(doubleArguments[0]);
- t.setYear((year >= 0 && year <= 99) ? (year + 1900) : year);
- t.setMonth(JSC::toInt32(doubleArguments[1]));
- t.setMonthDay((numArgs >= 3) ? JSC::toInt32(doubleArguments[2]) : 1);
- t.setHour(JSC::toInt32(doubleArguments[3]));
- t.setMinute(JSC::toInt32(doubleArguments[4]));
- t.setSecond(JSC::toInt32(doubleArguments[5]));
- t.setIsDST(-1);
- double ms = (numArgs >= 7) ? doubleArguments[6] : 0;
- value = gregorianDateTimeToMS(vm, t, ms, WTF::LocalTime);
- }
- }
+ } else
+ value = millisecondsFromComponents(exec, args, WTF::LocalTime);
+
+ Structure* dateStructure = InternalFunction::createSubclassStructure(exec, newTarget, globalObject->dateStructure());
- return DateInstance::create(vm, globalObject->dateStructure(), value);
+ return DateInstance::create(vm, dateStructure, value);
}
static EncodedJSValue JSC_HOST_CALL constructWithDateConstructor(ExecState* exec)
{
ArgList args(exec);
- return JSValue::encode(constructDate(exec, asInternalFunction(exec->callee())->globalObject(), args));
+ return JSValue::encode(constructDate(exec, asInternalFunction(exec->callee())->globalObject(), exec->newTarget(), args));
}
ConstructType DateConstructor::getConstructData(JSCell*, ConstructData& constructData)
@@ -174,47 +203,27 @@ CallType DateConstructor::getCallData(JSCell*, CallData& callData)
return CallTypeHost;
}
-static EncodedJSValue JSC_HOST_CALL dateParse(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dateParse(ExecState* exec)
{
- return JSValue::encode(jsNumber(parseDate(exec->vm(), exec->argument(0).toString(exec)->value(exec))));
+ String dateStr = exec->argument(0).toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(jsNumber(parseDate(exec->vm(), dateStr)));
}
-static EncodedJSValue JSC_HOST_CALL dateNow(ExecState*)
+EncodedJSValue JSC_HOST_CALL dateNow(ExecState* exec)
{
- return JSValue::encode(jsNumber(jsCurrentTime()));
+#if !ENABLE(WEB_REPLAY)
+ UNUSED_PARAM(exec);
+#endif
+
+ return JSValue::encode(jsNumber(NORMAL_OR_DETERMINISTIC_FUNCTION(jsCurrentTime(), deterministicCurrentTime(exec->lexicalGlobalObject()))));
}
-static EncodedJSValue JSC_HOST_CALL dateUTC(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dateUTC(ExecState* exec)
{
- double doubleArguments[7] = {
- exec->argument(0).toNumber(exec),
- exec->argument(1).toNumber(exec),
- exec->argument(2).toNumber(exec),
- exec->argument(3).toNumber(exec),
- exec->argument(4).toNumber(exec),
- exec->argument(5).toNumber(exec),
- exec->argument(6).toNumber(exec)
- };
- int n = exec->argumentCount();
- if (std::isnan(doubleArguments[0])
- || std::isnan(doubleArguments[1])
- || (n >= 3 && std::isnan(doubleArguments[2]))
- || (n >= 4 && std::isnan(doubleArguments[3]))
- || (n >= 5 && std::isnan(doubleArguments[4]))
- || (n >= 6 && std::isnan(doubleArguments[5]))
- || (n >= 7 && std::isnan(doubleArguments[6])))
- return JSValue::encode(jsNaN());
-
- GregorianDateTime t;
- int year = JSC::toInt32(doubleArguments[0]);
- t.setYear((year >= 0 && year <= 99) ? (year + 1900) : year);
- t.setMonth(JSC::toInt32(doubleArguments[1]));
- t.setMonthDay((n >= 3) ? JSC::toInt32(doubleArguments[2]) : 1);
- t.setHour(JSC::toInt32(doubleArguments[3]));
- t.setMinute(JSC::toInt32(doubleArguments[4]));
- t.setSecond(JSC::toInt32(doubleArguments[5]));
- double ms = (n >= 7) ? doubleArguments[6] : 0;
- return JSValue::encode(jsNumber(timeClip(gregorianDateTimeToMS(exec->vm(), t, ms, WTF::UTCTime))));
+ double ms = millisecondsFromComponents(exec, ArgList(exec), WTF::UTCTime);
+ return JSValue::encode(jsNumber(timeClip(ms)));
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/DateConstructor.h b/Source/JavaScriptCore/runtime/DateConstructor.h
index 383e6f1b3..4843a6967 100644
--- a/Source/JavaScriptCore/runtime/DateConstructor.h
+++ b/Source/JavaScriptCore/runtime/DateConstructor.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -25,39 +25,42 @@
namespace JSC {
- class DatePrototype;
+class DatePrototype;
+class GetterSetter;
- class DateConstructor : public InternalFunction {
- public:
- typedef InternalFunction Base;
+class DateConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
- static DateConstructor* create(VM& vm, Structure* structure, DatePrototype* datePrototype)
- {
- DateConstructor* constructor = new (NotNull, allocateCell<DateConstructor>(vm.heap)) DateConstructor(vm, structure);
- constructor->finishCreation(vm, datePrototype);
- return constructor;
- }
+ static DateConstructor* create(VM& vm, Structure* structure, DatePrototype* datePrototype, GetterSetter*)
+ {
+ DateConstructor* constructor = new (NotNull, allocateCell<DateConstructor>(vm.heap)) DateConstructor(vm, structure);
+ constructor->finishCreation(vm, datePrototype);
+ return constructor;
+ }
- DECLARE_INFO;
+ DECLARE_INFO;
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
- protected:
- void finishCreation(VM&, DatePrototype*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
+protected:
+ void finishCreation(VM&, DatePrototype*);
- private:
- DateConstructor(VM&, Structure*);
- static ConstructType getConstructData(JSCell*, ConstructData&);
- static CallType getCallData(JSCell*, CallData&);
+private:
+ DateConstructor(VM&, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- };
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+};
- JSObject* constructDate(ExecState*, JSGlobalObject*, const ArgList&);
+JSObject* constructDate(ExecState*, JSGlobalObject*, JSValue newTarget, const ArgList&);
+
+EncodedJSValue JSC_HOST_CALL dateNow(ExecState*);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/DateConversion.h b/Source/JavaScriptCore/runtime/DateConversion.h
index 8ea4c17ad..80a29c823 100644
--- a/Source/JavaScriptCore/runtime/DateConversion.h
+++ b/Source/JavaScriptCore/runtime/DateConversion.h
@@ -39,7 +39,7 @@ enum DateTimeFormat {
DateTimeFormatDateAndTime = DateTimeFormatDate | DateTimeFormatTime
};
-WTF::String formatDateTime(const GregorianDateTime&, DateTimeFormat, bool asUTCVariant);
+JS_EXPORT_PRIVATE WTF::String formatDateTime(const GregorianDateTime&, DateTimeFormat, bool asUTCVariant);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/DateInstance.cpp b/Source/JavaScriptCore/runtime/DateInstance.cpp
index bdb0f0c2d..e095f882c 100644
--- a/Source/JavaScriptCore/runtime/DateInstance.cpp
+++ b/Source/JavaScriptCore/runtime/DateInstance.cpp
@@ -24,7 +24,7 @@
#include "JSDateMath.h"
#include "JSGlobalObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include <math.h>
#include <wtf/MathExtras.h>
@@ -32,7 +32,7 @@ using namespace WTF;
namespace JSC {
-const ClassInfo DateInstance::s_info = {"Date", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(DateInstance)};
+const ClassInfo DateInstance::s_info = {"Date", &JSWrapperObject::s_info, 0, CREATE_METHOD_TABLE(DateInstance)};
DateInstance::DateInstance(VM& vm, Structure* structure)
: JSWrapperObject(vm, structure)
diff --git a/Source/JavaScriptCore/runtime/DateInstance.h b/Source/JavaScriptCore/runtime/DateInstance.h
index 193e05421..000e1a157 100644
--- a/Source/JavaScriptCore/runtime/DateInstance.h
+++ b/Source/JavaScriptCore/runtime/DateInstance.h
@@ -25,69 +25,69 @@
namespace JSC {
- class DateInstance : public JSWrapperObject {
- protected:
- JS_EXPORT_PRIVATE DateInstance(VM&, Structure*);
- void finishCreation(VM&);
- JS_EXPORT_PRIVATE void finishCreation(VM&, double);
-
- static void destroy(JSCell*);
-
- public:
- typedef JSWrapperObject Base;
-
- static DateInstance* create(VM& vm, Structure* structure, double date)
- {
- DateInstance* instance = new (NotNull, allocateCell<DateInstance>(vm.heap)) DateInstance(vm, structure);
- instance->finishCreation(vm, date);
- return instance;
- }
-
- static DateInstance* create(VM& vm, Structure* structure)
- {
- DateInstance* instance = new (NotNull, allocateCell<DateInstance>(vm.heap)) DateInstance(vm, structure);
- instance->finishCreation(vm);
- return instance;
- }
-
- double internalNumber() const { return internalValue().asNumber(); }
-
- DECLARE_EXPORT_INFO;
-
- const GregorianDateTime* gregorianDateTime(ExecState* exec) const
- {
- if (m_data && m_data->m_gregorianDateTimeCachedForMS == internalNumber())
- return &m_data->m_cachedGregorianDateTime;
- return calculateGregorianDateTime(exec);
- }
-
- const GregorianDateTime* gregorianDateTimeUTC(ExecState* exec) const
- {
- if (m_data && m_data->m_gregorianDateTimeUTCCachedForMS == internalNumber())
- return &m_data->m_cachedGregorianDateTimeUTC;
- return calculateGregorianDateTimeUTC(exec);
- }
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
-
- private:
- const GregorianDateTime* calculateGregorianDateTime(ExecState*) const;
- const GregorianDateTime* calculateGregorianDateTimeUTC(ExecState*) const;
-
- mutable RefPtr<DateInstanceData> m_data;
- };
-
- DateInstance* asDateInstance(JSValue);
-
- inline DateInstance* asDateInstance(JSValue value)
+class DateInstance : public JSWrapperObject {
+protected:
+ JS_EXPORT_PRIVATE DateInstance(VM&, Structure*);
+ void finishCreation(VM&);
+ JS_EXPORT_PRIVATE void finishCreation(VM&, double);
+
+ JS_EXPORT_PRIVATE static void destroy(JSCell*);
+
+public:
+ typedef JSWrapperObject Base;
+
+ static DateInstance* create(VM& vm, Structure* structure, double date)
+ {
+ DateInstance* instance = new (NotNull, allocateCell<DateInstance>(vm.heap)) DateInstance(vm, structure);
+ instance->finishCreation(vm, date);
+ return instance;
+ }
+
+ static DateInstance* create(VM& vm, Structure* structure)
+ {
+ DateInstance* instance = new (NotNull, allocateCell<DateInstance>(vm.heap)) DateInstance(vm, structure);
+ instance->finishCreation(vm);
+ return instance;
+ }
+
+ double internalNumber() const { return internalValue().asNumber(); }
+
+ DECLARE_EXPORT_INFO;
+
+ const GregorianDateTime* gregorianDateTime(ExecState* exec) const
{
- ASSERT(asObject(value)->inherits(DateInstance::info()));
- return static_cast<DateInstance*>(asObject(value));
+ if (m_data && m_data->m_gregorianDateTimeCachedForMS == internalNumber())
+ return &m_data->m_cachedGregorianDateTime;
+ return calculateGregorianDateTime(exec);
}
+ const GregorianDateTime* gregorianDateTimeUTC(ExecState* exec) const
+ {
+ if (m_data && m_data->m_gregorianDateTimeUTCCachedForMS == internalNumber())
+ return &m_data->m_cachedGregorianDateTimeUTC;
+ return calculateGregorianDateTimeUTC(exec);
+ }
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+private:
+ JS_EXPORT_PRIVATE const GregorianDateTime* calculateGregorianDateTime(ExecState*) const;
+ JS_EXPORT_PRIVATE const GregorianDateTime* calculateGregorianDateTimeUTC(ExecState*) const;
+
+ mutable RefPtr<DateInstanceData> m_data;
+};
+
+DateInstance* asDateInstance(JSValue);
+
+inline DateInstance* asDateInstance(JSValue value)
+{
+ ASSERT(asObject(value)->inherits(DateInstance::info()));
+ return static_cast<DateInstance*>(asObject(value));
+}
+
} // namespace JSC
#endif // DateInstance_h
diff --git a/Source/JavaScriptCore/runtime/DateInstanceCache.h b/Source/JavaScriptCore/runtime/DateInstanceCache.h
index 1c8c011ec..865ee8ff2 100644
--- a/Source/JavaScriptCore/runtime/DateInstanceCache.h
+++ b/Source/JavaScriptCore/runtime/DateInstanceCache.h
@@ -30,65 +30,64 @@
#include "JSDateMath.h"
#include <array>
#include <wtf/HashFunctions.h>
-#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
namespace JSC {
- class DateInstanceData : public RefCounted<DateInstanceData> {
- public:
- static PassRefPtr<DateInstanceData> create() { return adoptRef(new DateInstanceData); }
-
- double m_gregorianDateTimeCachedForMS;
- GregorianDateTime m_cachedGregorianDateTime;
- double m_gregorianDateTimeUTCCachedForMS;
- GregorianDateTime m_cachedGregorianDateTimeUTC;
-
- private:
- DateInstanceData()
- : m_gregorianDateTimeCachedForMS(QNaN)
- , m_gregorianDateTimeUTCCachedForMS(QNaN)
- {
- }
- };
+class DateInstanceData : public RefCounted<DateInstanceData> {
+public:
+ static Ref<DateInstanceData> create() { return adoptRef(*new DateInstanceData); }
- class DateInstanceCache {
- public:
- DateInstanceCache()
- {
- reset();
- }
-
- void reset()
- {
- for (size_t i = 0; i < cacheSize; ++i)
- m_cache[i].key = QNaN;
- }
-
- DateInstanceData* add(double d)
- {
- CacheEntry& entry = lookup(d);
- if (d == entry.key)
- return entry.value.get();
-
- entry.key = d;
- entry.value = DateInstanceData::create();
- return entry.value.get();
- }
+ double m_gregorianDateTimeCachedForMS;
+ GregorianDateTime m_cachedGregorianDateTime;
+ double m_gregorianDateTimeUTCCachedForMS;
+ GregorianDateTime m_cachedGregorianDateTimeUTC;
+
+private:
+ DateInstanceData()
+ : m_gregorianDateTimeCachedForMS(PNaN)
+ , m_gregorianDateTimeUTCCachedForMS(PNaN)
+ {
+ }
+};
+
+class DateInstanceCache {
+public:
+ DateInstanceCache()
+ {
+ reset();
+ }
- private:
- static const size_t cacheSize = 16;
+ void reset()
+ {
+ for (size_t i = 0; i < cacheSize; ++i)
+ m_cache[i].key = PNaN;
+ }
- struct CacheEntry {
- double key;
- RefPtr<DateInstanceData> value;
- };
+ DateInstanceData* add(double d)
+ {
+ CacheEntry& entry = lookup(d);
+ if (d == entry.key)
+ return entry.value.get();
+
+ entry.key = d;
+ entry.value = DateInstanceData::create();
+ return entry.value.get();
+ }
- CacheEntry& lookup(double d) { return m_cache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; }
+private:
+ static const size_t cacheSize = 16;
- std::array<CacheEntry, cacheSize> m_cache;
+ struct CacheEntry {
+ double key;
+ RefPtr<DateInstanceData> value;
};
+ CacheEntry& lookup(double d) { return m_cache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; }
+
+ std::array<CacheEntry, cacheSize> m_cache;
+};
+
} // namespace JSC
#endif // DateInstanceCache_h
diff --git a/Source/JavaScriptCore/runtime/DatePrototype.cpp b/Source/JavaScriptCore/runtime/DatePrototype.cpp
index b0675451a..b32cca4e3 100644
--- a/Source/JavaScriptCore/runtime/DatePrototype.cpp
+++ b/Source/JavaScriptCore/runtime/DatePrototype.cpp
@@ -27,13 +27,14 @@
#include "DateConversion.h"
#include "DateInstance.h"
#include "Error.h"
+#include "JSCBuiltins.h"
#include "JSDateMath.h"
#include "JSGlobalObject.h"
+#include "JSObject.h"
#include "JSString.h"
-#include "JSStringBuilder.h"
#include "Lookup.h"
#include "ObjectPrototype.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include <limits.h>
#include <locale.h>
#include <math.h>
@@ -71,51 +72,50 @@ using namespace WTF;
namespace JSC {
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
}
@@ -320,7 +320,7 @@ static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, doubl
static EncodedJSValue formateDateInstance(ExecState* exec, DateTimeFormat format, bool asUTCVariant)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -426,7 +426,7 @@ static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms
return ok;
}
-const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable, CREATE_METHOD_TABLE(DatePrototype)};
+const ClassInfo DatePrototype::s_info = {"Object", &JSNonFinalObject::s_info, &dateTable, CREATE_METHOD_TABLE(DatePrototype)};
/* Source for DatePrototype.lut.h
@begin dateTable
@@ -482,21 +482,29 @@ const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecS
// ECMA 15.9.4
DatePrototype::DatePrototype(VM& vm, Structure* structure)
- : DateInstance(vm, structure)
+ : Base(vm, structure)
{
}
-void DatePrototype::finishCreation(VM& vm, JSGlobalObject*)
+void DatePrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
{
Base::finishCreation(vm);
ASSERT(inherits(info()));
+#if ENABLE(INTL)
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toLocaleString", datePrototypeToLocaleStringCodeGenerator, DontEnum);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toLocaleDateString", datePrototypeToLocaleDateStringCodeGenerator, DontEnum);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toLocaleTimeString", datePrototypeToLocaleTimeStringCodeGenerator, DontEnum);
+#else
+ UNUSED_PARAM(globalObject);
+#endif // ENABLE(INTL)
+
// The constructor will be added later, after DateConstructor has been built.
}
bool DatePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
- return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec->vm()), jsCast<DatePrototype*>(object), propertyName, slot);
+ return getStaticFunctionSlot<JSObject>(exec, dateTable, jsCast<DatePrototype*>(object), propertyName, slot);
}
// Functions
@@ -515,7 +523,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -561,7 +569,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -571,7 +579,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -581,7 +589,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -591,7 +599,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -600,7 +608,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -614,7 +622,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -634,7 +642,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -648,7 +656,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -662,7 +670,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -676,7 +684,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -690,7 +698,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -704,7 +712,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -718,7 +726,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -732,7 +740,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -746,7 +754,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -760,7 +768,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -774,7 +782,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -788,7 +796,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -802,7 +810,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -818,7 +826,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -834,7 +842,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -848,7 +856,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -862,7 +870,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, WTF::TimeType inputTimeType)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -900,7 +908,7 @@ static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse,
static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, WTF::TimeType inputTimeType)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -941,91 +949,77 @@ static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse,
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
{
- const WTF::TimeType inputTimeType = WTF::LocalTime;
- return setNewValueFromTimeArgs(exec, 1, inputTimeType);
+ return setNewValueFromTimeArgs(exec, 1, WTF::LocalTime);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
{
- const WTF::TimeType inputTimeType = WTF::UTCTime;
- return setNewValueFromTimeArgs(exec, 1, inputTimeType);
+ return setNewValueFromTimeArgs(exec, 1, WTF::UTCTime);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
{
- const WTF::TimeType inputTimeType = WTF::LocalTime;
- return setNewValueFromTimeArgs(exec, 2, inputTimeType);
+ return setNewValueFromTimeArgs(exec, 2, WTF::LocalTime);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
{
- const WTF::TimeType inputTimeType = WTF::UTCTime;
- return setNewValueFromTimeArgs(exec, 2, inputTimeType);
+ return setNewValueFromTimeArgs(exec, 2, WTF::UTCTime);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
{
- const WTF::TimeType inputTimeType = WTF::LocalTime;
- return setNewValueFromTimeArgs(exec, 3, inputTimeType);
+ return setNewValueFromTimeArgs(exec, 3, WTF::LocalTime);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
{
- const WTF::TimeType inputTimeType = WTF::UTCTime;
- return setNewValueFromTimeArgs(exec, 3, inputTimeType);
+ return setNewValueFromTimeArgs(exec, 3, WTF::UTCTime);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
{
- const WTF::TimeType inputTimeType = WTF::LocalTime;
- return setNewValueFromTimeArgs(exec, 4, inputTimeType);
+ return setNewValueFromTimeArgs(exec, 4, WTF::LocalTime);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
{
- const WTF::TimeType inputTimeType = WTF::UTCTime;
- return setNewValueFromTimeArgs(exec, 4, inputTimeType);
+ return setNewValueFromTimeArgs(exec, 4, WTF::UTCTime);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
{
- const WTF::TimeType inputTimeType = WTF::LocalTime;
- return setNewValueFromDateArgs(exec, 1, inputTimeType);
+ return setNewValueFromDateArgs(exec, 1, WTF::LocalTime);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
{
- const WTF::TimeType inputTimeType = WTF::UTCTime;
- return setNewValueFromDateArgs(exec, 1, inputTimeType);
+ return setNewValueFromDateArgs(exec, 1, WTF::UTCTime);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
{
- const WTF::TimeType inputTimeType = WTF::LocalTime;
- return setNewValueFromDateArgs(exec, 2, inputTimeType);
+ return setNewValueFromDateArgs(exec, 2, WTF::LocalTime);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
{
- const WTF::TimeType inputTimeType = WTF::UTCTime;
- return setNewValueFromDateArgs(exec, 2, inputTimeType);
+ return setNewValueFromDateArgs(exec, 2, WTF::UTCTime);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
{
- const WTF::TimeType inputTimeType = WTF::LocalTime;
- return setNewValueFromDateArgs(exec, 3, inputTimeType);
+ return setNewValueFromDateArgs(exec, 3, WTF::LocalTime);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
{
- const WTF::TimeType inputTimeType = WTF::UTCTime;
- return setNewValueFromDateArgs(exec, 3, inputTimeType);
+ return setNewValueFromDateArgs(exec, 3, WTF::UTCTime);
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -1067,7 +1061,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(DateInstance::info()))
return throwVMTypeError(exec);
@@ -1083,11 +1077,17 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
JSObject* object = jsCast<JSObject*>(thisValue.toThis(exec, NotStrictMode));
if (exec->hadException())
return JSValue::encode(jsNull());
-
+
+ JSValue timeValue = object->toPrimitive(exec, PreferNumber);
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+ if (timeValue.isNumber() && !(timeValue.isInt32() || std::isfinite(timeValue.asDouble())))
+ return JSValue::encode(jsNull());
+
JSValue toISOValue = object->get(exec, exec->vm().propertyNames->toISOString);
if (exec->hadException())
return JSValue::encode(jsNull());
diff --git a/Source/JavaScriptCore/runtime/DatePrototype.h b/Source/JavaScriptCore/runtime/DatePrototype.h
index a9bfbd477..cda4c1a0f 100644
--- a/Source/JavaScriptCore/runtime/DatePrototype.h
+++ b/Source/JavaScriptCore/runtime/DatePrototype.h
@@ -25,34 +25,36 @@
namespace JSC {
- class ObjectPrototype;
-
- class DatePrototype : public DateInstance {
- private:
- DatePrototype(VM&, Structure*);
-
- public:
- typedef DateInstance Base;
-
- static DatePrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
- {
- DatePrototype* prototype = new (NotNull, allocateCell<DatePrototype>(vm.heap)) DatePrototype(vm, structure);
- prototype->finishCreation(vm, globalObject);
- return prototype;
- }
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
-
- DECLARE_INFO;
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
-
- protected:
- void finishCreation(VM&, JSGlobalObject*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | DateInstance::StructureFlags;
- };
+class ObjectPrototype;
+
+class DatePrototype : public JSNonFinalObject {
+private:
+ DatePrototype(VM&, Structure*);
+
+public:
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static DatePrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+ {
+ DatePrototype* prototype = new (NotNull, allocateCell<DatePrototype>(vm.heap)) DatePrototype(vm, structure);
+ prototype->finishCreation(vm, globalObject);
+ return prototype;
+ }
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+protected:
+ void finishCreation(VM&, JSGlobalObject*);
+};
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/DirectArguments.cpp b/Source/JavaScriptCore/runtime/DirectArguments.cpp
new file mode 100644
index 000000000..b840df9ed
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/DirectArguments.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "DirectArguments.h"
+
+#include "CodeBlock.h"
+#include "CopiedBlockInlines.h"
+#include "CopyVisitorInlines.h"
+#include "GenericArgumentsInlines.h"
+#include "JSCInlines.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DirectArguments);
+
+const ClassInfo DirectArguments::s_info = { "Arguments", &Base::s_info, 0, CREATE_METHOD_TABLE(DirectArguments) };
+
+DirectArguments::DirectArguments(VM& vm, Structure* structure, unsigned length, unsigned capacity)
+ : GenericArguments(vm, structure)
+ , m_length(length)
+ , m_minCapacity(capacity)
+{
+ // When we construct the object from C++ code, we expect the capacity to be at least as large as
+ // length. JIT-allocated DirectArguments objects play evil tricks, though.
+ ASSERT(capacity >= length);
+}
+
+DirectArguments* DirectArguments::createUninitialized(
+ VM& vm, Structure* structure, unsigned length, unsigned capacity)
+{
+ DirectArguments* result =
+ new (NotNull, allocateCell<DirectArguments>(vm.heap, allocationSize(capacity)))
+ DirectArguments(vm, structure, length, capacity);
+ result->finishCreation(vm);
+ return result;
+}
+
+DirectArguments* DirectArguments::create(VM& vm, Structure* structure, unsigned length, unsigned capacity)
+{
+ DirectArguments* result = createUninitialized(vm, structure, length, capacity);
+
+ for (unsigned i = capacity; i--;)
+ result->storage()[i].clear();
+
+ return result;
+}
+
+DirectArguments* DirectArguments::createByCopying(ExecState* exec)
+{
+ VM& vm = exec->vm();
+
+ unsigned length = exec->argumentCount();
+ unsigned capacity = std::max(length, static_cast<unsigned>(exec->codeBlock()->numParameters() - 1));
+ DirectArguments* result = createUninitialized(
+ vm, exec->lexicalGlobalObject()->directArgumentsStructure(), length, capacity);
+
+ for (unsigned i = capacity; i--;)
+ result->storage()[i].set(vm, result, exec->getArgumentUnsafe(i));
+
+ result->callee().set(vm, result, jsCast<JSFunction*>(exec->callee()));
+
+ return result;
+}
+
+size_t DirectArguments::estimatedSize(JSCell* cell)
+{
+ DirectArguments* thisObject = jsCast<DirectArguments*>(cell);
+ size_t overridesSize = thisObject->m_overrides ? thisObject->overridesSize() : 0;
+ return Base::estimatedSize(cell) + overridesSize;
+}
+
+void DirectArguments::visitChildren(JSCell* thisCell, SlotVisitor& visitor)
+{
+ DirectArguments* thisObject = static_cast<DirectArguments*>(thisCell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.appendValues(thisObject->storage(), std::max(thisObject->m_length, thisObject->m_minCapacity));
+ visitor.append(&thisObject->m_callee);
+
+ if (thisObject->m_overrides) {
+ visitor.copyLater(
+ thisObject, DirectArgumentsOverridesCopyToken,
+ thisObject->m_overrides.getWithoutBarrier(), thisObject->overridesSize());
+ }
+}
+
+void DirectArguments::copyBackingStore(JSCell* thisCell, CopyVisitor& visitor, CopyToken token)
+{
+ DirectArguments* thisObject = static_cast<DirectArguments*>(thisCell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+
+ RELEASE_ASSERT(token == DirectArgumentsOverridesCopyToken);
+
+ void* oldOverrides = thisObject->m_overrides.getWithoutBarrier();
+ if (visitor.checkIfShouldCopy(oldOverrides)) {
+ bool* newOverrides = static_cast<bool*>(visitor.allocateNewSpace(thisObject->overridesSize()));
+ memcpy(newOverrides, oldOverrides, thisObject->m_length);
+ thisObject->m_overrides.setWithoutBarrier(newOverrides);
+ visitor.didCopy(oldOverrides, thisObject->overridesSize());
+ }
+}
+
+Structure* DirectArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(DirectArgumentsType, StructureFlags), info());
+}
+
+void DirectArguments::overrideThings(VM& vm)
+{
+ RELEASE_ASSERT(!m_overrides);
+
+ putDirect(vm, vm.propertyNames->length, jsNumber(m_length), DontEnum);
+ putDirect(vm, vm.propertyNames->callee, m_callee.get(), DontEnum);
+ putDirect(vm, vm.propertyNames->iteratorSymbol, globalObject()->arrayProtoValuesFunction(), DontEnum);
+
+ void* backingStore;
+ RELEASE_ASSERT(vm.heap.tryAllocateStorage(this, overridesSize(), &backingStore));
+ bool* overrides = static_cast<bool*>(backingStore);
+ m_overrides.set(vm, this, overrides);
+ for (unsigned i = m_length; i--;)
+ overrides[i] = false;
+}
+
+void DirectArguments::overrideThingsIfNecessary(VM& vm)
+{
+ if (!m_overrides)
+ overrideThings(vm);
+}
+
+void DirectArguments::overrideArgument(VM& vm, unsigned index)
+{
+ overrideThingsIfNecessary(vm);
+ m_overrides.get(this)[index] = true;
+}
+
+void DirectArguments::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length)
+{
+ if (!m_overrides) {
+ unsigned limit = std::min(length + offset, m_length);
+ unsigned i;
+ VirtualRegister start = firstElementDest - offset;
+ for (i = offset; i < limit; ++i)
+ exec->r(start + i) = storage()[i].get();
+ for (; i < length; ++i)
+ exec->r(start + i) = get(exec, i);
+ return;
+ }
+
+ GenericArguments::copyToArguments(exec, firstElementDest, offset, length);
+}
+
+unsigned DirectArguments::overridesSize()
+{
+ // We always allocate something; in the relatively uncommon case of overriding an empty argument we
+ // still allocate so that m_overrides is non-null. We use that to indicate that the other properties
+ // (length, etc) are overridden.
+ return WTF::roundUpToMultipleOf<8>(m_length ? m_length : 1);
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/runtime/DirectArguments.h b/Source/JavaScriptCore/runtime/DirectArguments.h
new file mode 100644
index 000000000..1911e4c6d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/DirectArguments.h
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+#ifndef DirectArguments_h
+#define DirectArguments_h
+
+#include "DirectArgumentsOffset.h"
+#include "GenericArguments.h"
+
+namespace JSC {
+
+// This is an Arguments-class object that we create when you say "arguments" inside a function,
+// and none of the arguments are captured in the function's activation. The function will copy all
+// of its arguments into this object, and all subsequent accesses to the arguments will go through
+// this object thereafter. Special support is in place for mischevious events like the arguments
+// being deleted (something like "delete arguments[0]") or reconfigured (broadly, we say deletions
+// and reconfigurations mean that the respective argument was "overridden").
+//
+// To speed allocation, this object will hold all of the arguments in-place. The arguments as well
+// as a table of flags saying which arguments were overridden.
+class DirectArguments : public GenericArguments<DirectArguments> {
+private:
+ DirectArguments(VM&, Structure*, unsigned length, unsigned capacity);
+
+public:
+ // Creates an arguments object but leaves it uninitialized. This is dangerous if we GC right
+ // after allocation.
+ static DirectArguments* createUninitialized(VM&, Structure*, unsigned length, unsigned capacity);
+
+ // Creates an arguments object and initializes everything to the empty value. Use this if you
+ // cannot guarantee that you'll immediately initialize all of the elements.
+ static DirectArguments* create(VM&, Structure*, unsigned length, unsigned capacity);
+
+ // Creates an arguments object by copying the argumnets from the stack.
+ static DirectArguments* createByCopying(ExecState*);
+
+ static size_t estimatedSize(JSCell*);
+ static void visitChildren(JSCell*, SlotVisitor&);
+ static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
+
+ uint32_t internalLength() const
+ {
+ return m_length;
+ }
+
+ uint32_t length(ExecState* exec) const
+ {
+ if (UNLIKELY(m_overrides))
+ return get(exec, exec->propertyNames().length).toUInt32(exec);
+ return m_length;
+ }
+
+ bool canAccessIndexQuickly(uint32_t i) const
+ {
+ return i < m_length && (!m_overrides || !m_overrides.get(this)[i]);
+ }
+
+ bool canAccessArgumentIndexQuicklyInDFG(uint32_t i) const
+ {
+ return i < m_length && !overrodeThings();
+ }
+
+ JSValue getIndexQuickly(uint32_t i) const
+ {
+ ASSERT_WITH_SECURITY_IMPLICATION(canAccessIndexQuickly(i));
+ return const_cast<DirectArguments*>(this)->storage()[i].get();
+ }
+
+ void setIndexQuickly(VM& vm, uint32_t i, JSValue value)
+ {
+ ASSERT_WITH_SECURITY_IMPLICATION(canAccessIndexQuickly(i));
+ storage()[i].set(vm, this, value);
+ }
+
+ WriteBarrier<JSFunction>& callee()
+ {
+ return m_callee;
+ }
+
+ WriteBarrier<Unknown>& argument(DirectArgumentsOffset offset)
+ {
+ ASSERT(offset);
+ ASSERT_WITH_SECURITY_IMPLICATION(offset.offset() < std::max(m_length, m_minCapacity));
+ return storage()[offset.offset()];
+ }
+
+ // Methods intended for use by the GenericArguments mixin.
+ bool overrodeThings() const { return !!m_overrides; }
+ void overrideThings(VM&);
+ void overrideThingsIfNecessary(VM&);
+ void overrideArgument(VM&, unsigned index);
+
+ void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length);
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+
+ static ptrdiff_t offsetOfCallee() { return OBJECT_OFFSETOF(DirectArguments, m_callee); }
+ static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(DirectArguments, m_length); }
+ static ptrdiff_t offsetOfMinCapacity() { return OBJECT_OFFSETOF(DirectArguments, m_minCapacity); }
+ static ptrdiff_t offsetOfOverrides() { return OBJECT_OFFSETOF(DirectArguments, m_overrides); }
+
+ static size_t storageOffset()
+ {
+ return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(DirectArguments));
+ }
+
+ static size_t offsetOfSlot(uint32_t index)
+ {
+ return storageOffset() + sizeof(WriteBarrier<Unknown>) * index;
+ }
+
+ static size_t allocationSize(uint32_t capacity)
+ {
+ return offsetOfSlot(capacity);
+ }
+
+private:
+ WriteBarrier<Unknown>* storage()
+ {
+ return bitwise_cast<WriteBarrier<Unknown>*>(bitwise_cast<char*>(this) + storageOffset());
+ }
+
+ unsigned overridesSize();
+
+ WriteBarrier<JSFunction> m_callee;
+ uint32_t m_length; // Always the actual length of captured arguments and never what was stored into the length property.
+ uint32_t m_minCapacity; // The max of this and length determines the capacity of this object. It may be the actual capacity, or maybe something smaller. We arrange it this way to be kind to the JITs.
+ CopyBarrier<bool> m_overrides; // If non-null, it means that length, callee, and caller are fully materialized properties.
+};
+
+} // namespace JSC
+
+#endif // DirectArguments_h
+
diff --git a/Source/JavaScriptCore/runtime/JSArgumentsIterator.cpp b/Source/JavaScriptCore/runtime/DirectArgumentsOffset.cpp
index 2fcf8815c..9fc4c42df 100644
--- a/Source/JavaScriptCore/runtime/JSArgumentsIterator.cpp
+++ b/Source/JavaScriptCore/runtime/DirectArgumentsOffset.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple, Inc. All rights reserved.
+ * 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
@@ -24,18 +24,19 @@
*/
#include "config.h"
-#include "JSArgumentsIterator.h"
-
-#include "Arguments.h"
+#include "DirectArgumentsOffset.h"
namespace JSC {
-const ClassInfo JSArgumentsIterator::s_info = { "ArgumentsIterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArgumentsIterator) };
-
-void JSArgumentsIterator::finishCreation(VM& vm, Arguments* arguments)
+void DirectArgumentsOffset::dump(PrintStream& out) const
{
- Base::finishCreation(vm);
- m_arguments.set(vm, this, arguments);
-}
+ if (!*this) {
+ out.print("capturedArgumentInvalid");
+ return;
+ }
+ out.print("capturedArgument", offset());
}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/runtime/DirectArgumentsOffset.h b/Source/JavaScriptCore/runtime/DirectArgumentsOffset.h
new file mode 100644
index 000000000..88a51874e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/DirectArgumentsOffset.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef DirectArgumentsOffset_h
+#define DirectArgumentsOffset_h
+
+#include "GenericOffset.h"
+#include <wtf/PrintStream.h>
+
+namespace JSC {
+
+// This is an offset into the special arguments object, which captures the arguments to a
+// function. It only comes into play if the arguments aren't also lifted into the activation.
+// If they were then accesses to the arguments would resolve to a ScopeOffset and not a
+// DirectArgumentsOffset.
+class DirectArgumentsOffset : public GenericOffset<DirectArgumentsOffset> {
+public:
+ DirectArgumentsOffset() { }
+
+ explicit DirectArgumentsOffset(unsigned offset)
+ : GenericOffset(offset)
+ {
+ }
+
+ void dump(PrintStream&) const;
+};
+
+} // namespace JSC
+
+#endif // DirectArgumentsOffset_h
+
diff --git a/Source/JavaScriptCore/runtime/DumpContext.cpp b/Source/JavaScriptCore/runtime/DumpContext.cpp
index 0546f4c87..f07c2b25d 100644
--- a/Source/JavaScriptCore/runtime/DumpContext.cpp
+++ b/Source/JavaScriptCore/runtime/DumpContext.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
diff --git a/Source/JavaScriptCore/runtime/DumpContext.h b/Source/JavaScriptCore/runtime/DumpContext.h
index 9ec931318..ddd6ba06e 100644
--- a/Source/JavaScriptCore/runtime/DumpContext.h
+++ b/Source/JavaScriptCore/runtime/DumpContext.h
@@ -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
diff --git a/Source/JavaScriptCore/runtime/EnumerationMode.h b/Source/JavaScriptCore/runtime/EnumerationMode.h
new file mode 100644
index 000000000..86d53e049
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/EnumerationMode.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 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. 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.
+ */
+
+#ifndef EnumerationMode_h
+#define EnumerationMode_h
+
+namespace JSC {
+
+enum class PropertyNameMode {
+ Symbols = 1 << 0,
+ Strings = 1 << 1,
+ StringsAndSymbols = Symbols | Strings,
+};
+
+enum class DontEnumPropertiesMode {
+ Include,
+ Exclude
+};
+
+enum class JSObjectPropertiesMode {
+ Include,
+ Exclude
+};
+
+class EnumerationMode {
+public:
+ EnumerationMode(DontEnumPropertiesMode dontEnumPropertiesMode = DontEnumPropertiesMode::Exclude, JSObjectPropertiesMode jsObjectPropertiesMode = JSObjectPropertiesMode::Include)
+ : m_dontEnumPropertiesMode(dontEnumPropertiesMode)
+ , m_jsObjectPropertiesMode(jsObjectPropertiesMode)
+ {
+ }
+
+ EnumerationMode(const EnumerationMode& mode, JSObjectPropertiesMode jsObjectPropertiesMode)
+ : m_dontEnumPropertiesMode(mode.m_dontEnumPropertiesMode)
+ , m_jsObjectPropertiesMode(jsObjectPropertiesMode)
+ {
+ }
+
+ // Add other constructors as needed for convenience
+
+ bool includeDontEnumProperties()
+ {
+ return m_dontEnumPropertiesMode == DontEnumPropertiesMode::Include;
+ }
+
+ bool includeJSObjectProperties()
+ {
+ return m_jsObjectPropertiesMode == JSObjectPropertiesMode::Include;
+ }
+
+private:
+ DontEnumPropertiesMode m_dontEnumPropertiesMode;
+ JSObjectPropertiesMode m_jsObjectPropertiesMode;
+};
+
+} // namespace JSC
+
+#endif // EnumerationMode_h
diff --git a/Source/JavaScriptCore/runtime/Error.cpp b/Source/JavaScriptCore/runtime/Error.cpp
index a87be188a..56219c449 100644
--- a/Source/JavaScriptCore/runtime/Error.cpp
+++ b/Source/JavaScriptCore/runtime/Error.cpp
@@ -34,7 +34,7 @@
#include "JSObject.h"
#include "JSString.h"
#include "NativeErrorConstructor.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "SourceCode.h"
#include <wtf/text/StringBuilder.h>
@@ -44,91 +44,150 @@ namespace JSC {
static const char* linePropertyName = "line";
static const char* sourceURLPropertyName = "sourceURL";
-JSObject* createError(JSGlobalObject* globalObject, const String& message)
+JSObject* createError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
{
ASSERT(!message.isEmpty());
- return ErrorInstance::create(globalObject->vm(), globalObject->errorStructure(), message);
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ return ErrorInstance::create(exec, globalObject->vm(), globalObject->errorStructure(), message, appender, TypeNothing, true);
}
-JSObject* createEvalError(JSGlobalObject* globalObject, const String& message)
+JSObject* createEvalError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
{
ASSERT(!message.isEmpty());
- return ErrorInstance::create(globalObject->vm(), globalObject->evalErrorConstructor()->errorStructure(), message);
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ return ErrorInstance::create(exec, globalObject->vm(), globalObject->evalErrorConstructor()->errorStructure(), message, appender, TypeNothing, true);
}
-JSObject* createRangeError(JSGlobalObject* globalObject, const String& message)
+JSObject* createRangeError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
{
ASSERT(!message.isEmpty());
- return ErrorInstance::create(globalObject->vm(), globalObject->rangeErrorConstructor()->errorStructure(), message);
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ return ErrorInstance::create(exec, globalObject->vm(), globalObject->rangeErrorConstructor()->errorStructure(), message, appender, TypeNothing, true);
}
-JSObject* createReferenceError(JSGlobalObject* globalObject, const String& message)
+JSObject* createReferenceError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
{
ASSERT(!message.isEmpty());
- return ErrorInstance::create(globalObject->vm(), globalObject->referenceErrorConstructor()->errorStructure(), message);
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ return ErrorInstance::create(exec, globalObject->vm(), globalObject->referenceErrorConstructor()->errorStructure(), message, appender, TypeNothing, true);
}
-JSObject* createSyntaxError(JSGlobalObject* globalObject, const String& message)
+JSObject* createSyntaxError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
{
ASSERT(!message.isEmpty());
- return ErrorInstance::create(globalObject->vm(), globalObject->syntaxErrorConstructor()->errorStructure(), message);
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ return ErrorInstance::create(exec, globalObject->vm(), globalObject->syntaxErrorConstructor()->errorStructure(), message, appender, TypeNothing, true);
}
-JSObject* createTypeError(JSGlobalObject* globalObject, const String& message)
+JSObject* createTypeError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender, RuntimeType type)
{
ASSERT(!message.isEmpty());
- return ErrorInstance::create(globalObject->vm(), globalObject->typeErrorConstructor()->errorStructure(), message);
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ return ErrorInstance::create(exec, globalObject->vm(), globalObject->typeErrorConstructor()->errorStructure(), message, appender, type, true);
}
-JSObject* createNotEnoughArgumentsError(JSGlobalObject* globalObject)
+JSObject* createNotEnoughArgumentsError(ExecState* exec, ErrorInstance::SourceAppender appender)
{
- return createTypeError(globalObject, ASCIILiteral("Not enough arguments"));
+ return createTypeError(exec, ASCIILiteral("Not enough arguments"), appender, TypeNothing);
}
-JSObject* createURIError(JSGlobalObject* globalObject, const String& message)
+JSObject* createURIError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
{
ASSERT(!message.isEmpty());
- return ErrorInstance::create(globalObject->vm(), globalObject->URIErrorConstructor()->errorStructure(), message);
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ return ErrorInstance::create(exec, globalObject->vm(), globalObject->URIErrorConstructor()->errorStructure(), message, appender, TypeNothing, true);
}
-JSObject* createError(ExecState* exec, const String& message)
+JSObject* createOutOfMemoryError(ExecState* exec, ErrorInstance::SourceAppender appender)
{
- return createError(exec->lexicalGlobalObject(), message);
+ return createError(exec, ASCIILiteral("Out of memory"), appender);
}
-JSObject* createEvalError(ExecState* exec, const String& message)
-{
- return createEvalError(exec->lexicalGlobalObject(), message);
-}
-JSObject* createRangeError(ExecState* exec, const String& message)
-{
- return createRangeError(exec->lexicalGlobalObject(), message);
-}
+class FindFirstCallerFrameWithCodeblockFunctor {
+public:
+ FindFirstCallerFrameWithCodeblockFunctor(CallFrame* startCallFrame)
+ : m_startCallFrame(startCallFrame)
+ , m_foundCallFrame(nullptr)
+ , m_foundStartCallFrame(false)
+ , m_index(0)
+ { }
-JSObject* createReferenceError(ExecState* exec, const String& message)
-{
- return createReferenceError(exec->lexicalGlobalObject(), message);
-}
+ StackVisitor::Status operator()(StackVisitor& visitor)
+ {
+ if (!m_foundStartCallFrame && (visitor->callFrame() == m_startCallFrame))
+ m_foundStartCallFrame = true;
-JSObject* createSyntaxError(ExecState* exec, const String& message)
-{
- return createSyntaxError(exec->lexicalGlobalObject(), message);
-}
+ if (m_foundStartCallFrame) {
+ if (visitor->callFrame()->codeBlock()) {
+ m_foundCallFrame = visitor->callFrame();
+ return StackVisitor::Done;
+ }
+ m_index++;
+ }
-JSObject* createTypeError(ExecState* exec, const String& message)
-{
- return createTypeError(exec->lexicalGlobalObject(), message);
-}
+ return StackVisitor::Continue;
+ }
-JSObject* createNotEnoughArgumentsError(ExecState* exec)
+ CallFrame* foundCallFrame() const { return m_foundCallFrame; }
+ unsigned index() const { return m_index; }
+
+private:
+ CallFrame* m_startCallFrame;
+ CallFrame* m_foundCallFrame;
+ bool m_foundStartCallFrame;
+ unsigned m_index;
+};
+
+bool addErrorInfoAndGetBytecodeOffset(ExecState* exec, VM& vm, JSObject* obj, bool useCurrentFrame, CallFrame*& callFrame, unsigned &bytecodeOffset)
{
- return createNotEnoughArgumentsError(exec->lexicalGlobalObject());
+ Vector<StackFrame> stackTrace = Vector<StackFrame>();
+
+ if (exec && stackTrace.isEmpty())
+ vm.interpreter->getStackTrace(stackTrace);
+
+ if (!stackTrace.isEmpty()) {
+
+ ASSERT(exec == vm.topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec());
+
+ StackFrame* stackFrame;
+ for (unsigned i = 0 ; i < stackTrace.size(); ++i) {
+ stackFrame = &stackTrace.at(i);
+ if (stackFrame->bytecodeOffset)
+ break;
+ }
+
+ if (bytecodeOffset) {
+ FindFirstCallerFrameWithCodeblockFunctor functor(exec);
+ vm.topCallFrame->iterate(functor);
+ callFrame = functor.foundCallFrame();
+ unsigned stackIndex = functor.index();
+ bytecodeOffset = stackTrace.at(stackIndex).bytecodeOffset;
+ }
+
+ unsigned line;
+ unsigned column;
+ stackFrame->computeLineAndColumn(line, column);
+ obj->putDirect(vm, vm.propertyNames->line, jsNumber(line), ReadOnly | DontDelete);
+ obj->putDirect(vm, vm.propertyNames->column, jsNumber(column), ReadOnly | DontDelete);
+
+ if (!stackFrame->sourceURL.isEmpty())
+ obj->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, stackFrame->sourceURL), ReadOnly | DontDelete);
+
+ if (!useCurrentFrame)
+ stackTrace.remove(0);
+ obj->putDirect(vm, vm.propertyNames->stack, vm.interpreter->stackTraceAsString(vm.topCallFrame, stackTrace), DontEnum);
+
+ return true;
+ }
+ return false;
}
-JSObject* createURIError(ExecState* exec, const String& message)
+void addErrorInfo(ExecState* exec, JSObject* obj, bool useCurrentFrame)
{
- return createURIError(exec->lexicalGlobalObject(), message);
+ CallFrame* callFrame = nullptr;
+ unsigned bytecodeOffset = 0;
+ addErrorInfoAndGetBytecodeOffset(exec, exec->vm(), obj, useCurrentFrame, callFrame, bytecodeOffset);
}
JSObject* addErrorInfo(CallFrame* callFrame, JSObject* error, int line, const SourceCode& source)
@@ -137,22 +196,27 @@ JSObject* addErrorInfo(CallFrame* callFrame, JSObject* error, int line, const So
const String& sourceURL = source.provider()->url();
if (line != -1)
- error->putDirect(*vm, Identifier(vm, linePropertyName), jsNumber(line), ReadOnly | DontDelete);
+ error->putDirect(*vm, Identifier::fromString(vm, linePropertyName), jsNumber(line), ReadOnly | DontDelete);
if (!sourceURL.isNull())
- error->putDirect(*vm, Identifier(vm, sourceURLPropertyName), jsString(vm, sourceURL), ReadOnly | DontDelete);
+ error->putDirect(*vm, Identifier::fromString(vm, sourceURLPropertyName), jsString(vm, sourceURL), ReadOnly | DontDelete);
return error;
}
bool hasErrorInfo(ExecState* exec, JSObject* error)
{
- return error->hasProperty(exec, Identifier(exec, linePropertyName))
- || error->hasProperty(exec, Identifier(exec, sourceURLPropertyName));
+ return error->hasProperty(exec, Identifier::fromString(exec, linePropertyName))
+ || error->hasProperty(exec, Identifier::fromString(exec, sourceURLPropertyName));
+}
+
+JSObject* throwConstructorCannotBeCalledAsFunctionTypeError(ExecState* exec, const char* constructorName)
+{
+ return exec->vm().throwException(exec, createTypeError(exec, makeString("calling ", constructorName, " constructor without new is invalid")));
}
JSObject* throwTypeError(ExecState* exec)
{
- return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Type error")));
+ return exec->vm().throwException(exec, createTypeError(exec));
}
JSObject* throwSyntaxError(ExecState* exec)
@@ -160,7 +224,63 @@ JSObject* throwSyntaxError(ExecState* exec)
return exec->vm().throwException(exec, createSyntaxError(exec, ASCIILiteral("Syntax error")));
}
-const ClassInfo StrictModeTypeErrorFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(StrictModeTypeErrorFunction) };
+JSObject* throwSyntaxError(ExecState* exec, const String& message)
+{
+ return exec->vm().throwException(exec, createSyntaxError(exec, message));
+}
+
+JSObject* createError(ExecState* exec, const String& message)
+{
+ return createError(exec, message, nullptr);
+}
+
+JSObject* createEvalError(ExecState* exec, const String& message)
+{
+ return createEvalError(exec, message, nullptr);
+}
+
+JSObject* createRangeError(ExecState* exec, const String& message)
+{
+ return createRangeError(exec, message, nullptr);
+}
+
+JSObject* createReferenceError(ExecState* exec, const String& message)
+{
+ return createReferenceError(exec, message, nullptr);
+}
+
+JSObject* createSyntaxError(ExecState* exec, const String& message)
+{
+ return createSyntaxError(exec, message, nullptr);
+}
+
+JSObject* createTypeError(ExecState* exec)
+{
+ return createTypeError(exec, ASCIILiteral("Type error"));
+}
+
+JSObject* createTypeError(ExecState* exec, const String& message)
+{
+ return createTypeError(exec, message, nullptr, TypeNothing);
+}
+
+JSObject* createNotEnoughArgumentsError(ExecState* exec)
+{
+ return createNotEnoughArgumentsError(exec, nullptr);
+}
+
+JSObject* createURIError(ExecState* exec, const String& message)
+{
+ return createURIError(exec, message, nullptr);
+}
+
+JSObject* createOutOfMemoryError(ExecState* exec)
+{
+ return createOutOfMemoryError(exec, nullptr);
+}
+
+
+const ClassInfo StrictModeTypeErrorFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(StrictModeTypeErrorFunction) };
void StrictModeTypeErrorFunction::destroy(JSCell* cell)
{
diff --git a/Source/JavaScriptCore/runtime/Error.h b/Source/JavaScriptCore/runtime/Error.h
index bec5dd756..032986981 100644
--- a/Source/JavaScriptCore/runtime/Error.h
+++ b/Source/JavaScriptCore/runtime/Error.h
@@ -23,108 +23,122 @@
#ifndef Error_h
#define Error_h
+#include "ErrorInstance.h"
#include "InternalFunction.h"
#include "Interpreter.h"
#include "JSObject.h"
#include <stdint.h>
+
namespace JSC {
- class ExecState;
- class VM;
- class JSGlobalObject;
- class JSObject;
- class SourceCode;
- class Structure;
-
- // Methods to create a range of internal errors.
- JSObject* createError(JSGlobalObject*, const String&);
- JSObject* createEvalError(JSGlobalObject*, const String&);
- JSObject* createRangeError(JSGlobalObject*, const String&);
- JSObject* createReferenceError(JSGlobalObject*, const String&);
- JSObject* createSyntaxError(JSGlobalObject*, const String&);
- JSObject* createTypeError(JSGlobalObject*, const String&);
- JSObject* createNotEnoughArgumentsError(JSGlobalObject*);
- JSObject* createURIError(JSGlobalObject*, const String&);
- // ExecState wrappers.
- JS_EXPORT_PRIVATE JSObject* createError(ExecState*, const String&);
- JSObject* createEvalError(ExecState*, const String&);
- JS_EXPORT_PRIVATE JSObject* createRangeError(ExecState*, const String&);
- JS_EXPORT_PRIVATE JSObject* createReferenceError(ExecState*, const String&);
- JS_EXPORT_PRIVATE JSObject* createSyntaxError(ExecState*, const String&);
- JS_EXPORT_PRIVATE JSObject* createTypeError(ExecState*, const String&);
- JS_EXPORT_PRIVATE JSObject* createNotEnoughArgumentsError(ExecState*);
- JSObject* createURIError(ExecState*, const String&);
-
- // Methods to add
- bool hasErrorInfo(ExecState*, JSObject* error);
- // ExecState wrappers.
- JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&);
-
- // Methods to throw Errors.
-
- // Convenience wrappers, create an throw an exception with a default message.
- JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*);
- JS_EXPORT_PRIVATE JSObject* throwSyntaxError(ExecState*);
-
- // Convenience wrappers, wrap result as an EncodedJSValue.
- inline EncodedJSValue throwVMError(ExecState* exec, JSValue error) { return JSValue::encode(exec->vm().throwException(exec, error)); }
- inline EncodedJSValue throwVMTypeError(ExecState* exec) { return JSValue::encode(throwTypeError(exec)); }
-
- class StrictModeTypeErrorFunction : public InternalFunction {
- private:
- StrictModeTypeErrorFunction(VM& vm, Structure* structure, const String& message)
- : InternalFunction(vm, structure)
- , m_message(message)
- {
- }
-
- static void destroy(JSCell*);
-
- public:
- typedef InternalFunction Base;
-
- static StrictModeTypeErrorFunction* create(VM& vm, Structure* structure, const String& message)
- {
- StrictModeTypeErrorFunction* function = new (NotNull, allocateCell<StrictModeTypeErrorFunction>(vm.heap)) StrictModeTypeErrorFunction(vm, structure, message);
- function->finishCreation(vm, String());
- return function;
- }
-
- static EncodedJSValue JSC_HOST_CALL constructThrowTypeError(ExecState* exec)
- {
- throwTypeError(exec, static_cast<StrictModeTypeErrorFunction*>(exec->callee())->m_message);
- return JSValue::encode(jsNull());
- }
-
- static ConstructType getConstructData(JSCell*, ConstructData& constructData)
- {
- constructData.native.function = constructThrowTypeError;
- return ConstructTypeHost;
- }
-
- static EncodedJSValue JSC_HOST_CALL callThrowTypeError(ExecState* exec)
- {
- throwTypeError(exec, static_cast<StrictModeTypeErrorFunction*>(exec->callee())->m_message);
- return JSValue::encode(jsNull());
- }
-
- static CallType getCallData(JSCell*, CallData& callData)
- {
- callData.native.function = callThrowTypeError;
- return CallTypeHost;
- }
-
- DECLARE_INFO;
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
-
- private:
- String m_message;
- };
+class ExecState;
+class VM;
+class JSGlobalObject;
+class JSObject;
+class SourceCode;
+class Structure;
+
+// ExecState wrappers.
+JSObject* createError(ExecState*, const String&, ErrorInstance::SourceAppender);
+JSObject* createEvalError(ExecState*, const String&, ErrorInstance::SourceAppender);
+JSObject* createRangeError(ExecState*, const String&, ErrorInstance::SourceAppender);
+JSObject* createReferenceError(ExecState*, const String&, ErrorInstance::SourceAppender);
+JSObject* createSyntaxError(ExecState*, const String&, ErrorInstance::SourceAppender);
+JSObject* createTypeError(ExecState*, const String&, ErrorInstance::SourceAppender, RuntimeType);
+JSObject* createNotEnoughArgumentsError(ExecState*, ErrorInstance::SourceAppender);
+JSObject* createURIError(ExecState*, const String&, ErrorInstance::SourceAppender);
+JSObject* createOutOfMemoryError(ExecState*, ErrorInstance::SourceAppender);
+
+
+JS_EXPORT_PRIVATE JSObject* createError(ExecState*, const String&);
+JS_EXPORT_PRIVATE JSObject* createEvalError(ExecState*, const String&);
+JS_EXPORT_PRIVATE JSObject* createRangeError(ExecState*, const String&);
+JS_EXPORT_PRIVATE JSObject* createReferenceError(ExecState*, const String&);
+JS_EXPORT_PRIVATE JSObject* createSyntaxError(ExecState*, const String&);
+JS_EXPORT_PRIVATE JSObject* createTypeError(ExecState*);
+JS_EXPORT_PRIVATE JSObject* createTypeError(ExecState*, const String&);
+JS_EXPORT_PRIVATE JSObject* createNotEnoughArgumentsError(ExecState*);
+JS_EXPORT_PRIVATE JSObject* createURIError(ExecState*, const String&);
+JS_EXPORT_PRIVATE JSObject* createOutOfMemoryError(ExecState*);
+
+
+bool addErrorInfoAndGetBytecodeOffset(ExecState*, VM&, JSObject*, bool, CallFrame*&, unsigned&);
+
+bool hasErrorInfo(ExecState*, JSObject* error);
+JS_EXPORT_PRIVATE void addErrorInfo(ExecState*, JSObject*, bool);
+JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&);
+
+// Methods to throw Errors.
+
+// Convenience wrappers, create an throw an exception with a default message.
+JS_EXPORT_PRIVATE JSObject* throwConstructorCannotBeCalledAsFunctionTypeError(ExecState*, const char* constructorName);
+JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*);
+JS_EXPORT_PRIVATE JSObject* throwSyntaxError(ExecState*);
+JS_EXPORT_PRIVATE JSObject* throwSyntaxError(ExecState*, const String& errorMessage);
+inline JSObject* throwRangeError(ExecState* state, const String& errorMessage) { return state->vm().throwException(state, createRangeError(state, errorMessage)); }
+
+// Convenience wrappers, wrap result as an EncodedJSValue.
+inline void throwVMError(ExecState* exec, Exception* exception) { exec->vm().throwException(exec, exception); }
+inline EncodedJSValue throwVMError(ExecState* exec, JSValue error) { return JSValue::encode(exec->vm().throwException(exec, error)); }
+inline EncodedJSValue throwVMTypeError(ExecState* exec) { return JSValue::encode(throwTypeError(exec)); }
+inline EncodedJSValue throwVMTypeError(ExecState* exec, const String& errorMessage) { return JSValue::encode(throwTypeError(exec, errorMessage)); }
+inline EncodedJSValue throwVMRangeError(ExecState* state, const String& errorMessage) { return JSValue::encode(throwRangeError(state, errorMessage)); }
+
+class StrictModeTypeErrorFunction : public InternalFunction {
+private:
+ StrictModeTypeErrorFunction(VM& vm, Structure* structure, const String& message)
+ : InternalFunction(vm, structure)
+ , m_message(message)
+ {
+ }
+
+ static void destroy(JSCell*);
+
+public:
+ typedef InternalFunction Base;
+
+ static StrictModeTypeErrorFunction* create(VM& vm, Structure* structure, const String& message)
+ {
+ StrictModeTypeErrorFunction* function = new (NotNull, allocateCell<StrictModeTypeErrorFunction>(vm.heap)) StrictModeTypeErrorFunction(vm, structure, message);
+ function->finishCreation(vm, String());
+ return function;
+ }
+
+ static EncodedJSValue JSC_HOST_CALL constructThrowTypeError(ExecState* exec)
+ {
+ throwTypeError(exec, static_cast<StrictModeTypeErrorFunction*>(exec->callee())->m_message);
+ return JSValue::encode(jsNull());
+ }
+
+ static ConstructType getConstructData(JSCell*, ConstructData& constructData)
+ {
+ constructData.native.function = constructThrowTypeError;
+ return ConstructTypeHost;
+ }
+
+ static EncodedJSValue JSC_HOST_CALL callThrowTypeError(ExecState* exec)
+ {
+ throwTypeError(exec, static_cast<StrictModeTypeErrorFunction*>(exec->callee())->m_message);
+ return JSValue::encode(jsNull());
+ }
+
+ static CallType getCallData(JSCell*, CallData& callData)
+ {
+ callData.native.function = callThrowTypeError;
+ return CallTypeHost;
+ }
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+private:
+ String m_message;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ErrorConstructor.cpp b/Source/JavaScriptCore/runtime/ErrorConstructor.cpp
index 2e31e7fd5..2998d73f0 100644
--- a/Source/JavaScriptCore/runtime/ErrorConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ErrorConstructor.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
@@ -25,13 +25,13 @@
#include "Interpreter.h"
#include "JSGlobalObject.h"
#include "JSString.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ErrorConstructor);
-const ClassInfo ErrorConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ErrorConstructor) };
+const ClassInfo ErrorConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(ErrorConstructor) };
ErrorConstructor::ErrorConstructor(VM& vm, Structure* structure)
: InternalFunction(vm, structure)
@@ -51,11 +51,8 @@ void ErrorConstructor::finishCreation(VM& vm, ErrorPrototype* errorPrototype)
EncodedJSValue JSC_HOST_CALL Interpreter::constructWithErrorConstructor(ExecState* exec)
{
JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined();
- Structure* errorStructure = asInternalFunction(exec->callee())->globalObject()->errorStructure();
- Vector<StackFrame> stackTrace;
- exec->vm().interpreter->getStackTrace(stackTrace, std::numeric_limits<size_t>::max());
- stackTrace.remove(0);
- return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, stackTrace));
+ Structure* errorStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), asInternalFunction(exec->callee())->globalObject()->errorStructure());
+ return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, nullptr, TypeNothing, false));
}
ConstructType ErrorConstructor::getConstructData(JSCell*, ConstructData& constructData)
@@ -68,10 +65,7 @@ EncodedJSValue JSC_HOST_CALL Interpreter::callErrorConstructor(ExecState* exec)
{
JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined();
Structure* errorStructure = asInternalFunction(exec->callee())->globalObject()->errorStructure();
- Vector<StackFrame> stackTrace;
- exec->vm().interpreter->getStackTrace(stackTrace, std::numeric_limits<size_t>::max());
- stackTrace.remove(0);
- return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, stackTrace));
+ return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, nullptr, TypeNothing, false));
}
CallType ErrorConstructor::getCallData(JSCell*, CallData& callData)
diff --git a/Source/JavaScriptCore/runtime/ErrorConstructor.h b/Source/JavaScriptCore/runtime/ErrorConstructor.h
index 29283d01b..96dea4948 100644
--- a/Source/JavaScriptCore/runtime/ErrorConstructor.h
+++ b/Source/JavaScriptCore/runtime/ErrorConstructor.h
@@ -26,34 +26,35 @@
namespace JSC {
- class ErrorPrototype;
+class ErrorPrototype;
+class GetterSetter;
- class ErrorConstructor : public InternalFunction {
- public:
- typedef InternalFunction Base;
+class ErrorConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
- static ErrorConstructor* create(VM& vm, Structure* structure, ErrorPrototype* errorPrototype)
- {
- ErrorConstructor* constructor = new (NotNull, allocateCell<ErrorConstructor>(vm.heap)) ErrorConstructor(vm, structure);
- constructor->finishCreation(vm, errorPrototype);
- return constructor;
- }
+ static ErrorConstructor* create(VM& vm, Structure* structure, ErrorPrototype* errorPrototype, GetterSetter*)
+ {
+ ErrorConstructor* constructor = new (NotNull, allocateCell<ErrorConstructor>(vm.heap)) ErrorConstructor(vm, structure);
+ constructor->finishCreation(vm, errorPrototype);
+ return constructor;
+ }
- DECLARE_INFO;
+ DECLARE_INFO;
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
- protected:
- void finishCreation(VM&, ErrorPrototype*);
+protected:
+ void finishCreation(VM&, ErrorPrototype*);
- private:
- ErrorConstructor(VM&, Structure*);
- static ConstructType getConstructData(JSCell*, ConstructData&);
- static CallType getCallData(JSCell*, CallData&);
- };
+private:
+ ErrorConstructor(VM&, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ErrorHandlingScope.cpp b/Source/JavaScriptCore/runtime/ErrorHandlingScope.cpp
new file mode 100644
index 000000000..beb52a334
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ErrorHandlingScope.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+#include "ErrorHandlingScope.h"
+
+#include "Interpreter.h"
+#include "Options.h"
+#include "VM.h"
+
+namespace JSC {
+
+ErrorHandlingScope::ErrorHandlingScope(VM& vm)
+ : m_vm(vm)
+{
+ RELEASE_ASSERT(m_vm.stackPointerAtVMEntry());
+ size_t newReservedZoneSize = Options::errorModeReservedZoneSize();
+ m_savedReservedZoneSize = m_vm.updateReservedZoneSize(newReservedZoneSize);
+#if !ENABLE(JIT)
+ m_vm.interpreter->stack().setReservedZoneSize(newReservedZoneSize);
+#endif
+}
+
+ErrorHandlingScope::~ErrorHandlingScope()
+{
+ RELEASE_ASSERT(m_vm.stackPointerAtVMEntry());
+ m_vm.updateReservedZoneSize(m_savedReservedZoneSize);
+#if !ENABLE(JIT)
+ m_vm.interpreter->stack().setReservedZoneSize(m_savedReservedZoneSize);
+#endif
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ErrorHandlingScope.h b/Source/JavaScriptCore/runtime/ErrorHandlingScope.h
new file mode 100644
index 000000000..451b241e4
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ErrorHandlingScope.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ErrorHandlingScope_h
+#define ErrorHandlingScope_h
+
+namespace JSC {
+
+class VM;
+
+class ErrorHandlingScope {
+public:
+ JS_EXPORT_PRIVATE ErrorHandlingScope(VM&);
+ JS_EXPORT_PRIVATE ~ErrorHandlingScope();
+private:
+ VM& m_vm;
+ size_t m_savedReservedZoneSize;
+};
+
+} // namespace JSC
+
+#endif // ErrorHandlingScope_h
+
diff --git a/Source/JavaScriptCore/runtime/ErrorInstance.cpp b/Source/JavaScriptCore/runtime/ErrorInstance.cpp
index c831f9183..164258266 100644
--- a/Source/JavaScriptCore/runtime/ErrorInstance.cpp
+++ b/Source/JavaScriptCore/runtime/ErrorInstance.cpp
@@ -21,30 +21,135 @@
#include "config.h"
#include "ErrorInstance.h"
+#include "CodeBlock.h"
+#include "InlineCallFrame.h"
#include "JSScope.h"
-#include "Operations.h"
+#include "JSCInlines.h"
+#include "JSGlobalObjectFunctions.h"
+#include <wtf/Vector.h>
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ErrorInstance);
-const ClassInfo ErrorInstance::s_info = { "Error", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(ErrorInstance) };
+const ClassInfo ErrorInstance::s_info = { "Error", &JSNonFinalObject::s_info, 0, CREATE_METHOD_TABLE(ErrorInstance) };
ErrorInstance::ErrorInstance(VM& vm, Structure* structure)
: JSNonFinalObject(vm, structure)
- , m_appendSourceToMessage(false)
{
}
-void ErrorInstance::finishCreation(VM& vm, const String& message, Vector<StackFrame> stackTrace)
+static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset)
+{
+ ErrorInstance::SourceAppender appender = exception->sourceAppender();
+ exception->clearSourceAppender();
+ RuntimeType type = exception->runtimeTypeForCause();
+ exception->clearRuntimeTypeForCause();
+
+ if (!callFrame->codeBlock()->hasExpressionInfo())
+ return;
+
+ int startOffset = 0;
+ int endOffset = 0;
+ int divotPoint = 0;
+ unsigned line = 0;
+ unsigned column = 0;
+
+ CodeBlock* codeBlock;
+ CodeOrigin codeOrigin = callFrame->codeOrigin();
+ if (codeOrigin && codeOrigin.inlineCallFrame)
+ codeBlock = baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame);
+ else
+ codeBlock = callFrame->codeBlock();
+
+ codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset, line, column);
+
+ int expressionStart = divotPoint - startOffset;
+ int expressionStop = divotPoint + endOffset;
+
+ StringView sourceString = codeBlock->source()->source();
+ if (!expressionStop || expressionStart > static_cast<int>(sourceString.length()))
+ return;
+
+ VM* vm = &callFrame->vm();
+ JSValue jsMessage = exception->getDirect(*vm, vm->propertyNames->message);
+ if (!jsMessage || !jsMessage.isString())
+ return;
+
+ String message = asString(jsMessage)->value(callFrame);
+ if (expressionStart < expressionStop)
+ message = appender(message, codeBlock->source()->getRange(expressionStart, expressionStop).toString(), type, ErrorInstance::FoundExactSource);
+ else {
+ // No range information, so give a few characters of context.
+ int dataLength = sourceString.length();
+ int start = expressionStart;
+ int stop = expressionStart;
+ // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
+ // Then strip whitespace.
+ while (start > 0 && (expressionStart - start < 20) && sourceString[start - 1] != '\n')
+ start--;
+ while (start < (expressionStart - 1) && isStrWhiteSpace(sourceString[start]))
+ start++;
+ while (stop < dataLength && (stop - expressionStart < 20) && sourceString[stop] != '\n')
+ stop++;
+ while (stop > expressionStart && isStrWhiteSpace(sourceString[stop - 1]))
+ stop--;
+ message = appender(message, codeBlock->source()->getRange(start, stop).toString(), type, ErrorInstance::FoundApproximateSource);
+ }
+ exception->putDirect(*vm, vm->propertyNames->message, jsString(vm, message));
+
+}
+
+class FindFirstCallerFrameWithCodeblockFunctor {
+public:
+ FindFirstCallerFrameWithCodeblockFunctor(CallFrame* startCallFrame)
+ : m_startCallFrame(startCallFrame)
+ , m_foundCallFrame(nullptr)
+ , m_foundStartCallFrame(false)
+ , m_index(0)
+ { }
+
+ StackVisitor::Status operator()(StackVisitor& visitor)
+ {
+ if (!m_foundStartCallFrame && (visitor->callFrame() == m_startCallFrame))
+ m_foundStartCallFrame = true;
+
+ if (m_foundStartCallFrame) {
+ if (visitor->callFrame()->codeBlock()) {
+ m_foundCallFrame = visitor->callFrame();
+ return StackVisitor::Done;
+ }
+ m_index++;
+ }
+
+ return StackVisitor::Continue;
+ }
+
+ CallFrame* foundCallFrame() const { return m_foundCallFrame; }
+ unsigned index() const { return m_index; }
+
+private:
+ CallFrame* m_startCallFrame;
+ CallFrame* m_foundCallFrame;
+ bool m_foundStartCallFrame;
+ unsigned m_index;
+};
+
+void ErrorInstance::finishCreation(ExecState* exec, VM& vm, const String& message, bool useCurrentFrame)
{
Base::finishCreation(vm);
ASSERT(inherits(info()));
if (!message.isNull())
putDirect(vm, vm.propertyNames->message, jsString(&vm, message), DontEnum);
-
- if (!stackTrace.isEmpty())
- putDirect(vm, vm.propertyNames->stack, vm.interpreter->stackTraceAsString(vm.topCallFrame, stackTrace), DontEnum);
+
+ unsigned bytecodeOffset = hasSourceAppender();
+ CallFrame* callFrame = nullptr;
+ bool hasTrace = addErrorInfoAndGetBytecodeOffset(exec, vm, this, useCurrentFrame, callFrame, bytecodeOffset);
+
+ if (hasTrace && callFrame && hasSourceAppender()) {
+ if (callFrame && callFrame->codeBlock())
+ appendSourceToError(callFrame, this, bytecodeOffset);
+ }
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ErrorInstance.h b/Source/JavaScriptCore/runtime/ErrorInstance.h
index 91dd7ef0a..3f584a99f 100644
--- a/Source/JavaScriptCore/runtime/ErrorInstance.h
+++ b/Source/JavaScriptCore/runtime/ErrorInstance.h
@@ -22,45 +22,58 @@
#define ErrorInstance_h
#include "Interpreter.h"
-#include "JSObject.h"
+#include "RuntimeType.h"
#include "SourceProvider.h"
+#include <wtf/Vector.h>
namespace JSC {
- class ErrorInstance : public JSNonFinalObject {
- public:
- typedef JSNonFinalObject Base;
+class ErrorInstance : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
- DECLARE_INFO;
+ enum SourceTextWhereErrorOccurred { FoundExactSource, FoundApproximateSource };
+ typedef String (*SourceAppender) (const String& originalMessage, const String& sourceText, RuntimeType, SourceTextWhereErrorOccurred);
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ErrorInstanceType, StructureFlags), info());
- }
+ DECLARE_INFO;
- static ErrorInstance* create(VM& vm, Structure* structure, const String& message, Vector<StackFrame> stackTrace = Vector<StackFrame>())
- {
- ErrorInstance* instance = new (NotNull, allocateCell<ErrorInstance>(vm.heap)) ErrorInstance(vm, structure);
- instance->finishCreation(vm, message, stackTrace);
- return instance;
- }
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ErrorInstanceType, StructureFlags), info());
+ }
- static ErrorInstance* create(ExecState* exec, Structure* structure, JSValue message, Vector<StackFrame> stackTrace = Vector<StackFrame>())
- {
- return create(exec->vm(), structure, message.isUndefined() ? String() : message.toString(exec)->value(exec), stackTrace);
- }
+ static ErrorInstance* create(ExecState* exec, VM& vm, Structure* structure, const String& message, SourceAppender appender = nullptr, RuntimeType type = TypeNothing, bool useCurrentFrame = true)
+ {
+ ErrorInstance* instance = new (NotNull, allocateCell<ErrorInstance>(vm.heap)) ErrorInstance(vm, structure);
+ instance->m_sourceAppender = appender;
+ instance->m_runtimeTypeForCause = type;
+ instance->finishCreation(exec, vm, message, useCurrentFrame);
+ return instance;
+ }
- bool appendSourceToMessage() { return m_appendSourceToMessage; }
- void setAppendSourceToMessage() { m_appendSourceToMessage = true; }
- void clearAppendSourceToMessage() { m_appendSourceToMessage = false; }
+ static ErrorInstance* create(ExecState* exec, Structure* structure, JSValue message, SourceAppender appender = nullptr, RuntimeType type = TypeNothing, bool useCurrentFrame = true)
+ {
+ return create(exec, exec->vm(), structure, message.isUndefined() ? String() : message.toString(exec)->value(exec), appender, type, useCurrentFrame);
+ }
- protected:
- explicit ErrorInstance(VM&, Structure*);
+ static void addErrorInfo(ExecState*, VM&, JSObject*, bool = true);
- void finishCreation(VM&, const String&, Vector<StackFrame> = Vector<StackFrame>());
+ bool hasSourceAppender() const { return !!m_sourceAppender; }
+ SourceAppender sourceAppender() const { return m_sourceAppender; }
+ void setSourceAppender(SourceAppender appender) { m_sourceAppender = appender; }
+ void clearSourceAppender() { m_sourceAppender = nullptr; }
+ void setRuntimeTypeForCause(RuntimeType type) { m_runtimeTypeForCause = type; }
+ RuntimeType runtimeTypeForCause() const { return m_runtimeTypeForCause; }
+ void clearRuntimeTypeForCause() { m_runtimeTypeForCause = TypeNothing; }
- bool m_appendSourceToMessage;
- };
+protected:
+ explicit ErrorInstance(VM&, Structure*);
+
+ void finishCreation(ExecState*, VM&, const String&, bool useCurrentFrame = true);
+
+ SourceAppender m_sourceAppender { nullptr };
+ RuntimeType m_runtimeTypeForCause { TypeNothing };
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp
index 55cb03304..5bc2ec3c8 100644
--- a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp
@@ -26,7 +26,7 @@
#include "JSString.h"
#include "JSStringBuilder.h"
#include "ObjectPrototype.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "StringRecursionChecker.h"
namespace JSC {
@@ -41,7 +41,7 @@ static EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState*);
namespace JSC {
-const ClassInfo ErrorPrototype::s_info = { "Error", &ErrorInstance::s_info, 0, ExecState::errorPrototypeTable, CREATE_METHOD_TABLE(ErrorPrototype) };
+const ClassInfo ErrorPrototype::s_info = { "Error", &ErrorInstance::s_info, &errorPrototypeTable, CREATE_METHOD_TABLE(ErrorPrototype) };
/* Source for ErrorPrototype.lut.h
@begin errorPrototypeTable
@@ -54,16 +54,16 @@ ErrorPrototype::ErrorPrototype(VM& vm, Structure* structure)
{
}
-void ErrorPrototype::finishCreation(VM& vm, JSGlobalObject*)
+void ErrorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
{
- Base::finishCreation(vm, "");
+ Base::finishCreation(globalObject->globalExec(), vm, "");
ASSERT(inherits(info()));
putDirect(vm, vm.propertyNames->name, jsNontrivialString(&vm, String(ASCIILiteral("Error"))), DontEnum);
}
bool ErrorPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
{
- return getStaticFunctionSlot<ErrorInstance>(exec, ExecState::errorPrototypeTable(exec->vm()), jsCast<ErrorPrototype*>(object), propertyName, slot);
+ return getStaticFunctionSlot<ErrorInstance>(exec, errorPrototypeTable, jsCast<ErrorPrototype*>(object), propertyName, slot);
}
// ------------------------------ Functions ---------------------------
@@ -72,7 +72,7 @@ bool ErrorPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, Prope
EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState* exec)
{
// 1. Let O be the this value.
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
// 2. If Type(O) is not Object, throw a TypeError exception.
if (!thisValue.isObject())
diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.h b/Source/JavaScriptCore/runtime/ErrorPrototype.h
index 10707abdb..29cd6a948 100644
--- a/Source/JavaScriptCore/runtime/ErrorPrototype.h
+++ b/Source/JavaScriptCore/runtime/ErrorPrototype.h
@@ -25,35 +25,34 @@
namespace JSC {
- class ObjectPrototype;
-
- class ErrorPrototype : public ErrorInstance {
- public:
- typedef ErrorInstance Base;
-
- static ErrorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
- {
- ErrorPrototype* prototype = new (NotNull, allocateCell<ErrorPrototype>(vm.heap)) ErrorPrototype(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(ErrorInstanceType, StructureFlags), info());
- }
-
- protected:
- ErrorPrototype(VM&, Structure*);
- void finishCreation(VM&, JSGlobalObject*);
-
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ErrorInstance::StructureFlags;
-
- private:
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- };
+class ObjectPrototype;
+
+class ErrorPrototype : public ErrorInstance {
+public:
+ typedef ErrorInstance Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static ErrorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+ {
+ ErrorPrototype* prototype = new (NotNull, allocateCell<ErrorPrototype>(vm.heap)) ErrorPrototype(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(ErrorInstanceType, StructureFlags), info());
+ }
+
+protected:
+ ErrorPrototype(VM&, Structure*);
+ void finishCreation(VM&, JSGlobalObject*);
+
+private:
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Exception.cpp b/Source/JavaScriptCore/runtime/Exception.cpp
new file mode 100644
index 000000000..4f5fcb981
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Exception.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "Exception.h"
+
+#include "JSCInlines.h"
+
+namespace JSC {
+
+const ClassInfo Exception::s_info = { "Exception", &Base::s_info, 0, CREATE_METHOD_TABLE(Exception) };
+
+Exception* Exception::create(VM& vm, JSValue thrownValue, StackCaptureAction action)
+{
+ Exception* result = new (NotNull, allocateCell<Exception>(vm.heap)) Exception(vm);
+ result->finishCreation(vm, thrownValue, action);
+ return result;
+}
+
+void Exception::destroy(JSCell* cell)
+{
+ Exception* exception = static_cast<Exception*>(cell);
+ exception->~Exception();
+}
+
+Structure* Exception::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+void Exception::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ Exception* thisObject = jsCast<Exception*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_value);
+}
+
+Exception::Exception(VM& vm)
+ : Base(vm, vm.exceptionStructure.get())
+{
+}
+
+Exception::~Exception()
+{
+}
+
+void Exception::finishCreation(VM& vm, JSValue thrownValue, StackCaptureAction action)
+{
+ Base::finishCreation(vm);
+
+ m_value.set(vm, this, thrownValue);
+
+ Vector<StackFrame> stackTrace;
+ if (action == StackCaptureAction::CaptureStack)
+ vm.interpreter->getStackTrace(stackTrace);
+ m_stack = RefCountedArray<StackFrame>(stackTrace);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSArgumentsIterator.h b/Source/JavaScriptCore/runtime/Exception.h
index 0eed745c9..491cb4994 100644
--- a/Source/JavaScriptCore/runtime/JSArgumentsIterator.h
+++ b/Source/JavaScriptCore/runtime/Exception.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple, Inc. All rights reserved.
+ * 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
@@ -20,60 +20,61 @@
* 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.
*/
-#ifndef JSArgumentsIterator_h
-#define JSArgumentsIterator_h
+#ifndef Exception_h
+#define Exception_h
-#include "Arguments.h"
+#include "Interpreter.h"
+#include <wtf/RefCountedArray.h>
namespace JSC {
-
-class JSArgumentsIterator : public JSNonFinalObject {
+
+class Exception : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = StructureIsImmortal | Base::StructureFlags;
+
+ enum StackCaptureAction {
+ CaptureStack,
+ DoNotCaptureStack
+ };
+ JS_EXPORT_PRIVATE static Exception* create(VM&, JSValue thrownValue, StackCaptureAction = CaptureStack);
+
+ static const bool needsDestruction = true;
+ static void destroy(JSCell*);
+
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+
+ static void visitChildren(JSCell*, SlotVisitor&);
DECLARE_EXPORT_INFO;
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ static ptrdiff_t valueOffset()
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ return OBJECT_OFFSETOF(Exception, m_value);
}
- static JSArgumentsIterator* create(VM& vm, Structure* structure, Arguments* arguments)
- {
- JSArgumentsIterator* instance = new (NotNull, allocateCell<JSArgumentsIterator>(vm.heap)) JSArgumentsIterator(vm, structure);
- instance->finishCreation(vm, arguments);
- return instance;
- }
+ JSValue value() const { return m_value.get(); }
+ const RefCountedArray<StackFrame>& stack() const { return m_stack; }
- bool next(CallFrame* callFrame, JSValue& value)
- {
- if (m_nextIndex >= m_arguments->length(callFrame))
- return false;
- value = m_arguments->tryGetArgument(m_nextIndex++);
- if (!value)
- value = jsUndefined();
- return true;
- }
+ bool didNotifyInspectorOfThrow() const { return m_didNotifyInspectorOfThrow; }
+ void setDidNotifyInspectorOfThrow() { m_didNotifyInspectorOfThrow = true; }
+
+ ~Exception();
private:
+ Exception(VM&);
+ void finishCreation(VM&, JSValue thrownValue, StackCaptureAction);
- static const unsigned StructureFlags = Base::StructureFlags;
+ WriteBarrier<Unknown> m_value;
+ RefCountedArray<StackFrame> m_stack;
+ bool m_didNotifyInspectorOfThrow { false };
- JSArgumentsIterator(VM& vm, Structure* structure)
- : Base(vm, structure)
- , m_nextIndex(0)
- {
- }
-
- void finishCreation(VM&, Arguments*);
-
- WriteBarrier<Arguments> m_arguments;
- size_t m_nextIndex;
+ friend class LLIntOffsetsExtractor;
};
-}
+} // namespace JSC
-#endif // !defined(JSArgumentsIterator_h)
+#endif // Exception_h
diff --git a/Source/JavaScriptCore/runtime/ExceptionFuzz.cpp b/Source/JavaScriptCore/runtime/ExceptionFuzz.cpp
new file mode 100644
index 000000000..3fb2787fe
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ExceptionFuzz.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+#include "ExceptionFuzz.h"
+
+#include "Error.h"
+#include "JSCInlines.h"
+#include "TestRunnerUtils.h"
+
+namespace JSC {
+
+static unsigned s_numberOfExceptionFuzzChecks;
+unsigned numberOfExceptionFuzzChecks() { return s_numberOfExceptionFuzzChecks; }
+
+// Call this only if you know that exception fuzzing is enabled.
+void doExceptionFuzzing(ExecState* exec, const char* where, void* returnPC)
+{
+ ASSERT(Options::useExceptionFuzz());
+
+ DeferGCForAWhile deferGC(exec->vm().heap);
+
+ s_numberOfExceptionFuzzChecks++;
+
+ unsigned fireTarget = Options::fireExceptionFuzzAt();
+ if (fireTarget == s_numberOfExceptionFuzzChecks) {
+ printf("JSC EXCEPTION FUZZ: Throwing fuzz exception with call frame %p, seen in %s and return address %p.\n", exec, where, returnPC);
+ exec->vm().throwException(
+ exec, createError(exec, ASCIILiteral("Exception Fuzz")));
+ }
+}
+
+} // namespace JSC
+
+
diff --git a/Source/JavaScriptCore/runtime/ExceptionFuzz.h b/Source/JavaScriptCore/runtime/ExceptionFuzz.h
new file mode 100644
index 000000000..d96c756dd
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ExceptionFuzz.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ExceptionFuzz_h
+#define ExceptionFuzz_h
+
+#include "Options.h"
+
+namespace JSC {
+
+class ExecState;
+
+// Call this only if you know that exception fuzzing is enabled.
+void doExceptionFuzzing(ExecState* exec, const char* where, void* returnPC);
+
+// This is what you should call if you don't know if fuzzing is enabled.
+ALWAYS_INLINE void doExceptionFuzzingIfEnabled(ExecState* exec, const char* where, void* returnPC)
+{
+ if (LIKELY(!Options::useExceptionFuzz()))
+ return;
+ doExceptionFuzzing(exec, where, returnPC);
+}
+
+} // namespace JSC
+
+#endif // ExceptionFuzz_h
+
diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
index 8f44248e3..f9a5bb456 100644
--- a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
+++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
@@ -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.
*
@@ -31,25 +31,28 @@
#include "CodeBlock.h"
#include "CallFrame.h"
-#include "ErrorInstance.h"
+#include "ErrorHandlingScope.h"
+#include "Exception.h"
#include "JSGlobalObjectFunctions.h"
-#include "JSObject.h"
#include "JSNotAnObject.h"
#include "Interpreter.h"
#include "Nodes.h"
-#include "Operations.h"
+#include "JSCInlines.h"
+#include "RuntimeType.h"
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringView.h>
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(TerminatedExecutionError);
-const ClassInfo TerminatedExecutionError::s_info = { "TerminatedExecutionError", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(TerminatedExecutionError) };
+const ClassInfo TerminatedExecutionError::s_info = { "TerminatedExecutionError", &Base::s_info, 0, CREATE_METHOD_TABLE(TerminatedExecutionError) };
JSValue TerminatedExecutionError::defaultValue(const JSObject*, ExecState* exec, PreferredPrimitiveType hint)
{
if (hint == PreferString)
return jsNontrivialString(exec, String(ASCIILiteral("JavaScript execution terminated.")));
- return JSValue(QNaN);
+ return JSValue(PNaN);
}
JSObject* createTerminatedExecutionException(VM* vm)
@@ -57,117 +60,253 @@ JSObject* createTerminatedExecutionException(VM* vm)
return TerminatedExecutionError::create(*vm);
}
-bool isTerminatedExecutionException(JSObject* object)
+bool isTerminatedExecutionException(Exception* exception)
{
- return object->inherits(TerminatedExecutionError::info());
-}
+ if (!exception->value().isObject())
+ return false;
-bool isTerminatedExecutionException(JSValue value)
-{
- return value.inherits(TerminatedExecutionError::info());
+ return exception->value().inherits(TerminatedExecutionError::info());
}
-
JSObject* createStackOverflowError(ExecState* exec)
{
return createRangeError(exec, ASCIILiteral("Maximum call stack size exceeded."));
}
-JSObject* createStackOverflowError(JSGlobalObject* globalObject)
-{
- return createRangeError(globalObject, ASCIILiteral("Maximum call stack size exceeded."));
-}
-
JSObject* createUndefinedVariableError(ExecState* exec, const Identifier& ident)
{
+ if (exec->propertyNames().isPrivateName(ident)) {
+ String message(makeString("Can't find private variable: @", exec->propertyNames().lookUpPublicName(ident).string()));
+ return createReferenceError(exec, message);
+ }
String message(makeString("Can't find variable: ", ident.string()));
return createReferenceError(exec, message);
}
JSString* errorDescriptionForValue(ExecState* exec, JSValue v)
{
- VM& vm = exec->vm();
- if (v.isNull())
- return vm.smallStrings.nullString();
- if (v.isUndefined())
- return vm.smallStrings.undefinedString();
- if (v.isInt32())
- return jsString(&vm, vm.numericStrings.add(v.asInt32()));
- if (v.isDouble())
- return jsString(&vm, vm.numericStrings.add(v.asDouble()));
- if (v.isTrue())
- return vm.smallStrings.trueString();
- if (v.isFalse())
- return vm.smallStrings.falseString();
if (v.isString())
- return jsCast<JSString*>(v.asCell());
+ return jsNontrivialString(exec, makeString('"', asString(v)->value(exec), '"'));
if (v.isObject()) {
CallData callData;
JSObject* object = asObject(v);
if (object->methodTable()->getCallData(object, callData) != CallTypeNone)
- return vm.smallStrings.functionString();
- return jsString(exec, object->methodTable()->className(object));
+ return exec->vm().smallStrings.functionString();
+ return jsString(exec, JSObject::calculatedClassName(object));
}
-
- // The JSValue should never be empty, so this point in the code should never be reached.
- ASSERT_NOT_REACHED();
- return vm.smallStrings.emptyString();
+ return v.toString(exec);
}
-JSObject* createError(ExecState* exec, ErrorFactory errorFactory, JSValue value, const String& message)
+static String defaultApproximateSourceError(const String& originalMessage, const String& sourceText)
+{
+ return makeString(originalMessage, " (near '...", sourceText, "...')");
+}
+
+static String defaultSourceAppender(const String& originalMessage, const String& sourceText, RuntimeType, ErrorInstance::SourceTextWhereErrorOccurred occurrence)
+{
+ if (occurrence == ErrorInstance::FoundApproximateSource)
+ return defaultApproximateSourceError(originalMessage, sourceText);
+
+ ASSERT(occurrence == ErrorInstance::FoundExactSource);
+ return makeString(originalMessage, " (evaluating '", sourceText, "')");
+}
+
+static String functionCallBase(const String& sourceText)
+{
+ // This function retrieves the 'foo.bar' substring from 'foo.bar(baz)'.
+ // FIXME: This function has simple processing of /* */ style comments.
+ // It doesn't properly handle embedded comments of string literals that contain
+ // parenthesis or comment constructs, e.g. foo.bar("/abc\)*/").
+ // https://bugs.webkit.org/show_bug.cgi?id=146304
+
+ unsigned sourceLength = sourceText.length();
+ unsigned idx = sourceLength - 1;
+ if (sourceLength < 2 || sourceText[idx] != ')') {
+ // For function calls that have many new lines in between their open parenthesis
+ // and their closing parenthesis, the text range passed into the message appender
+ // will not inlcude the text in between these parentheses, it will just be the desired
+ // text that precedes the parentheses.
+ return sourceText;
+ }
+
+ unsigned parenStack = 1;
+ bool isInMultiLineComment = false;
+ idx -= 1;
+ // Note that we're scanning text right to left instead of the more common left to right,
+ // so syntax detection is backwards.
+ while (parenStack > 0) {
+ UChar curChar = sourceText[idx];
+ if (isInMultiLineComment) {
+ if (idx > 0 && curChar == '*' && sourceText[idx - 1] == '/') {
+ isInMultiLineComment = false;
+ idx -= 1;
+ }
+ } else if (curChar == '(')
+ parenStack -= 1;
+ else if (curChar == ')')
+ parenStack += 1;
+ else if (idx > 0 && curChar == '/' && sourceText[idx - 1] == '*') {
+ isInMultiLineComment = true;
+ idx -= 1;
+ }
+
+ if (!idx)
+ break;
+
+ idx -= 1;
+ }
+
+ return sourceText.left(idx + 1);
+}
+
+static String notAFunctionSourceAppender(const String& originalMessage, const String& sourceText, RuntimeType type, ErrorInstance::SourceTextWhereErrorOccurred occurrence)
+{
+ ASSERT(type != TypeFunction);
+
+ if (occurrence == ErrorInstance::FoundApproximateSource)
+ return defaultApproximateSourceError(originalMessage, sourceText);
+
+ ASSERT(occurrence == ErrorInstance::FoundExactSource);
+ auto notAFunctionIndex = originalMessage.reverseFind("is not a function");
+ RELEASE_ASSERT(notAFunctionIndex != notFound);
+ StringView displayValue;
+ if (originalMessage.is8Bit())
+ displayValue = StringView(originalMessage.characters8(), notAFunctionIndex - 1);
+ else
+ displayValue = StringView(originalMessage.characters16(), notAFunctionIndex - 1);
+
+ String base = functionCallBase(sourceText);
+ StringBuilder builder;
+ builder.append(base);
+ builder.appendLiteral(" is not a function. (In '");
+ builder.append(sourceText);
+ builder.appendLiteral("', '");
+ builder.append(base);
+ builder.appendLiteral("' is ");
+ if (type == TypeObject)
+ builder.appendLiteral("an instance of ");
+ builder.append(displayValue);
+ builder.append(')');
+
+ return builder.toString();
+}
+
+static String invalidParameterInSourceAppender(const String& originalMessage, const String& sourceText, RuntimeType type, ErrorInstance::SourceTextWhereErrorOccurred occurrence)
+{
+ ASSERT_UNUSED(type, type != TypeObject);
+
+ if (occurrence == ErrorInstance::FoundApproximateSource)
+ return defaultApproximateSourceError(originalMessage, sourceText);
+
+ ASSERT(occurrence == ErrorInstance::FoundExactSource);
+ auto inIndex = sourceText.reverseFind("in");
+ RELEASE_ASSERT(inIndex != notFound);
+ if (sourceText.find("in") != inIndex)
+ return makeString(originalMessage, " (evaluating '", sourceText, "')");
+
+ static const unsigned inLength = 2;
+ String rightHandSide = sourceText.substring(inIndex + inLength).simplifyWhiteSpace();
+ return makeString(rightHandSide, " is not an Object. (evaluating '", sourceText, "')");
+}
+
+inline String invalidParameterInstanceofSourceAppender(const String& content, const String& originalMessage, const String& sourceText, RuntimeType, ErrorInstance::SourceTextWhereErrorOccurred occurrence)
+{
+ if (occurrence == ErrorInstance::FoundApproximateSource)
+ return defaultApproximateSourceError(originalMessage, sourceText);
+
+ ASSERT(occurrence == ErrorInstance::FoundExactSource);
+ auto instanceofIndex = sourceText.reverseFind("instanceof");
+ RELEASE_ASSERT(instanceofIndex != notFound);
+ if (sourceText.find("instanceof") != instanceofIndex)
+ return makeString(originalMessage, " (evaluating '", sourceText, "')");
+
+ static const unsigned instanceofLength = 10;
+ String rightHandSide = sourceText.substring(instanceofIndex + instanceofLength).simplifyWhiteSpace();
+ return makeString(rightHandSide, content, ". (evaluating '", sourceText, "')");
+}
+
+static String invalidParameterInstanceofNotFunctionSourceAppender(const String& originalMessage, const String& sourceText, RuntimeType runtimeType, ErrorInstance::SourceTextWhereErrorOccurred occurrence)
{
- String errorMessage = makeString(errorDescriptionForValue(exec, value)->value(exec), " ", message);
- JSObject* exception = errorFactory(exec, errorMessage);
+ return invalidParameterInstanceofSourceAppender(WTF::makeString(" is not a function"), originalMessage, sourceText, runtimeType, occurrence);
+}
+
+static String invalidParameterInstanceofhasInstanceValueNotFunctionSourceAppender(const String& originalMessage, const String& sourceText, RuntimeType runtimeType, ErrorInstance::SourceTextWhereErrorOccurred occurrence)
+{
+ return invalidParameterInstanceofSourceAppender(WTF::makeString("[Symbol.hasInstance] is not a function, undefined, or null"), originalMessage, sourceText, runtimeType, occurrence);
+}
+
+JSObject* createError(ExecState* exec, JSValue value, const String& message, ErrorInstance::SourceAppender appender)
+{
+ String errorMessage = makeString(errorDescriptionForValue(exec, value)->value(exec), ' ', message);
+ JSObject* exception = createTypeError(exec, errorMessage, appender, runtimeTypeForValue(value));
+ ASSERT(exception->isErrorInstance());
+ return exception;
+}
+
+JSObject* createInvalidFunctionApplyParameterError(ExecState* exec, JSValue value)
+{
+ JSObject* exception = createTypeError(exec, makeString("second argument to Function.prototype.apply must be an Array-like object"), defaultSourceAppender, runtimeTypeForValue(value));
ASSERT(exception->isErrorInstance());
- static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage();
return exception;
}
-JSObject* createInvalidParameterError(ExecState* exec, const char* op, JSValue value)
+JSObject* createInvalidInParameterError(ExecState* exec, JSValue value)
{
- return createError(exec, createTypeError, value, makeString("is not a valid argument for '", op, "'"));
+ return createError(exec, value, makeString("is not an Object."), invalidParameterInSourceAppender);
+}
+
+JSObject* createInvalidInstanceofParameterErrorNotFunction(ExecState* exec, JSValue value)
+{
+ return createError(exec, value, makeString(" is not a function"), invalidParameterInstanceofNotFunctionSourceAppender);
+}
+
+JSObject* createInvalidInstanceofParameterErrorhasInstanceValueNotFunction(ExecState* exec, JSValue value)
+{
+ return createError(exec, value, makeString("[Symbol.hasInstance] is not a function, undefined, or null"), invalidParameterInstanceofhasInstanceValueNotFunctionSourceAppender);
}
JSObject* createNotAConstructorError(ExecState* exec, JSValue value)
{
- return createError(exec, createTypeError, value, "is not a constructor");
+ return createError(exec, value, ASCIILiteral("is not a constructor"), defaultSourceAppender);
}
JSObject* createNotAFunctionError(ExecState* exec, JSValue value)
{
- return createError(exec, createTypeError, value, "is not a function");
+ return createError(exec, value, ASCIILiteral("is not a function"), notAFunctionSourceAppender);
}
JSObject* createNotAnObjectError(ExecState* exec, JSValue value)
{
- return createError(exec, createTypeError, value, "is not an object");
+ return createError(exec, value, ASCIILiteral("is not an object"), defaultSourceAppender);
}
JSObject* createErrorForInvalidGlobalAssignment(ExecState* exec, const String& propertyName)
{
- return createReferenceError(exec, makeString("Strict mode forbids implicit creation of global property '", propertyName, "'"));
+ return createReferenceError(exec, makeString("Strict mode forbids implicit creation of global property '", propertyName, '\''));
}
-JSObject* createOutOfMemoryError(JSGlobalObject* globalObject)
+JSObject* createTDZError(ExecState* exec)
{
- return createError(globalObject, ASCIILiteral("Out of memory"));
+ return createReferenceError(exec, "Cannot access uninitialized variable.");
}
JSObject* throwOutOfMemoryError(ExecState* exec)
{
- return exec->vm().throwException(exec, createOutOfMemoryError(exec->lexicalGlobalObject()));
+ return exec->vm().throwException(exec, createOutOfMemoryError(exec));
}
JSObject* throwStackOverflowError(ExecState* exec)
{
- Interpreter::ErrorHandlingMode mode(exec);
- return exec->vm().throwException(exec, createStackOverflowError(exec));
+ VM& vm = exec->vm();
+ ErrorHandlingScope errorScope(vm);
+ return vm.throwException(exec, createStackOverflowError(exec));
}
JSObject* throwTerminatedExecutionException(ExecState* exec)
{
- Interpreter::ErrorHandlingMode mode(exec);
- return exec->vm().throwException(exec, createTerminatedExecutionException(&exec->vm()));
+ VM& vm = exec->vm();
+ ErrorHandlingScope errorScope(vm);
+ return vm.throwException(exec, createTerminatedExecutionException(&vm));
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.h b/Source/JavaScriptCore/runtime/ExceptionHelpers.h
index 0c3fcf2d5..54c5d7096 100644
--- a/Source/JavaScriptCore/runtime/ExceptionHelpers.h
+++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.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.
*
@@ -29,43 +29,38 @@
#ifndef ExceptionHelpers_h
#define ExceptionHelpers_h
+#include "ErrorInstance.h"
#include "JSObject.h"
namespace JSC {
-typedef JSObject* (*ErrorFactory)(ExecState*, const String&);
+typedef JSObject* (*ErrorFactory)(ExecState*, const String&, ErrorInstance::SourceAppender);
JSObject* createTerminatedExecutionException(VM*);
-bool isTerminatedExecutionException(JSObject*);
-JS_EXPORT_PRIVATE bool isTerminatedExecutionException(JSValue);
-JS_EXPORT_PRIVATE JSObject* createError(ExecState*, ErrorFactory, JSValue, const String&);
+JS_EXPORT_PRIVATE bool isTerminatedExecutionException(Exception*);
+JS_EXPORT_PRIVATE JSObject* createError(ExecState*, JSValue, const String&, ErrorInstance::SourceAppender);
JS_EXPORT_PRIVATE JSObject* createStackOverflowError(ExecState*);
-JSObject* createStackOverflowError(JSGlobalObject*);
-JSObject* createOutOfMemoryError(JSGlobalObject*);
JSObject* createUndefinedVariableError(ExecState*, const Identifier&);
+JSObject* createTDZError(ExecState*);
JSObject* createNotAnObjectError(ExecState*, JSValue);
-JSObject* createInvalidParameterError(ExecState*, const char* op, JSValue);
+JSObject* createInvalidFunctionApplyParameterError(ExecState*, JSValue);
+JSObject* createInvalidInParameterError(ExecState*, JSValue);
+JSObject* createInvalidInstanceofParameterErrorNotFunction(ExecState*, JSValue);
+JSObject* createInvalidInstanceofParameterErrorhasInstanceValueNotFunction(ExecState*, JSValue);
JSObject* createNotAConstructorError(ExecState*, JSValue);
JSObject* createNotAFunctionError(ExecState*, JSValue);
JSObject* createErrorForInvalidGlobalAssignment(ExecState*, const String&);
JSString* errorDescriptionForValue(ExecState*, JSValue);
-JSObject* throwOutOfMemoryError(ExecState*);
-JSObject* throwStackOverflowError(ExecState*);
-JSObject* throwTerminatedExecutionException(ExecState*);
+JS_EXPORT_PRIVATE JSObject* throwOutOfMemoryError(ExecState*);
+JS_EXPORT_PRIVATE JSObject* throwStackOverflowError(ExecState*);
+JS_EXPORT_PRIVATE JSObject* throwTerminatedExecutionException(ExecState*);
-class TerminatedExecutionError : public JSNonFinalObject {
-private:
- TerminatedExecutionError(VM& vm)
- : JSNonFinalObject(vm, vm.terminatedExecutionErrorStructure.get())
- {
- }
-
- static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
-
+class TerminatedExecutionError final : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
static TerminatedExecutionError* create(VM& vm)
{
@@ -80,6 +75,15 @@ public:
}
DECLARE_EXPORT_INFO;
+
+private:
+ explicit TerminatedExecutionError(VM& vm)
+ : JSNonFinalObject(vm, vm.terminatedExecutionErrorStructure.get())
+ {
+ }
+
+ static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
+
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp
index bbd6ed23e..8a55026e2 100644
--- a/Source/JavaScriptCore/runtime/Executable.cpp
+++ b/Source/JavaScriptCore/runtime/Executable.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009, 2010, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010, 2013, 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
@@ -27,37 +27,78 @@
#include "Executable.h"
#include "BatchedTransitionOptimizer.h"
-#include "BytecodeGenerator.h"
#include "CodeBlock.h"
#include "DFGDriver.h"
#include "JIT.h"
+#include "JSCInlines.h"
+#include "JSWASMModule.h"
#include "LLIntEntrypoint.h"
-#include "Operations.h"
#include "Parser.h"
+#include "ProfilerDatabase.h"
+#include "TypeProfiler.h"
+#include "WASMFunctionParser.h"
+#include <wtf/CommaPrinter.h>
#include <wtf/Vector.h>
#include <wtf/text/StringBuilder.h>
namespace JSC {
-const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0, CREATE_METHOD_TABLE(ExecutableBase) };
+const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, CREATE_METHOD_TABLE(ExecutableBase) };
-#if ENABLE(JIT)
void ExecutableBase::destroy(JSCell* cell)
{
static_cast<ExecutableBase*>(cell)->ExecutableBase::~ExecutableBase();
}
-#endif
void ExecutableBase::clearCode()
{
#if ENABLE(JIT)
- m_jitCodeForCall.clear();
- m_jitCodeForConstruct.clear();
+ m_jitCodeForCall = nullptr;
+ m_jitCodeForConstruct = nullptr;
m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr();
m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr();
#endif
m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED;
m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED;
+
+ if (classInfo() == FunctionExecutable::info()) {
+ FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
+ executable->m_codeBlockForCall.clear();
+ executable->m_codeBlockForConstruct.clear();
+ return;
+ }
+
+ if (classInfo() == EvalExecutable::info()) {
+ EvalExecutable* executable = jsCast<EvalExecutable*>(this);
+ executable->m_evalCodeBlock.clear();
+ executable->m_unlinkedEvalCodeBlock.clear();
+ return;
+ }
+
+ if (classInfo() == ProgramExecutable::info()) {
+ ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
+ executable->m_programCodeBlock.clear();
+ executable->m_unlinkedProgramCodeBlock.clear();
+ return;
+ }
+
+ if (classInfo() == ModuleProgramExecutable::info()) {
+ ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
+ executable->m_moduleProgramCodeBlock.clear();
+ executable->m_unlinkedModuleProgramCodeBlock.clear();
+ executable->m_moduleEnvironmentSymbolTable.clear();
+ return;
+ }
+
+#if ENABLE(WEBASSEMBLY)
+ if (classInfo() == WebAssemblyExecutable::info()) {
+ WebAssemblyExecutable* executable = jsCast<WebAssemblyExecutable*>(this);
+ executable->m_codeBlockForCall.clear();
+ return;
+ }
+#endif
+
+ ASSERT(classInfo() == NativeExecutable::info());
}
#if ENABLE(DFG_JIT)
@@ -74,14 +115,12 @@ Intrinsic ExecutableBase::intrinsic() const
}
#endif
-const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(NativeExecutable) };
+const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(NativeExecutable) };
-#if ENABLE(JIT)
void NativeExecutable::destroy(JSCell* cell)
{
static_cast<NativeExecutable*>(cell)->NativeExecutable::~NativeExecutable();
}
-#endif
#if ENABLE(DFG_JIT)
Intrinsic NativeExecutable::intrinsic() const
@@ -90,66 +129,75 @@ Intrinsic NativeExecutable::intrinsic() const
}
#endif
-const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) };
+const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(ScriptExecutable) };
+
+ScriptExecutable::ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext, DerivedContextType derivedContextType, bool isInArrowFunctionContext)
+ : ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED)
+ , m_features(isInStrictContext ? StrictModeFeature : 0)
+ , m_didTryToEnterInLoop(false)
+ , m_hasCapturedVariables(false)
+ , m_neverInline(false)
+ , m_neverOptimize(false)
+ , m_isArrowFunctionContext(isInArrowFunctionContext)
+ , m_derivedContextType(static_cast<unsigned>(derivedContextType))
+ , m_overrideLineNumber(-1)
+ , m_firstLine(-1)
+ , m_lastLine(-1)
+ , m_startColumn(UINT_MAX)
+ , m_endColumn(UINT_MAX)
+ , m_typeProfilingStartOffset(UINT_MAX)
+ , m_typeProfilingEndOffset(UINT_MAX)
+ , m_source(source)
+{
+}
-#if ENABLE(JIT)
void ScriptExecutable::destroy(JSCell* cell)
{
static_cast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable();
}
-#endif
-void ScriptExecutable::installCode(CodeBlock* genericCodeBlock)
+void ScriptExecutable::installCode(CodeBlock* codeBlock)
+{
+ installCode(*codeBlock->vm(), codeBlock, codeBlock->codeType(), codeBlock->specializationKind());
+}
+
+void ScriptExecutable::installCode(VM& vm, CodeBlock* genericCodeBlock, CodeType codeType, CodeSpecializationKind kind)
{
- RELEASE_ASSERT(genericCodeBlock->ownerExecutable() == this);
- RELEASE_ASSERT(JITCode::isExecutableScript(genericCodeBlock->jitType()));
-
- VM& vm = *genericCodeBlock->vm();
-
- if (vm.m_perBytecodeProfiler)
- vm.m_perBytecodeProfiler->ensureBytecodesFor(genericCodeBlock);
-
ASSERT(vm.heap.isDeferred());
- CodeSpecializationKind kind = genericCodeBlock->specializationKind();
-
- RefPtr<CodeBlock> oldCodeBlock;
+ CodeBlock* oldCodeBlock = nullptr;
- switch (kind) {
- case CodeForCall:
- m_jitCodeForCall = genericCodeBlock->jitCode();
- m_jitCodeForCallWithArityCheck = genericCodeBlock->jitCodeWithArityCheck();
- m_numParametersForCall = genericCodeBlock->numParameters();
- break;
- case CodeForConstruct:
- m_jitCodeForConstruct = genericCodeBlock->jitCode();
- m_jitCodeForConstructWithArityCheck = genericCodeBlock->jitCodeWithArityCheck();
- m_numParametersForConstruct = genericCodeBlock->numParameters();
- break;
- }
-
- switch (genericCodeBlock->codeType()) {
+ switch (codeType) {
case GlobalCode: {
ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
ProgramCodeBlock* codeBlock = static_cast<ProgramCodeBlock*>(genericCodeBlock);
- ASSERT(!codeBlock->jitCodeWithArityCheck());
ASSERT(kind == CodeForCall);
- oldCodeBlock = executable->m_programCodeBlock;
- executable->m_programCodeBlock = codeBlock;
+ oldCodeBlock = executable->m_programCodeBlock.get();
+ executable->m_programCodeBlock.setMayBeNull(vm, this, codeBlock);
break;
}
-
+
+ case ModuleCode: {
+ ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
+ ModuleProgramCodeBlock* codeBlock = static_cast<ModuleProgramCodeBlock*>(genericCodeBlock);
+
+ ASSERT(kind == CodeForCall);
+
+ oldCodeBlock = executable->m_moduleProgramCodeBlock.get();
+ executable->m_moduleProgramCodeBlock.setMayBeNull(vm, this, codeBlock);
+ break;
+ }
+
case EvalCode: {
EvalExecutable* executable = jsCast<EvalExecutable*>(this);
EvalCodeBlock* codeBlock = static_cast<EvalCodeBlock*>(genericCodeBlock);
- ASSERT(!codeBlock->jitCodeWithArityCheck());
ASSERT(kind == CodeForCall);
- oldCodeBlock = executable->m_evalCodeBlock;
- executable->m_evalCodeBlock = codeBlock;
+ oldCodeBlock = executable->m_evalCodeBlock.get();
+ executable->m_evalCodeBlock.setMayBeNull(vm, this, codeBlock);
break;
}
@@ -159,27 +207,53 @@ void ScriptExecutable::installCode(CodeBlock* genericCodeBlock)
switch (kind) {
case CodeForCall:
- oldCodeBlock = executable->m_codeBlockForCall;
- executable->m_codeBlockForCall = codeBlock;
+ oldCodeBlock = executable->m_codeBlockForCall.get();
+ executable->m_codeBlockForCall.setMayBeNull(vm, this, codeBlock);
break;
case CodeForConstruct:
- oldCodeBlock = executable->m_codeBlockForConstruct;
- executable->m_codeBlockForConstruct = codeBlock;
+ oldCodeBlock = executable->m_codeBlockForConstruct.get();
+ executable->m_codeBlockForConstruct.setMayBeNull(vm, this, codeBlock);
break;
}
break;
- } }
+ }
+ }
+
+ switch (kind) {
+ case CodeForCall:
+ m_jitCodeForCall = genericCodeBlock ? genericCodeBlock->jitCode() : nullptr;
+ m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr();
+ m_numParametersForCall = genericCodeBlock ? genericCodeBlock->numParameters() : NUM_PARAMETERS_NOT_COMPILED;
+ break;
+ case CodeForConstruct:
+ m_jitCodeForConstruct = genericCodeBlock ? genericCodeBlock->jitCode() : nullptr;
+ m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr();
+ m_numParametersForConstruct = genericCodeBlock ? genericCodeBlock->numParameters() : NUM_PARAMETERS_NOT_COMPILED;
+ break;
+ }
+
+ if (genericCodeBlock) {
+ RELEASE_ASSERT(genericCodeBlock->ownerExecutable() == this);
+ RELEASE_ASSERT(JITCode::isExecutableScript(genericCodeBlock->jitType()));
+
+ if (Options::verboseOSR())
+ dataLog("Installing ", *genericCodeBlock, "\n");
+
+ if (vm.m_perBytecodeProfiler)
+ vm.m_perBytecodeProfiler->ensureBytecodesFor(genericCodeBlock);
+
+ if (Debugger* debugger = genericCodeBlock->globalObject()->debugger())
+ debugger->registerCodeBlock(genericCodeBlock);
+ }
if (oldCodeBlock)
oldCodeBlock->unlinkIncomingCalls();
- Debugger* debugger = genericCodeBlock->globalObject()->debugger();
- if (debugger)
- debugger->registerCodeBlock(genericCodeBlock);
+ vm.heap.writeBarrier(this);
}
-PassRefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor(
- CodeSpecializationKind kind, JSScope* scope, JSObject*& exception)
+CodeBlock* ScriptExecutable::newCodeBlockFor(
+ CodeSpecializationKind kind, JSFunction* function, JSScope* scope, JSObject*& exception)
{
VM* vm = scope->vm();
@@ -191,47 +265,64 @@ PassRefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor(
EvalExecutable* executable = jsCast<EvalExecutable*>(this);
RELEASE_ASSERT(kind == CodeForCall);
RELEASE_ASSERT(!executable->m_evalCodeBlock);
- return adoptRef(new EvalCodeBlock(
+ RELEASE_ASSERT(!function);
+ return EvalCodeBlock::create(vm,
executable, executable->m_unlinkedEvalCodeBlock.get(), scope,
- executable->source().provider()));
+ executable->source().provider());
}
if (classInfo() == ProgramExecutable::info()) {
ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
RELEASE_ASSERT(kind == CodeForCall);
RELEASE_ASSERT(!executable->m_programCodeBlock);
- return adoptRef(new ProgramCodeBlock(
+ RELEASE_ASSERT(!function);
+ return ProgramCodeBlock::create(vm,
executable, executable->m_unlinkedProgramCodeBlock.get(), scope,
- executable->source().provider(), executable->source().startColumn()));
+ executable->source().provider(), executable->source().startColumn());
}
-
+
+ if (classInfo() == ModuleProgramExecutable::info()) {
+ ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
+ RELEASE_ASSERT(kind == CodeForCall);
+ RELEASE_ASSERT(!executable->m_moduleProgramCodeBlock);
+ RELEASE_ASSERT(!function);
+ return ModuleProgramCodeBlock::create(vm,
+ executable, executable->m_unlinkedModuleProgramCodeBlock.get(), scope,
+ executable->source().provider(), executable->source().startColumn());
+ }
+
RELEASE_ASSERT(classInfo() == FunctionExecutable::info());
+ RELEASE_ASSERT(function);
FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
RELEASE_ASSERT(!executable->codeBlockFor(kind));
JSGlobalObject* globalObject = scope->globalObject();
ParserError error;
DebuggerMode debuggerMode = globalObject->hasDebugger() ? DebuggerOn : DebuggerOff;
- ProfilerMode profilerMode = globalObject->hasProfiler() ? ProfilerOn : ProfilerOff;
- UnlinkedFunctionCodeBlock* unlinkedCodeBlock =
- executable->m_unlinkedExecutable->codeBlockFor(
- *vm, executable->m_source, kind, debuggerMode, profilerMode, error);
- recordParse(executable->m_unlinkedExecutable->features(), executable->m_unlinkedExecutable->hasCapturedVariables(), lineNo(), lastLine(), startColumn(), endColumn());
+ ProfilerMode profilerMode = globalObject->hasLegacyProfiler() ? ProfilerOn : ProfilerOff;
+ UnlinkedFunctionCodeBlock* unlinkedCodeBlock =
+ executable->m_unlinkedExecutable->unlinkedCodeBlockFor(
+ *vm, executable->m_source, kind, debuggerMode, profilerMode, error,
+ executable->parseMode());
+ recordParse(
+ executable->m_unlinkedExecutable->features(),
+ executable->m_unlinkedExecutable->hasCapturedVariables(), firstLine(),
+ lastLine(), startColumn(), endColumn());
if (!unlinkedCodeBlock) {
exception = vm->throwException(
globalObject->globalExec(),
error.toErrorObject(globalObject, executable->m_source));
- return 0;
+ return nullptr;
}
-
+
SourceProvider* provider = executable->source().provider();
unsigned sourceOffset = executable->source().startOffset();
unsigned startColumn = executable->source().startColumn();
- return adoptRef(new FunctionCodeBlock(
- executable, unlinkedCodeBlock, scope, provider, sourceOffset, startColumn));
+ return FunctionCodeBlock::create(vm,
+ executable, unlinkedCodeBlock, scope, provider, sourceOffset, startColumn);
}
-PassRefPtr<CodeBlock> ScriptExecutable::newReplacementCodeBlockFor(
+CodeBlock* ScriptExecutable::newReplacementCodeBlockFor(
CodeSpecializationKind kind)
{
if (classInfo() == EvalExecutable::info()) {
@@ -239,9 +330,9 @@ PassRefPtr<CodeBlock> ScriptExecutable::newReplacementCodeBlockFor(
EvalExecutable* executable = jsCast<EvalExecutable*>(this);
EvalCodeBlock* baseline = static_cast<EvalCodeBlock*>(
executable->m_evalCodeBlock->baselineVersion());
- RefPtr<EvalCodeBlock> result = adoptRef(new EvalCodeBlock(
- CodeBlock::CopyParsedBlock, *baseline));
- result->setAlternative(baseline);
+ EvalCodeBlock* result = EvalCodeBlock::create(vm(),
+ CodeBlock::CopyParsedBlock, *baseline);
+ result->setAlternative(*vm(), baseline);
return result;
}
@@ -250,9 +341,20 @@ PassRefPtr<CodeBlock> ScriptExecutable::newReplacementCodeBlockFor(
ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
ProgramCodeBlock* baseline = static_cast<ProgramCodeBlock*>(
executable->m_programCodeBlock->baselineVersion());
- RefPtr<ProgramCodeBlock> result = adoptRef(new ProgramCodeBlock(
- CodeBlock::CopyParsedBlock, *baseline));
- result->setAlternative(baseline);
+ ProgramCodeBlock* result = ProgramCodeBlock::create(vm(),
+ CodeBlock::CopyParsedBlock, *baseline);
+ result->setAlternative(*vm(), baseline);
+ return result;
+ }
+
+ if (classInfo() == ModuleProgramExecutable::info()) {
+ RELEASE_ASSERT(kind == CodeForCall);
+ ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
+ ModuleProgramCodeBlock* baseline = static_cast<ModuleProgramCodeBlock*>(
+ executable->m_moduleProgramCodeBlock->baselineVersion());
+ ModuleProgramCodeBlock* result = ModuleProgramCodeBlock::create(vm(),
+ CodeBlock::CopyParsedBlock, *baseline);
+ result->setAlternative(*vm(), baseline);
return result;
}
@@ -260,21 +362,15 @@ PassRefPtr<CodeBlock> ScriptExecutable::newReplacementCodeBlockFor(
FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
FunctionCodeBlock* baseline = static_cast<FunctionCodeBlock*>(
executable->codeBlockFor(kind)->baselineVersion());
- RefPtr<FunctionCodeBlock> result = adoptRef(new FunctionCodeBlock(
- CodeBlock::CopyParsedBlock, *baseline));
- result->setAlternative(baseline);
+ FunctionCodeBlock* result = FunctionCodeBlock::create(vm(),
+ CodeBlock::CopyParsedBlock, *baseline);
+ result->setAlternative(*vm(), baseline);
return result;
}
static void setupLLInt(VM& vm, CodeBlock* codeBlock)
{
-#if ENABLE(LLINT)
LLInt::setEntrypoint(vm, codeBlock);
-#else
- UNUSED_PARAM(vm);
- UNUSED_PARAM(codeBlock);
- UNREACHABLE_FOR_PLATFORM();
-#endif
}
static void setupJIT(VM& vm, CodeBlock* codeBlock)
@@ -290,13 +386,16 @@ static void setupJIT(VM& vm, CodeBlock* codeBlock)
}
JSObject* ScriptExecutable::prepareForExecutionImpl(
- ExecState* exec, JSScope* scope, CodeSpecializationKind kind)
+ ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind)
{
VM& vm = exec->vm();
DeferGC deferGC(vm.heap);
-
+
+ if (vm.getAndClearFailNextNewCodeBlock())
+ return createError(exec->callerFrame(), ASCIILiteral("Forced Failure"));
+
JSObject* exception = 0;
- RefPtr<CodeBlock> codeBlock = newCodeBlockFor(kind, scope, exception);
+ CodeBlock* codeBlock = newCodeBlockFor(kind, function, scope, exception);
if (!codeBlock) {
RELEASE_ASSERT(exception);
return exception;
@@ -305,29 +404,18 @@ JSObject* ScriptExecutable::prepareForExecutionImpl(
if (Options::validateBytecode())
codeBlock->validate();
- bool shouldUseLLInt;
-#if !ENABLE(JIT)
- // No JIT implies use of the C Loop LLINT. Override the options to reflect this.
- Options::useLLInt() = true;
- shouldUseLLInt = true;
-#elif ENABLE(LLINT)
- shouldUseLLInt = Options::useLLInt();
-#else
- shouldUseLLInt = false;
-#endif
-
- if (shouldUseLLInt)
- setupLLInt(vm, codeBlock.get());
+ if (Options::useLLInt())
+ setupLLInt(vm, codeBlock);
else
- setupJIT(vm, codeBlock.get());
+ setupJIT(vm, codeBlock);
- installCode(codeBlock.get());
+ installCode(*codeBlock->vm(), codeBlock, codeBlock->codeType(), codeBlock->specializationKind());
return 0;
}
-const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(EvalExecutable) };
+const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(EvalExecutable) };
-EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext)
+EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext, ThisTDZMode thisTDZMode, DerivedContextType derivedContextType, bool isArrowFunctionContext, const VariableEnvironment* variablesUnderTDZ)
{
JSGlobalObject* globalObject = exec->lexicalGlobalObject();
if (!globalObject->evalEnabled()) {
@@ -335,10 +423,10 @@ EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source
return 0;
}
- EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext);
+ EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext, derivedContextType, isArrowFunctionContext);
executable->finishCreation(exec->vm());
- UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable);
+ UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable, thisTDZMode, isArrowFunctionContext, variablesUnderTDZ);
if (!unlinkedEvalCode)
return 0;
@@ -347,8 +435,8 @@ EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source
return executable;
}
-EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext)
- : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec, source, inStrictContext)
+EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext, DerivedContextType derivedContextType, bool isArrowFunctionContext)
+ : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec->vm(), source, inStrictContext, derivedContextType, isArrowFunctionContext)
{
}
@@ -357,11 +445,15 @@ void EvalExecutable::destroy(JSCell* cell)
static_cast<EvalExecutable*>(cell)->EvalExecutable::~EvalExecutable();
}
-const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(ProgramExecutable) };
+const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(ProgramExecutable) };
ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source)
- : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec, source, false)
+ : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec->vm(), source, false, DerivedContextType::None, false)
{
+ m_typeProfilingStartOffset = 0;
+ m_typeProfilingEndOffset = source.length() - 1;
+ if (exec->vm().typeProfiler() || exec->vm().controlFlowProfiler())
+ exec->vm().functionHasExecutedCache()->insertUnexecutedRange(sourceID(), m_typeProfilingStartOffset, m_typeProfilingEndOffset);
}
void ProgramExecutable::destroy(JSCell* cell)
@@ -369,12 +461,43 @@ void ProgramExecutable::destroy(JSCell* cell)
static_cast<ProgramExecutable*>(cell)->ProgramExecutable::~ProgramExecutable();
}
-const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) };
+const ClassInfo ModuleProgramExecutable::s_info = { "ModuleProgramExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(ModuleProgramExecutable) };
+
+ModuleProgramExecutable::ModuleProgramExecutable(ExecState* exec, const SourceCode& source)
+ : ScriptExecutable(exec->vm().moduleProgramExecutableStructure.get(), exec->vm(), source, false, DerivedContextType::None, false)
+{
+ m_typeProfilingStartOffset = 0;
+ m_typeProfilingEndOffset = source.length() - 1;
+ if (exec->vm().typeProfiler() || exec->vm().controlFlowProfiler())
+ exec->vm().functionHasExecutedCache()->insertUnexecutedRange(sourceID(), m_typeProfilingStartOffset, m_typeProfilingEndOffset);
+}
+
+ModuleProgramExecutable* ModuleProgramExecutable::create(ExecState* exec, const SourceCode& source)
+{
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ ModuleProgramExecutable* executable = new (NotNull, allocateCell<ModuleProgramExecutable>(*exec->heap())) ModuleProgramExecutable(exec, source);
+ executable->finishCreation(exec->vm());
+
+ UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCode = globalObject->createModuleProgramCodeBlock(exec, executable);
+ if (!unlinkedModuleProgramCode)
+ return nullptr;
+ executable->m_unlinkedModuleProgramCodeBlock.set(exec->vm(), executable, unlinkedModuleProgramCode);
-FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn, bool bodyIncludesBraces)
- : ScriptExecutable(vm.functionExecutableStructure.get(), vm, source, unlinkedExecutable->isInStrictContext())
+ executable->m_moduleEnvironmentSymbolTable.set(exec->vm(), executable, jsCast<SymbolTable*>(unlinkedModuleProgramCode->constantRegister(unlinkedModuleProgramCode->moduleEnvironmentSymbolTableConstantRegisterOffset()).get())->cloneScopePart(exec->vm()));
+
+ return executable;
+}
+
+void ModuleProgramExecutable::destroy(JSCell* cell)
+{
+ static_cast<ModuleProgramExecutable*>(cell)->ModuleProgramExecutable::~ModuleProgramExecutable();
+}
+
+const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(FunctionExecutable) };
+
+FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn)
+ : ScriptExecutable(vm.functionExecutableStructure.get(), vm, source, unlinkedExecutable->isInStrictContext(), unlinkedExecutable->derivedContextType(), false)
, m_unlinkedExecutable(vm, this, unlinkedExecutable)
- , m_bodyIncludesBraces(bodyIncludesBraces)
{
RELEASE_ASSERT(!source.isNull());
ASSERT(source.length());
@@ -384,6 +507,15 @@ FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, Unlinke
ASSERT(endColumn != UINT_MAX);
m_startColumn = startColumn;
m_endColumn = endColumn;
+ m_parametersStartOffset = unlinkedExecutable->parametersStartOffset();
+ m_typeProfilingStartOffset = unlinkedExecutable->typeProfilingStartOffset();
+ m_typeProfilingEndOffset = unlinkedExecutable->typeProfilingEndOffset();
+}
+
+void FunctionExecutable::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ m_singletonFunction.set(vm, this, InferredValue::create(vm));
}
void FunctionExecutable::destroy(JSCell* cell)
@@ -412,29 +544,10 @@ void EvalExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
EvalExecutable* thisObject = jsCast<EvalExecutable*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
ScriptExecutable::visitChildren(thisObject, visitor);
- if (thisObject->m_evalCodeBlock)
- thisObject->m_evalCodeBlock->visitAggregate(visitor);
visitor.append(&thisObject->m_unlinkedEvalCodeBlock);
-}
-
-void EvalExecutable::unlinkCalls()
-{
-#if ENABLE(JIT)
- if (!m_jitCodeForCall)
- return;
- RELEASE_ASSERT(m_evalCodeBlock);
- m_evalCodeBlock->unlinkCalls();
-#endif
-}
-
-void EvalExecutable::clearCode()
-{
- m_evalCodeBlock.clear();
- m_unlinkedEvalCodeBlock.clear();
- Base::clearCode();
+ if (thisObject->m_evalCodeBlock)
+ thisObject->m_evalCodeBlock->visitWeakly(visitor);
}
JSObject* ProgramExecutable::checkSyntax(ExecState* exec)
@@ -442,23 +555,15 @@ JSObject* ProgramExecutable::checkSyntax(ExecState* exec)
ParserError error;
VM* vm = &exec->vm();
JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
- RefPtr<ProgramNode> programNode = parse<ProgramNode>(vm, m_source, 0, Identifier(), JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, error);
+ std::unique_ptr<ProgramNode> programNode = parse<ProgramNode>(
+ vm, m_source, Identifier(), JSParserBuiltinMode::NotBuiltin,
+ JSParserStrictMode::NotStrict, SourceParseMode::ProgramMode, SuperBinding::NotNeeded, error);
if (programNode)
return 0;
- ASSERT(error.m_type != ParserError::ErrorNone);
+ ASSERT(error.isValid());
return error.toErrorObject(lexicalGlobalObject, m_source);
}
-void ProgramExecutable::unlinkCalls()
-{
-#if ENABLE(JIT)
- if (!m_jitCodeForCall)
- return;
- RELEASE_ASSERT(m_programCodeBlock);
- m_programCodeBlock->unlinkCalls();
-#endif
-}
-
JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callFrame, JSScope* scope)
{
RELEASE_ASSERT(scope);
@@ -471,24 +576,73 @@ JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callF
if (exception)
return exception;
+ JSGlobalLexicalEnvironment* globalLexicalEnvironment = globalObject->globalLexicalEnvironment();
+ const VariableEnvironment& variableDeclarations = unlinkedCodeBlock->variableDeclarations();
+ const VariableEnvironment& lexicalDeclarations = unlinkedCodeBlock->lexicalDeclarations();
+ // The ES6 spec says that no vars/global properties/let/const can be duplicated in the global scope.
+ // This carried out section 15.1.8 of the ES6 spec: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-globaldeclarationinstantiation
+ {
+ ExecState* exec = globalObject->globalExec();
+ // Check for intersection of "var" and "let"/"const"/"class"
+ for (auto& entry : lexicalDeclarations) {
+ if (variableDeclarations.contains(entry.key))
+ return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'"));
+ }
+
+ // Check if any new "let"/"const"/"class" will shadow any pre-existing global property names, or "var"/"let"/"const" variables.
+ // It's an error to introduce a shadow.
+ for (auto& entry : lexicalDeclarations) {
+ if (globalObject->hasProperty(exec, entry.key.get()))
+ return createSyntaxError(exec, makeString("Can't create duplicate variable that shadows a global property: '", String(entry.key.get()), "'"));
+
+ if (globalLexicalEnvironment->hasProperty(exec, entry.key.get()))
+ return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'"));
+ }
+
+ // Check if any new "var"s will shadow any previous "let"/"const"/"class" names.
+ // It's an error to introduce a shadow.
+ if (!globalLexicalEnvironment->isEmpty()) {
+ for (auto& entry : variableDeclarations) {
+ if (globalLexicalEnvironment->hasProperty(exec, entry.key.get()))
+ return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'"));
+ }
+ }
+ }
+
+
m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCodeBlock);
BatchedTransitionOptimizer optimizer(vm, globalObject);
- const UnlinkedProgramCodeBlock::VariableDeclations& variableDeclarations = unlinkedCodeBlock->variableDeclarations();
- const UnlinkedProgramCodeBlock::FunctionDeclations& functionDeclarations = unlinkedCodeBlock->functionDeclarations();
+ for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) {
+ UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i);
+ ASSERT(!unlinkedFunctionExecutable->name().isEmpty());
+ globalObject->addFunction(callFrame, unlinkedFunctionExecutable->name());
+ if (vm.typeProfiler() || vm.controlFlowProfiler()) {
+ vm.functionHasExecutedCache()->insertUnexecutedRange(sourceID(),
+ unlinkedFunctionExecutable->typeProfilingStartOffset(),
+ unlinkedFunctionExecutable->typeProfilingEndOffset());
+ }
+ }
- for (size_t i = 0; i < functionDeclarations.size(); ++i) {
- UnlinkedFunctionExecutable* unlinkedFunctionExecutable = functionDeclarations[i].second.get();
- JSValue value = JSFunction::create(vm, unlinkedFunctionExecutable->link(vm, m_source, lineNo(), 0), scope);
- globalObject->addFunction(callFrame, functionDeclarations[i].first, value);
+ for (auto& entry : variableDeclarations) {
+ ASSERT(entry.value.isVar());
+ globalObject->addVar(callFrame, Identifier::fromUid(&vm, entry.key.get()));
}
- for (size_t i = 0; i < variableDeclarations.size(); ++i) {
- if (variableDeclarations[i].second & DeclarationStacks::IsConstant)
- globalObject->addConst(callFrame, variableDeclarations[i].first);
- else
- globalObject->addVar(callFrame, variableDeclarations[i].first);
+ {
+ JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(globalObject->globalScope());
+ SymbolTable* symbolTable = globalLexicalEnvironment->symbolTable();
+ ConcurrentJITLocker locker(symbolTable->m_lock);
+ for (auto& entry : lexicalDeclarations) {
+ ScopeOffset offset = symbolTable->takeNextScopeOffset(locker);
+ SymbolTableEntry newEntry(VarOffset(offset), entry.value.isConst() ? ReadOnly : 0);
+ newEntry.prepareToWatch();
+ symbolTable->add(locker, entry.key.get(), newEntry);
+
+ ScopeOffset offsetForAssert = globalLexicalEnvironment->addVariables(1, jsTDZValue());
+ RELEASE_ASSERT(offsetForAssert == offset);
+ }
}
return 0;
}
@@ -497,19 +651,21 @@ void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
ProgramExecutable* thisObject = jsCast<ProgramExecutable*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
ScriptExecutable::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_unlinkedProgramCodeBlock);
if (thisObject->m_programCodeBlock)
- thisObject->m_programCodeBlock->visitAggregate(visitor);
+ thisObject->m_programCodeBlock->visitWeakly(visitor);
}
-void ProgramExecutable::clearCode()
+void ModuleProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
- m_programCodeBlock.clear();
- m_unlinkedProgramCodeBlock.clear();
- Base::clearCode();
+ ModuleProgramExecutable* thisObject = jsCast<ModuleProgramExecutable*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ ScriptExecutable::visitChildren(thisObject, visitor);
+ visitor.append(&thisObject->m_unlinkedModuleProgramCodeBlock);
+ visitor.append(&thisObject->m_moduleEnvironmentSymbolTable);
+ if (thisObject->m_moduleProgramCodeBlock)
+ thisObject->m_moduleProgramCodeBlock->visitWeakly(visitor);
}
FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKind kind)
@@ -530,84 +686,124 @@ void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
FunctionExecutable* thisObject = jsCast<FunctionExecutable*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
ScriptExecutable::visitChildren(thisObject, visitor);
if (thisObject->m_codeBlockForCall)
- thisObject->m_codeBlockForCall->visitAggregate(visitor);
+ thisObject->m_codeBlockForCall->visitWeakly(visitor);
if (thisObject->m_codeBlockForConstruct)
- thisObject->m_codeBlockForConstruct->visitAggregate(visitor);
+ thisObject->m_codeBlockForConstruct->visitWeakly(visitor);
visitor.append(&thisObject->m_unlinkedExecutable);
+ visitor.append(&thisObject->m_singletonFunction);
}
-SymbolTable* FunctionExecutable::symbolTable(CodeSpecializationKind kind)
+FunctionExecutable* FunctionExecutable::fromGlobalCode(
+ const Identifier& name, ExecState& exec, const SourceCode& source,
+ JSObject*& exception, int overrideLineNumber)
{
- return codeBlockFor(kind)->symbolTable();
-}
+ UnlinkedFunctionExecutable* unlinkedExecutable =
+ UnlinkedFunctionExecutable::fromGlobalCode(
+ name, exec, source, exception, overrideLineNumber);
+ if (!unlinkedExecutable)
+ return nullptr;
-void FunctionExecutable::clearCodeIfNotCompiling()
-{
- if (isCompiling())
- return;
- clearCode();
+ return unlinkedExecutable->link(exec.vm(), source, overrideLineNumber);
}
-void FunctionExecutable::clearUnlinkedCodeForRecompilationIfNotCompiling()
+#if ENABLE(WEBASSEMBLY)
+const ClassInfo WebAssemblyExecutable::s_info = { "WebAssemblyExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(WebAssemblyExecutable) };
+
+WebAssemblyExecutable::WebAssemblyExecutable(VM& vm, const SourceCode& source, JSWASMModule* module, unsigned functionIndex)
+ : ExecutableBase(vm, vm.webAssemblyExecutableStructure.get(), NUM_PARAMETERS_NOT_COMPILED)
+ , m_source(source)
+ , m_module(vm, this, module)
+ , m_functionIndex(functionIndex)
{
- if (isCompiling())
- return;
- m_unlinkedExecutable->clearCodeForRecompilation();
}
-void FunctionExecutable::clearCode()
+void WebAssemblyExecutable::destroy(JSCell* cell)
{
- m_codeBlockForCall.clear();
- m_codeBlockForConstruct.clear();
- Base::clearCode();
+ static_cast<WebAssemblyExecutable*>(cell)->WebAssemblyExecutable::~WebAssemblyExecutable();
}
-void FunctionExecutable::unlinkCalls()
+void WebAssemblyExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
-#if ENABLE(JIT)
- if (!!m_jitCodeForCall) {
- RELEASE_ASSERT(m_codeBlockForCall);
- m_codeBlockForCall->unlinkCalls();
- }
- if (!!m_jitCodeForConstruct) {
- RELEASE_ASSERT(m_codeBlockForConstruct);
- m_codeBlockForConstruct->unlinkCalls();
- }
-#endif
+ WebAssemblyExecutable* thisObject = jsCast<WebAssemblyExecutable*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ ExecutableBase::visitChildren(thisObject, visitor);
+ if (thisObject->m_codeBlockForCall)
+ thisObject->m_codeBlockForCall->visitWeakly(visitor);
+ visitor.append(&thisObject->m_module);
}
-FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& name, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception)
+void WebAssemblyExecutable::prepareForExecution(ExecState* exec)
{
- UnlinkedFunctionExecutable* unlinkedExecutable = UnlinkedFunctionExecutable::fromGlobalCode(name, exec, debugger, source, exception);
- if (!unlinkedExecutable)
- return 0;
- unsigned lineCount = unlinkedExecutable->lineCount();
- unsigned firstLine = source.firstLine() + unlinkedExecutable->firstLineOffset();
- unsigned startOffset = source.startOffset() + unlinkedExecutable->startOffset();
+ if (hasJITCodeForCall())
+ return;
+
+ VM& vm = exec->vm();
+ DeferGC deferGC(vm.heap);
+
+ WebAssemblyCodeBlock* codeBlock = WebAssemblyCodeBlock::create(&vm,
+ this, exec->lexicalGlobalObject());
+
+ WASMFunctionParser::compile(vm, codeBlock, m_module.get(), m_source, m_functionIndex);
- // We don't have any owner executable. The source string is effectively like a global
- // string (like in the handling of eval). Hence, the startColumn is always 1.
- unsigned startColumn = 1;
- unsigned sourceLength = unlinkedExecutable->sourceLength();
- bool endColumnIsOnStartLine = !lineCount;
- // The unlinkedBodyEndColumn is based-0. Hence, we need to add 1 to it. But if the
- // endColumn is on the startLine, then we need to subtract back the adjustment for
- // the open brace resulting in an adjustment of 0.
- unsigned endColumnExcludingBraces = unlinkedExecutable->unlinkedBodyEndColumn() + (endColumnIsOnStartLine ? 0 : 1);
- unsigned startOffsetExcludingOpenBrace = startOffset + 1;
- unsigned endOffsetExcludingCloseBrace = startOffset + sourceLength - 1;
- SourceCode bodySource(source.provider(), startOffsetExcludingOpenBrace, endOffsetExcludingCloseBrace, firstLine, startColumn);
+ m_jitCodeForCall = codeBlock->jitCode();
+ m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr();
+ m_numParametersForCall = codeBlock->numParameters();
+
+ m_codeBlockForCall.set(vm, this, codeBlock);
- return FunctionExecutable::create(exec->vm(), bodySource, unlinkedExecutable, firstLine, firstLine + lineCount, startColumn, endColumnExcludingBraces, false);
+ Heap::heap(this)->writeBarrier(this);
}
+#endif
-String FunctionExecutable::paramString() const
+void ExecutableBase::dump(PrintStream& out) const
{
- return m_unlinkedExecutable->paramString();
+ ExecutableBase* realThis = const_cast<ExecutableBase*>(this);
+
+ if (classInfo() == NativeExecutable::info()) {
+ NativeExecutable* native = jsCast<NativeExecutable*>(realThis);
+ out.print("NativeExecutable:", RawPointer(bitwise_cast<void*>(native->function())), "/", RawPointer(bitwise_cast<void*>(native->constructor())));
+ return;
+ }
+
+ if (classInfo() == EvalExecutable::info()) {
+ EvalExecutable* eval = jsCast<EvalExecutable*>(realThis);
+ if (CodeBlock* codeBlock = eval->codeBlock())
+ out.print(*codeBlock);
+ else
+ out.print("EvalExecutable w/o CodeBlock");
+ return;
+ }
+
+ if (classInfo() == ProgramExecutable::info()) {
+ ProgramExecutable* eval = jsCast<ProgramExecutable*>(realThis);
+ if (CodeBlock* codeBlock = eval->codeBlock())
+ out.print(*codeBlock);
+ else
+ out.print("ProgramExecutable w/o CodeBlock");
+ return;
+ }
+
+ if (classInfo() == ModuleProgramExecutable::info()) {
+ ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(realThis);
+ if (CodeBlock* codeBlock = executable->codeBlock())
+ out.print(*codeBlock);
+ else
+ out.print("ModuleProgramExecutable w/o CodeBlock");
+ return;
+ }
+
+ FunctionExecutable* function = jsCast<FunctionExecutable*>(realThis);
+ if (!function->eitherCodeBlock())
+ out.print("FunctionExecutable w/o CodeBlock");
+ else {
+ CommaPrinter comma("/");
+ if (function->codeBlockForCall())
+ out.print(comma, *function->codeBlockForCall());
+ if (function->codeBlockForConstruct())
+ out.print(comma, *function->codeBlockForConstruct());
+ }
}
CodeBlockHash ExecutableBase::hashFor(CodeSpecializationKind kind) const
diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h
index 6ff27aee9..3a3fd8f42 100644
--- a/Source/JavaScriptCore/runtime/Executable.h
+++ b/Source/JavaScriptCore/runtime/Executable.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009, 2010, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2010, 2013-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
@@ -26,20 +26,21 @@
#ifndef Executable_h
#define Executable_h
+#include "ArityCheckMode.h"
#include "CallData.h"
#include "CodeBlockHash.h"
#include "CodeSpecializationKind.h"
#include "CompilationResult.h"
-#include "DFGPlan.h"
+#include "ExecutableInfo.h"
#include "HandlerInfo.h"
-#include "JSFunction.h"
-#include "Interpreter.h"
+#include "InferredValue.h"
#include "JITCode.h"
#include "JSGlobalObject.h"
#include "SamplingTool.h"
#include "SourceCode.h"
+#include "TypeSet.h"
#include "UnlinkedCodeBlock.h"
-#include <wtf/PassOwnPtr.h>
+#include "UnlinkedFunctionExecutable.h"
namespace JSC {
@@ -47,10 +48,17 @@ class CodeBlock;
class Debugger;
class EvalCodeBlock;
class FunctionCodeBlock;
+class JSScope;
+class JSWASMModule;
class LLIntOffsetsExtractor;
class ProgramCodeBlock;
+class ModuleProgramCodeBlock;
class JSScope;
-
+class WebAssemblyCodeBlock;
+class ModuleProgramCodeBlock;
+class JSModuleRecord;
+class JSScope;
+
enum CompilationKind { FirstCompilation, OptimizingCompilation };
inline bool isCall(CodeSpecializationKind kind)
@@ -61,8 +69,7 @@ inline bool isCall(CodeSpecializationKind kind)
return false;
}
-class ExecutableBase : public JSCell, public DoublyLinkedListNode<ExecutableBase> {
- friend class WTF::DoublyLinkedListNode<ExecutableBase>;
+class ExecutableBase : public JSCell {
friend class JIT;
protected:
@@ -83,27 +90,30 @@ protected:
public:
typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags;
-#if ENABLE(JIT)
static const bool needsDestruction = true;
- static const bool hasImmortalStructure = true;
static void destroy(JSCell*);
-#endif
CodeBlockHash hashFor(CodeSpecializationKind) const;
- bool isEvalExecutable()
+ bool isEvalExecutable() const
{
- return structure()->typeInfo().type() == EvalExecutableType;
+ return type() == EvalExecutableType;
}
- bool isFunctionExecutable()
+ bool isFunctionExecutable() const
{
- return structure()->typeInfo().type() == FunctionExecutableType;
+ return type() == FunctionExecutableType;
}
- bool isProgramExecutable()
+ bool isProgramExecutable() const
{
- return structure()->typeInfo().type() == ProgramExecutableType;
+ return type() == ProgramExecutableType;
}
+ bool isModuleProgramExecutable()
+ {
+ return type() == ModuleProgramExecutableType;
+ }
+
bool isHostFunction() const
{
@@ -111,20 +121,24 @@ public:
return m_numParametersForCall == NUM_PARAMETERS_IS_HOST;
}
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CompoundType, StructureFlags), info()); }
+#if ENABLE(WEBASSEMBLY)
+ bool isWebAssemblyExecutable() const
+ {
+ return type() == WebAssemblyExecutableType;
+ }
+#endif
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); }
void clearCode();
DECLARE_EXPORT_INFO;
protected:
- static const unsigned StructureFlags = 0;
int m_numParametersForCall;
int m_numParametersForConstruct;
public:
- static void clearCodeVirtual(ExecutableBase*);
-
PassRefPtr<JITCode> generatedJITCodeForCall()
{
ASSERT(m_jitCodeForCall);
@@ -144,37 +158,53 @@ public:
ASSERT(kind == CodeForConstruct);
return generatedJITCodeForConstruct();
}
-
- MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
- {
- ASSERT(m_jitCodeForCall);
- ASSERT(m_jitCodeForCallWithArityCheck);
- return m_jitCodeForCallWithArityCheck;
- }
-
- MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
- {
- ASSERT(m_jitCodeForConstruct);
- ASSERT(m_jitCodeForConstructWithArityCheck);
- return m_jitCodeForConstructWithArityCheck;
- }
-
- MacroAssemblerCodePtr generatedJITCodeWithArityCheckFor(CodeSpecializationKind kind)
- {
- if (kind == CodeForCall)
- return generatedJITCodeForCallWithArityCheck();
- ASSERT(kind == CodeForConstruct);
- return generatedJITCodeForConstructWithArityCheck();
- }
-
- static ptrdiff_t offsetOfJITCodeWithArityCheckFor(CodeSpecializationKind kind)
- {
- if (kind == CodeForCall)
+
+ MacroAssemblerCodePtr entrypointFor(CodeSpecializationKind kind, ArityCheckMode arity)
+ {
+ // Check if we have a cached result. We only have it for arity check because we use the
+ // no-arity entrypoint in non-virtual calls, which will "cache" this value directly in
+ // machine code.
+ if (arity == MustCheckArity) {
+ switch (kind) {
+ case CodeForCall:
+ if (MacroAssemblerCodePtr result = m_jitCodeForCallWithArityCheck)
+ return result;
+ break;
+ case CodeForConstruct:
+ if (MacroAssemblerCodePtr result = m_jitCodeForConstructWithArityCheck)
+ return result;
+ break;
+ }
+ }
+ MacroAssemblerCodePtr result =
+ generatedJITCodeFor(kind)->addressForCall(arity);
+ if (arity == MustCheckArity) {
+ // Cache the result; this is necessary for the JIT's virtual call optimizations.
+ switch (kind) {
+ case CodeForCall:
+ m_jitCodeForCallWithArityCheck = result;
+ break;
+ case CodeForConstruct:
+ m_jitCodeForConstructWithArityCheck = result;
+ break;
+ }
+ }
+ return result;
+ }
+
+ static ptrdiff_t offsetOfJITCodeWithArityCheckFor(
+ CodeSpecializationKind kind)
+ {
+ switch (kind) {
+ case CodeForCall:
return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck);
- ASSERT(kind == CodeForConstruct);
- return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck);
+ case CodeForConstruct:
+ return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck);
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return 0;
}
-
+
static ptrdiff_t offsetOfNumParametersFor(CodeSpecializationKind kind)
{
if (kind == CodeForCall)
@@ -210,52 +240,32 @@ public:
return intrinsic();
return NoIntrinsic;
}
+
+ void dump(PrintStream&) const;
- MacroAssemblerCodePtr hostCodeEntryFor(CodeSpecializationKind kind)
- {
- return generatedJITCodeFor(kind)->addressForCall();
- }
-
- MacroAssemblerCodePtr jsCodeEntryFor(CodeSpecializationKind kind)
- {
- return generatedJITCodeFor(kind)->addressForCall();
- }
-
- MacroAssemblerCodePtr jsCodeWithArityCheckEntryFor(CodeSpecializationKind kind)
- {
- return generatedJITCodeWithArityCheckFor(kind);
- }
-
protected:
- ExecutableBase* m_prev;
- ExecutableBase* m_next;
-
RefPtr<JITCode> m_jitCodeForCall;
RefPtr<JITCode> m_jitCodeForConstruct;
MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
};
-class NativeExecutable : public ExecutableBase {
+class NativeExecutable final : public ExecutableBase {
friend class JIT;
friend class LLIntOffsetsExtractor;
public:
typedef ExecutableBase Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
- static NativeExecutable* create(VM& vm, MacroAssemblerCodeRef callThunk, NativeFunction function, MacroAssemblerCodeRef constructThunk, NativeFunction constructor, Intrinsic intrinsic)
+ static NativeExecutable* create(VM& vm, PassRefPtr<JITCode> callThunk, NativeFunction function, PassRefPtr<JITCode> constructThunk, NativeFunction constructor, Intrinsic intrinsic, const String& name)
{
NativeExecutable* executable;
executable = new (NotNull, allocateCell<NativeExecutable>(vm.heap)) NativeExecutable(vm, function, constructor);
- if (!callThunk)
- executable->finishCreation(vm, 0, 0, intrinsic);
- else
- executable->finishCreation(vm, JITCode::hostFunction(callThunk), JITCode::hostFunction(constructThunk), intrinsic);
+ executable->finishCreation(vm, callThunk, constructThunk, intrinsic, name);
return executable;
}
-#if ENABLE(JIT)
static void destroy(JSCell*);
-#endif
CodeBlockHash hashFor(CodeSpecializationKind) const;
@@ -278,24 +288,27 @@ public:
return OBJECT_OFFSETOF(NativeExecutable, m_constructor);
}
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(LeafType, StructureFlags), info()); }
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); }
DECLARE_INFO;
Intrinsic intrinsic() const;
+ const String& name() const { return m_name; }
+
protected:
- void finishCreation(VM& vm, PassRefPtr<JITCode> callThunk, PassRefPtr<JITCode> constructThunk, Intrinsic intrinsic)
+ void finishCreation(VM& vm, PassRefPtr<JITCode> callThunk, PassRefPtr<JITCode> constructThunk, Intrinsic intrinsic, const String& name)
{
Base::finishCreation(vm);
- m_jitCodeForCallWithArityCheck = callThunk ? callThunk->addressForCall() : MacroAssemblerCodePtr();
- m_jitCodeForConstructWithArityCheck = constructThunk ? constructThunk->addressForCall() : MacroAssemblerCodePtr();
m_jitCodeForCall = callThunk;
m_jitCodeForConstruct = constructThunk;
m_intrinsic = intrinsic;
+ m_name = name;
}
private:
+ friend class ExecutableBase;
+
NativeExecutable(VM& vm, NativeFunction function, NativeFunction constructor)
: ExecutableBase(vm, vm.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
, m_function(function)
@@ -307,61 +320,54 @@ private:
NativeFunction m_constructor;
Intrinsic m_intrinsic;
+
+ String m_name;
};
class ScriptExecutable : public ExecutableBase {
public:
typedef ExecutableBase Base;
+ static const unsigned StructureFlags = Base::StructureFlags;
- ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext)
- : ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED)
- , m_source(source)
- , m_features(isInStrictContext ? StrictModeFeature : 0)
- , m_neverInline(false)
- , m_startColumn(UINT_MAX)
- , m_endColumn(UINT_MAX)
- {
- }
-
- ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext)
- : ExecutableBase(exec->vm(), structure, NUM_PARAMETERS_NOT_COMPILED)
- , m_source(source)
- , m_features(isInStrictContext ? StrictModeFeature : 0)
- , m_neverInline(false)
- , m_startColumn(UINT_MAX)
- , m_endColumn(UINT_MAX)
- {
- }
-
-#if ENABLE(JIT)
static void destroy(JSCell*);
-#endif
CodeBlockHash hashFor(CodeSpecializationKind) const;
const SourceCode& source() const { return m_source; }
intptr_t sourceID() const { return m_source.providerID(); }
const String& sourceURL() const { return m_source.provider()->url(); }
- int lineNo() const { return m_firstLine; }
+ int firstLine() const { return m_firstLine; }
+ void setOverrideLineNumber(int overrideLineNumber) { m_overrideLineNumber = overrideLineNumber; }
+ bool hasOverrideLineNumber() const { return m_overrideLineNumber != -1; }
+ int overrideLineNumber() const { return m_overrideLineNumber; }
int lastLine() const { return m_lastLine; }
unsigned startColumn() const { return m_startColumn; }
unsigned endColumn() const { return m_endColumn; }
+ unsigned typeProfilingStartOffset() const { return m_typeProfilingStartOffset; }
+ unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; }
bool usesEval() const { return m_features & EvalFeature; }
bool usesArguments() const { return m_features & ArgumentsFeature; }
- bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); }
+ bool isArrowFunctionContext() const { return m_isArrowFunctionContext; }
bool isStrictMode() const { return m_features & StrictModeFeature; }
+ DerivedContextType derivedContextType() const { return static_cast<DerivedContextType>(m_derivedContextType); }
+
ECMAMode ecmaMode() const { return isStrictMode() ? StrictMode : NotStrictMode; }
void setNeverInline(bool value) { m_neverInline = value; }
+ void setNeverOptimize(bool value) { m_neverOptimize = value; }
+ void setDidTryToEnterInLoop(bool value) { m_didTryToEnterInLoop = value; }
bool neverInline() const { return m_neverInline; }
+ bool neverOptimize() const { return m_neverOptimize; }
+ bool didTryToEnterInLoop() const { return m_didTryToEnterInLoop; }
bool isInliningCandidate() const { return !neverInline(); }
+ bool isOkToOptimize() const { return !neverOptimize(); }
+
+ bool* addressOfDidTryToEnterInLoop() { return &m_didTryToEnterInLoop; }
- void unlinkCalls();
-
CodeFeatures features() const { return m_features; }
- DECLARE_INFO;
+ DECLARE_EXPORT_INFO;
void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine, unsigned startColumn, unsigned endColumn)
{
@@ -376,24 +382,30 @@ public:
}
void installCode(CodeBlock*);
- PassRefPtr<CodeBlock> newCodeBlockFor(CodeSpecializationKind, JSScope*, JSObject*& exception);
- PassRefPtr<CodeBlock> newReplacementCodeBlockFor(CodeSpecializationKind);
+ void installCode(VM&, CodeBlock*, CodeType, CodeSpecializationKind);
+ CodeBlock* newCodeBlockFor(CodeSpecializationKind, JSFunction*, JSScope*, JSObject*& exception);
+ CodeBlock* newReplacementCodeBlockFor(CodeSpecializationKind);
- JSObject* prepareForExecution(ExecState* exec, JSScope* scope, CodeSpecializationKind kind)
+ JSObject* prepareForExecution(ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind)
{
if (hasJITCodeFor(kind))
return 0;
- return prepareForExecutionImpl(exec, scope, kind);
+ return prepareForExecutionImpl(exec, function, scope, kind);
}
+ template <typename Functor> void forEachCodeBlock(Functor&&);
+
private:
- JSObject* prepareForExecutionImpl(ExecState*, JSScope*, CodeSpecializationKind);
+ friend class ExecutableBase;
+ JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind);
protected:
+ ScriptExecutable(Structure*, VM&, const SourceCode&, bool isInStrictContext, DerivedContextType, bool isInArrowFunctionContext);
+
void finishCreation(VM& vm)
{
Base::finishCreation(vm);
- vm.heap.addCompiledCode(this); // Balanced by Heap::deleteUnmarkedCompiledCode().
+ vm.heap.addExecutable(this); // Balanced by Heap::deleteUnmarkedCompiledCode().
#if ENABLE(CODEBLOCK_SAMPLING)
if (SamplingTool* sampler = vm.interpreter->sampler())
@@ -401,20 +413,29 @@ protected:
#endif
}
- SourceCode m_source;
CodeFeatures m_features;
- bool m_hasCapturedVariables;
- bool m_neverInline;
+ bool m_didTryToEnterInLoop;
+ bool m_hasCapturedVariables : 1;
+ bool m_neverInline : 1;
+ bool m_neverOptimize : 1;
+ bool m_isArrowFunctionContext : 1;
+ unsigned m_derivedContextType : 2; // DerivedContextType
+
+ int m_overrideLineNumber;
int m_firstLine;
int m_lastLine;
unsigned m_startColumn;
unsigned m_endColumn;
+ unsigned m_typeProfilingStartOffset;
+ unsigned m_typeProfilingEndOffset;
+ SourceCode m_source;
};
-class EvalExecutable : public ScriptExecutable {
+class EvalExecutable final : public ScriptExecutable {
friend class LLIntOffsetsExtractor;
public:
typedef ScriptExecutable Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
static void destroy(JSCell*);
@@ -423,7 +444,7 @@ public:
return m_evalCodeBlock.get();
}
- static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext);
+ static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, ThisTDZMode, DerivedContextType, bool isArrowFunctionContext, const VariableEnvironment*);
PassRefPtr<JITCode> generatedJITCode()
{
@@ -437,30 +458,28 @@ public:
DECLARE_INFO;
- void unlinkCalls();
-
- void clearCode();
-
- ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false); }
+ ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, SuperBinding::NotNeeded, SourceParseMode::ProgramMode, derivedContextType(), isArrowFunctionContext() , false); }
unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }
unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }
private:
+ friend class ExecutableBase;
friend class ScriptExecutable;
- static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
- EvalExecutable(ExecState*, const SourceCode&, bool);
+
+ EvalExecutable(ExecState*, const SourceCode&, bool inStrictContext, DerivedContextType, bool isArrowFunctionContext);
static void visitChildren(JSCell*, SlotVisitor&);
- RefPtr<EvalCodeBlock> m_evalCodeBlock;
+ WriteBarrier<EvalCodeBlock> m_evalCodeBlock;
WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock;
};
-class ProgramExecutable : public ScriptExecutable {
+class ProgramExecutable final : public ScriptExecutable {
friend class LLIntOffsetsExtractor;
public:
typedef ScriptExecutable Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
static ProgramExecutable* create(ExecState* exec, const SourceCode& source)
{
@@ -492,43 +511,89 @@ public:
}
DECLARE_INFO;
-
- void unlinkCalls();
- void clearCode();
-
- ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false); }
+ ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, SuperBinding::NotNeeded, SourceParseMode::ProgramMode, derivedContextType(), isArrowFunctionContext(), false); }
private:
+ friend class ExecutableBase;
friend class ScriptExecutable;
-
- static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
ProgramExecutable(ExecState*, const SourceCode&);
static void visitChildren(JSCell*, SlotVisitor&);
WriteBarrier<UnlinkedProgramCodeBlock> m_unlinkedProgramCodeBlock;
- RefPtr<ProgramCodeBlock> m_programCodeBlock;
+ WriteBarrier<ProgramCodeBlock> m_programCodeBlock;
+};
+
+class ModuleProgramExecutable final : public ScriptExecutable {
+ friend class LLIntOffsetsExtractor;
+public:
+ typedef ScriptExecutable Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+ static ModuleProgramExecutable* create(ExecState*, const SourceCode&);
+
+ static void destroy(JSCell*);
+
+ ModuleProgramCodeBlock* codeBlock()
+ {
+ return m_moduleProgramCodeBlock.get();
+ }
+
+ PassRefPtr<JITCode> generatedJITCode()
+ {
+ return generatedJITCodeForCall();
+ }
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(vm, globalObject, proto, TypeInfo(ModuleProgramExecutableType, StructureFlags), info());
+ }
+
+ DECLARE_INFO;
+
+ ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, SuperBinding::NotNeeded, SourceParseMode::ModuleEvaluateMode, derivedContextType(), isArrowFunctionContext(), false); }
+
+ UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCodeBlock() { return m_unlinkedModuleProgramCodeBlock.get(); }
+
+ SymbolTable* moduleEnvironmentSymbolTable() { return m_moduleEnvironmentSymbolTable.get(); }
+
+private:
+ friend class ExecutableBase;
+ friend class ScriptExecutable;
+
+ ModuleProgramExecutable(ExecState*, const SourceCode&);
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ WriteBarrier<UnlinkedModuleProgramCodeBlock> m_unlinkedModuleProgramCodeBlock;
+ WriteBarrier<SymbolTable> m_moduleEnvironmentSymbolTable;
+ WriteBarrier<ModuleProgramCodeBlock> m_moduleProgramCodeBlock;
};
-class FunctionExecutable : public ScriptExecutable {
+class FunctionExecutable final : public ScriptExecutable {
friend class JIT;
friend class LLIntOffsetsExtractor;
public:
typedef ScriptExecutable Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
- static FunctionExecutable* create(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn, bool bodyIncludesBraces = true)
+ static FunctionExecutable* create(
+ VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable,
+ unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn)
{
- FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn, endColumn, bodyIncludesBraces);
+ FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(vm.heap)) FunctionExecutable(vm, source, unlinkedExecutable, firstLine, lastLine, startColumn, endColumn);
executable->finishCreation(vm);
return executable;
}
- static FunctionExecutable* fromGlobalCode(const Identifier& name, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
+ static FunctionExecutable* fromGlobalCode(
+ const Identifier& name, ExecState&, const SourceCode&,
+ JSObject*& exception, int overrideLineNumber);
static void destroy(JSCell*);
- UnlinkedFunctionExecutable* unlinkedExecutable()
+ UnlinkedFunctionExecutable* unlinkedExecutable() const
{
return m_unlinkedExecutable.get();
}
@@ -545,7 +610,7 @@ public:
bool isGeneratedForCall() const
{
- return m_codeBlockForCall;
+ return !!m_codeBlockForCall;
}
FunctionCodeBlock* codeBlockForCall()
@@ -555,7 +620,7 @@ public:
bool isGeneratedForConstruct() const
{
- return m_codeBlockForConstruct;
+ return m_codeBlockForConstruct.get();
}
FunctionCodeBlock* codeBlockForConstruct()
@@ -585,89 +650,107 @@ public:
{
return baselineCodeBlockFor(kind);
}
+
+ RefPtr<TypeSet> returnStatementTypeSet()
+ {
+ if (!m_returnStatementTypeSet)
+ m_returnStatementTypeSet = TypeSet::create();
+
+ return m_returnStatementTypeSet;
+ }
+ FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); }
+ bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); }
+ ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); }
+ bool isArrowFunction() const { return parseMode() == SourceParseMode::ArrowFunctionMode; }
+ DerivedContextType derivedContextType() const { return m_unlinkedExecutable->derivedContextType(); }
+ bool isClassConstructorFunction() const { return m_unlinkedExecutable->isClassConstructorFunction(); }
const Identifier& name() { return m_unlinkedExecutable->name(); }
const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); }
JSString* nameValue() const { return m_unlinkedExecutable->nameValue(); }
size_t parameterCount() const { return m_unlinkedExecutable->parameterCount(); } // Excluding 'this'!
- String paramString() const;
- SymbolTable* symbolTable(CodeSpecializationKind);
+ SourceParseMode parseMode() const { return m_unlinkedExecutable->parseMode(); }
- void clearCodeIfNotCompiling();
- void clearUnlinkedCodeForRecompilationIfNotCompiling();
static void visitChildren(JSCell*, SlotVisitor&);
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
{
return Structure::create(vm, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), info());
}
-
- DECLARE_INFO;
-
- void unlinkCalls();
-
- void clearCode();
-
- bool bodyIncludesBraces() const { return m_bodyIncludesBraces; }
-private:
- FunctionExecutable(VM&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn, bool bodyIncludesBraces);
+ unsigned parametersStartOffset() const { return m_parametersStartOffset; }
- bool isCompiling()
+ void overrideParameterAndTypeProfilingStartEndOffsets(unsigned parametersStartOffset, unsigned typeProfilingStartOffset, unsigned typeProfilingEndOffset)
{
-#if ENABLE(JIT)
- if (!m_jitCodeForCall && m_codeBlockForCall)
- return true;
- if (!m_jitCodeForConstruct && m_codeBlockForConstruct)
- return true;
-#endif
- return false;
+ m_parametersStartOffset = parametersStartOffset;
+ m_typeProfilingStartOffset = typeProfilingStartOffset;
+ m_typeProfilingEndOffset = typeProfilingEndOffset;
}
- friend class ScriptExecutable;
+ DECLARE_INFO;
+
+ InferredValue* singletonFunction() { return m_singletonFunction.get(); }
+
+private:
+ friend class ExecutableBase;
+ FunctionExecutable(
+ VM&, const SourceCode&, UnlinkedFunctionExecutable*, unsigned firstLine,
+ unsigned lastLine, unsigned startColumn, unsigned endColumn);
+
+ void finishCreation(VM&);
- static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
+ friend class ScriptExecutable;
+
+ unsigned m_parametersStartOffset;
WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable;
- RefPtr<FunctionCodeBlock> m_codeBlockForCall;
- RefPtr<FunctionCodeBlock> m_codeBlockForConstruct;
- bool m_bodyIncludesBraces;
+ WriteBarrier<FunctionCodeBlock> m_codeBlockForCall;
+ WriteBarrier<FunctionCodeBlock> m_codeBlockForConstruct;
+ RefPtr<TypeSet> m_returnStatementTypeSet;
+ WriteBarrier<InferredValue> m_singletonFunction;
};
-inline bool isHostFunction(JSValue value, NativeFunction nativeFunction)
-{
- JSFunction* function = jsCast<JSFunction*>(getJSFunction(value));
- if (!function || !function->isHostFunction())
- return false;
- return function->nativeFunction() == nativeFunction;
-}
+#if ENABLE(WEBASSEMBLY)
+class WebAssemblyExecutable final : public ExecutableBase {
+public:
+ typedef ExecutableBase Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
-inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable)
-{
- switch (executable->structure()->typeInfo().type()) {
- case EvalExecutableType:
- return jsCast<EvalExecutable*>(executable)->clearCode();
- case ProgramExecutableType:
- return jsCast<ProgramExecutable*>(executable)->clearCode();
- case FunctionExecutableType:
- return jsCast<FunctionExecutable*>(executable)->clearCode();
- default:
- return jsCast<NativeExecutable*>(executable)->clearCode();
+ static WebAssemblyExecutable* create(VM& vm, const SourceCode& source, JSWASMModule* module, unsigned functionIndex)
+ {
+ WebAssemblyExecutable* executable = new (NotNull, allocateCell<WebAssemblyExecutable>(vm.heap)) WebAssemblyExecutable(vm, source, module, functionIndex);
+ executable->finishCreation(vm);
+ return executable;
}
-}
-inline void ScriptExecutable::unlinkCalls()
-{
- switch (structure()->typeInfo().type()) {
- case EvalExecutableType:
- return jsCast<EvalExecutable*>(this)->unlinkCalls();
- case ProgramExecutableType:
- return jsCast<ProgramExecutable*>(this)->unlinkCalls();
- case FunctionExecutableType:
- return jsCast<FunctionExecutable*>(this)->unlinkCalls();
- default:
- RELEASE_ASSERT_NOT_REACHED();
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(vm, globalObject, proto, TypeInfo(WebAssemblyExecutableType, StructureFlags), info());
}
-}
-}
+ static void destroy(JSCell*);
+
+ DECLARE_INFO;
+
+ void prepareForExecution(ExecState*);
+
+ WebAssemblyCodeBlock* codeBlockForCall()
+ {
+ return m_codeBlockForCall.get();
+ }
+private:
+ friend class ExecutableBase;
+ WebAssemblyExecutable(VM&, const SourceCode&, JSWASMModule*, unsigned functionIndex);
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ SourceCode m_source;
+ WriteBarrier<JSWASMModule> m_module;
+ unsigned m_functionIndex;
+
+ WriteBarrier<WebAssemblyCodeBlock> m_codeBlockForCall;
+};
#endif
+
+} // namespace JSC
+
+#endif // Executable_h
diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
index 53de63271..cda30b957 100644
--- a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
@@ -29,7 +29,7 @@
#include "JSString.h"
#include "Lexer.h"
#include "Nodes.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "Parser.h"
#include <wtf/text/StringBuilder.h>
@@ -37,7 +37,7 @@ namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(FunctionConstructor);
-const ClassInfo FunctionConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionConstructor) };
+const ClassInfo FunctionConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(FunctionConstructor) };
FunctionConstructor::FunctionConstructor(VM& vm, Structure* structure)
: InternalFunction(vm, structure)
@@ -56,7 +56,7 @@ void FunctionConstructor::finishCreation(VM& vm, FunctionPrototype* functionProt
static EncodedJSValue JSC_HOST_CALL constructWithFunctionConstructor(ExecState* exec)
{
ArgList args(exec);
- return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args));
+ return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args, FunctionConstructionMode::Function, exec->newTarget()));
}
ConstructType FunctionConstructor::getConstructData(JSCell*, ConstructData& constructData)
@@ -79,52 +79,59 @@ CallType FunctionConstructor::getCallData(JSCell*, CallData& callData)
}
// ECMA 15.3.2 The Function Constructor
-JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const String& sourceURL, const TextPosition& position)
+JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const String& sourceURL, const TextPosition& position, FunctionConstructionMode functionConstructionMode, JSValue newTarget)
{
if (!globalObject->evalEnabled())
return exec->vm().throwException(exec, createEvalError(exec, globalObject->evalDisabledErrorMessage()));
- return constructFunctionSkippingEvalEnabledCheck(exec, globalObject, args, functionName, sourceURL, position);
+ return constructFunctionSkippingEvalEnabledCheck(exec, globalObject, args, functionName, sourceURL, position, -1, functionConstructionMode, newTarget);
}
-JSObject* constructFunctionSkippingEvalEnabledCheck(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const String& sourceURL, const TextPosition& position)
+JSObject* constructFunctionSkippingEvalEnabledCheck(
+ ExecState* exec, JSGlobalObject* globalObject, const ArgList& args,
+ const Identifier& functionName, const String& sourceURL,
+ const TextPosition& position, int overrideLineNumber, FunctionConstructionMode functionConstructionMode, JSValue newTarget)
{
- // Functions need to have a space following the opening { due to for web compatibility
- // see https://bugs.webkit.org/show_bug.cgi?id=24350
- // We also need \n before the closing } to handle // comments at the end of the last line
+ // How we stringify functions is sometimes important for web compatibility.
+ // See https://bugs.webkit.org/show_bug.cgi?id=24350.
String program;
if (args.isEmpty())
- program = ASCIILiteral("(function() {\n})");
+ program = makeString("{function ", functionConstructionMode == FunctionConstructionMode::Generator ? "*" : "", functionName.string(), "() {\n\n}}");
else if (args.size() == 1)
- program = makeString("(function() {", args.at(0).toString(exec)->value(exec), "\n})");
+ program = makeString("{function ", functionConstructionMode == FunctionConstructionMode::Generator ? "*" : "", functionName.string(), "() {\n", args.at(0).toString(exec)->value(exec), "\n}}");
else {
StringBuilder builder;
- builder.appendLiteral("(function(");
- builder.append(args.at(0).toString(exec)->value(exec));
+ builder.appendLiteral("{function ");
+ if (functionConstructionMode == FunctionConstructionMode::Generator)
+ builder.append('*');
+ builder.append(functionName.string());
+ builder.append('(');
+ builder.append(args.at(0).toString(exec)->view(exec).get());
for (size_t i = 1; i < args.size() - 1; i++) {
- builder.append(',');
- builder.append(args.at(i).toString(exec)->value(exec));
+ builder.appendLiteral(", ");
+ builder.append(args.at(i).toString(exec)->view(exec).get());
}
- builder.appendLiteral(") {");
- builder.append(args.at(args.size() - 1).toString(exec)->value(exec));
- builder.appendLiteral("\n})");
+ builder.appendLiteral(") {\n");
+ builder.append(args.at(args.size() - 1).toString(exec)->view(exec).get());
+ builder.appendLiteral("\n}}");
program = builder.toString();
}
SourceCode source = makeSource(program, sourceURL, position);
- JSObject* exception = 0;
- FunctionExecutable* function = FunctionExecutable::fromGlobalCode(functionName, exec, exec->vmEntryGlobalObject()->debugger(), source, &exception);
+ JSObject* exception = nullptr;
+ FunctionExecutable* function = FunctionExecutable::fromGlobalCode(functionName, *exec, source, exception, overrideLineNumber);
if (!function) {
ASSERT(exception);
return exec->vm().throwException(exec, exception);
}
- return JSFunction::create(exec->vm(), function, globalObject);
+
+ return JSFunction::create(exec->vm(), function, globalObject, InternalFunction::createSubclassStructure(exec, newTarget, globalObject->functionStructure()));
}
// ECMA 15.3.2 The Function Constructor
-JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args)
+JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, FunctionConstructionMode functionConstructionMode, JSValue newTarget)
{
- return constructFunction(exec, globalObject, args, exec->propertyNames().anonymous, String(), TextPosition::minimumPosition());
+ return constructFunction(exec, globalObject, args, exec->propertyNames().anonymous, String(), TextPosition::minimumPosition(), functionConstructionMode, newTarget);
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.h b/Source/JavaScriptCore/runtime/FunctionConstructor.h
index 61443e944..63bc408c4 100644
--- a/Source/JavaScriptCore/runtime/FunctionConstructor.h
+++ b/Source/JavaScriptCore/runtime/FunctionConstructor.h
@@ -29,37 +29,45 @@ class TextPosition;
namespace JSC {
- class FunctionPrototype;
+class FunctionPrototype;
- class FunctionConstructor : public InternalFunction {
- public:
- typedef InternalFunction Base;
+class FunctionConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
- static FunctionConstructor* create(VM& vm, Structure* structure, FunctionPrototype* functionPrototype)
- {
- FunctionConstructor* constructor = new (NotNull, allocateCell<FunctionConstructor>(vm.heap)) FunctionConstructor(vm, structure);
- constructor->finishCreation(vm, functionPrototype);
- return constructor;
- }
+ static FunctionConstructor* create(VM& vm, Structure* structure, FunctionPrototype* functionPrototype)
+ {
+ FunctionConstructor* constructor = new (NotNull, allocateCell<FunctionConstructor>(vm.heap)) FunctionConstructor(vm, structure);
+ constructor->finishCreation(vm, functionPrototype);
+ return constructor;
+ }
- DECLARE_INFO;
+ DECLARE_INFO;
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
- private:
- FunctionConstructor(VM&, Structure*);
- void finishCreation(VM&, FunctionPrototype*);
- static ConstructType getConstructData(JSCell*, ConstructData&);
- static CallType getCallData(JSCell*, CallData&);
- };
+private:
+ FunctionConstructor(VM&, Structure*);
+ void finishCreation(VM&, FunctionPrototype*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+};
- JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const String& sourceURL, const WTF::TextPosition&);
- JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&);
+enum class FunctionConstructionMode {
+ Function,
+ Generator,
+};
- JS_EXPORT_PRIVATE JSObject* constructFunctionSkippingEvalEnabledCheck(ExecState*, JSGlobalObject*, const ArgList&, const Identifier&, const String&, const WTF::TextPosition&);
+JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const String& sourceURL, const WTF::TextPosition&, FunctionConstructionMode = FunctionConstructionMode::Function, JSValue newTarget = JSValue());
+JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, FunctionConstructionMode = FunctionConstructionMode::Function, JSValue newTarget = JSValue());
+
+JS_EXPORT_PRIVATE JSObject* constructFunctionSkippingEvalEnabledCheck(
+ ExecState*, JSGlobalObject*, const ArgList&, const Identifier&,
+ const String&, const WTF::TextPosition&, int overrideLineNumber = -1,
+ FunctionConstructionMode = FunctionConstructionMode::Function, JSValue newTarget = JSValue());
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp b/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp
index d0583fc9b..d80a8e701 100644
--- a/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp
+++ b/Source/JavaScriptCore/runtime/FunctionExecutableDump.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * 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
@@ -25,6 +25,7 @@
#include "config.h"
#include "FunctionExecutableDump.h"
+#include "JSCellInlines.h"
#include "CodeBlock.h"
@@ -34,12 +35,12 @@ void FunctionExecutableDump::dump(PrintStream& out) const
{
out.print(m_executable->inferredName().string(), "#");
if (m_executable->isGeneratedForCall())
- out.print(m_executable->codeBlockForCall()->hash());
+ out.print(m_executable->codeBlockForCall()->hashAsStringIfPossible());
else
out.print("<nogen>");
out.print("/");
if (m_executable->isGeneratedForConstruct())
- out.print(m_executable->codeBlockForConstruct()->hash());
+ out.print(m_executable->codeBlockForConstruct()->hashAsStringIfPossible());
else
out.print("<nogen>");
out.print(":[", RawPointer(m_executable), "]");
diff --git a/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.cpp b/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.cpp
new file mode 100644
index 000000000..3d7e31b2e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+#include "FunctionHasExecutedCache.h"
+
+#include <limits.h>
+
+namespace JSC {
+
+bool FunctionHasExecutedCache::hasExecutedAtOffset(intptr_t id, unsigned offset)
+{
+ if (m_rangeMap.find(id) == m_rangeMap.end())
+ return false;
+
+ RangeMap& map = m_rangeMap.find(id)->second;
+ unsigned distance = UINT_MAX;
+ bool hasExecuted = false;
+ for (auto iter = map.begin(), end = map.end(); iter != end; ++iter) {
+ const FunctionRange& range = iter->first;
+ if (range.m_start <= offset && offset <= range.m_end && range.m_end - range.m_start < distance) {
+ hasExecuted = iter->second;
+ distance = range.m_end - range.m_start;
+ }
+ }
+
+ return hasExecuted;
+}
+
+void FunctionHasExecutedCache::insertUnexecutedRange(intptr_t id, unsigned start, unsigned end)
+{
+ if (m_rangeMap.find(id) == m_rangeMap.end()) {
+ RangeMap map;
+ m_rangeMap[id] = map;
+ }
+
+ RangeMap& map = m_rangeMap.find(id)->second;
+ FunctionRange range;
+ range.m_start = start;
+ range.m_end = end;
+ // Only insert unexecuted ranges once for a given sourceID because we may run into a situation where an executable executes, then is GCed, and then is allocated again,
+ // and tries to reinsert itself, claiming it has never run, but this is false because it indeed already executed.
+ if (map.find(range) == map.end())
+ map[range] = false;
+}
+
+void FunctionHasExecutedCache::removeUnexecutedRange(intptr_t id, unsigned start, unsigned end)
+{
+ // FIXME: We should never have an instance where we return here, but currently do in some situations. Find out why.
+ if (m_rangeMap.find(id) == m_rangeMap.end())
+ return;
+
+ RangeMap& map = m_rangeMap.find(id)->second;
+
+ FunctionRange range;
+ range.m_start = start;
+ range.m_end = end;
+ map[range] = true;
+}
+
+Vector<std::tuple<bool, unsigned, unsigned>> FunctionHasExecutedCache::getFunctionRanges(intptr_t id)
+{
+ Vector<std::tuple<bool, unsigned, unsigned>> ranges(0);
+ auto findResult = m_rangeMap.find(id);
+ if (findResult == m_rangeMap.end())
+ return ranges;
+
+ RangeMap& map = m_rangeMap.find(id)->second;
+ for (auto iter = map.begin(), end = map.end(); iter != end; ++iter) {
+ const FunctionRange& range = iter->first;
+ bool hasExecuted = iter->second;
+ ranges.append(std::tuple<bool, unsigned, unsigned>(hasExecuted, range.m_start, range.m_end));
+ }
+
+ return ranges;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.h b/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.h
new file mode 100644
index 000000000..7f3eb9784
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/FunctionHasExecutedCache.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef FunctionHasExecutedCache_h
+#define FunctionHasExecutedCache_h
+
+#include <unordered_map>
+#include <wtf/HashMethod.h>
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+class FunctionHasExecutedCache {
+public:
+ struct FunctionRange {
+ FunctionRange() {}
+ bool operator==(const FunctionRange& other) const
+ {
+ return m_start == other.m_start && m_end == other.m_end;
+ }
+ unsigned hash() const
+ {
+ return m_start * m_end;
+ }
+
+ unsigned m_start;
+ unsigned m_end;
+ };
+
+ bool hasExecutedAtOffset(intptr_t id, unsigned offset);
+ void insertUnexecutedRange(intptr_t id, unsigned start, unsigned end);
+ void removeUnexecutedRange(intptr_t id, unsigned start, unsigned end);
+ Vector<std::tuple<bool, unsigned, unsigned>> getFunctionRanges(intptr_t id);
+
+private:
+ typedef std::unordered_map<FunctionRange, bool, HashMethod<FunctionRange>> RangeMap;
+ typedef std::unordered_map<intptr_t, RangeMap> SourceIDToRangeMap;
+ SourceIDToRangeMap m_rangeMap;
+};
+
+} // namespace JSC
+
+#endif // FunctionHasExecutedCache_h
diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
index c1b08af2d..4ca55f90e 100644
--- a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 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
@@ -21,7 +21,9 @@
#include "config.h"
#include "FunctionPrototype.h"
-#include "Arguments.h"
+#include "BuiltinExecutables.h"
+#include "BuiltinNames.h"
+#include "Error.h"
#include "JSArray.h"
#include "JSBoundFunction.h"
#include "JSFunction.h"
@@ -29,17 +31,15 @@
#include "JSStringBuilder.h"
#include "Interpreter.h"
#include "Lexer.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(FunctionPrototype);
-const ClassInfo FunctionPrototype::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionPrototype) };
+const ClassInfo FunctionPrototype::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(FunctionPrototype) };
static EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL functionProtoFuncApply(ExecState*);
-static EncodedJSValue JSC_HOST_CALL functionProtoFuncCall(ExecState*);
static EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState*);
FunctionPrototype::FunctionPrototype(VM& vm, Structure* structure)
@@ -53,18 +53,16 @@ void FunctionPrototype::finishCreation(VM& vm, const String& name)
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
}
-void FunctionPrototype::addFunctionProperties(ExecState* exec, JSGlobalObject* globalObject, JSFunction** callFunction, JSFunction** applyFunction)
+void FunctionPrototype::addFunctionProperties(ExecState* exec, JSGlobalObject* globalObject, JSFunction** callFunction, JSFunction** applyFunction, JSFunction** hasInstanceSymbolFunction)
{
VM& vm = exec->vm();
JSFunction* toStringFunction = JSFunction::create(vm, globalObject, 0, vm.propertyNames->toString.string(), functionProtoFuncToString);
putDirectWithoutTransition(vm, vm.propertyNames->toString, toStringFunction, DontEnum);
- *applyFunction = JSFunction::create(vm, globalObject, 2, vm.propertyNames->apply.string(), functionProtoFuncApply);
- putDirectWithoutTransition(vm, vm.propertyNames->apply, *applyFunction, DontEnum);
-
- *callFunction = JSFunction::create(vm, globalObject, 1, vm.propertyNames->call.string(), functionProtoFuncCall);
- putDirectWithoutTransition(vm, vm.propertyNames->call, *callFunction, DontEnum);
+ *applyFunction = putDirectBuiltinFunctionWithoutTransition(vm, globalObject, vm.propertyNames->builtinNames().applyPublicName(), functionPrototypeApplyCodeGenerator(vm), DontEnum);
+ *callFunction = putDirectBuiltinFunctionWithoutTransition(vm, globalObject, vm.propertyNames->builtinNames().callPublicName(), functionPrototypeCallCodeGenerator(vm), DontEnum);
+ *hasInstanceSymbolFunction = putDirectBuiltinFunction(vm, globalObject, vm.propertyNames->hasInstanceSymbol, functionPrototypeSymbolHasInstanceCodeGenerator(vm), DontDelete | ReadOnly | DontEnum);
JSFunction* bindFunction = JSFunction::create(vm, globalObject, 1, vm.propertyNames->bind.string(), functionProtoFuncBind);
putDirectWithoutTransition(vm, vm.propertyNames->bind, bindFunction, DontEnum);
@@ -82,38 +80,28 @@ CallType FunctionPrototype::getCallData(JSCell*, CallData& callData)
return CallTypeHost;
}
-// Functions
-
-// Compatibility hack for the Optimost JavaScript library. (See <rdar://problem/6595040>.)
-static inline void insertSemicolonIfNeeded(String& functionBody, bool bodyIncludesBraces)
-{
- if (!bodyIncludesBraces)
- functionBody = makeString("{ ", functionBody, "}");
-
- ASSERT(functionBody[0] == '{');
- ASSERT(functionBody[functionBody.length() - 1] == '}');
-
- for (size_t i = functionBody.length() - 2; i > 0; --i) {
- UChar ch = functionBody[i];
- if (!Lexer<UChar>::isWhiteSpace(ch) && !Lexer<UChar>::isLineTerminator(ch)) {
- if (ch != ';' && ch != '}')
- functionBody = makeString(functionBody.substringSharingImpl(0, i + 1), ";", functionBody.substringSharingImpl(i + 1, functionBody.length() - (i + 1)));
- return;
- }
- }
-}
-
EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (thisValue.inherits(JSFunction::info())) {
JSFunction* function = jsCast<JSFunction*>(thisValue);
- if (function->isHostFunction())
- return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}"));
+ if (function->isHostOrBuiltinFunction()) {
+ String name;
+ if (JSBoundFunction* boundFunction = jsDynamicCast<JSBoundFunction*>(function))
+ name = boundFunction->toStringName(exec);
+ else
+ name = function->name(exec);
+ return JSValue::encode(jsMakeNontrivialString(exec, "function ", name, "() {\n [native code]\n}"));
+ }
+
FunctionExecutable* executable = function->jsExecutable();
- String sourceString = executable->source().toString();
- insertSemicolonIfNeeded(sourceString, executable->bodyIncludesBraces());
- return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "(", executable->paramString(), ") ", sourceString));
+
+ String functionHeader = executable->isArrowFunction() ? "" : "function ";
+
+ StringView source = executable->source().provider()->getRange(
+ executable->parametersStartOffset(),
+ executable->parametersStartOffset() + executable->source().length());
+ return JSValue::encode(jsMakeNontrivialString(exec, functionHeader, function->name(exec), source));
}
if (thisValue.inherits(InternalFunction::info())) {
@@ -121,56 +109,18 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec)
return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}"));
}
- return throwVMTypeError(exec);
-}
-
-EncodedJSValue JSC_HOST_CALL functionProtoFuncApply(ExecState* exec)
-{
- JSValue thisValue = exec->hostThisValue();
- CallData callData;
- CallType callType = getCallData(thisValue, callData);
- if (callType == CallTypeNone)
- return throwVMTypeError(exec);
-
- JSValue array = exec->argument(1);
-
- MarkedArgumentBuffer applyArgs;
- if (!array.isUndefinedOrNull()) {
- if (!array.isObject())
- return throwVMTypeError(exec);
- if (asObject(array)->classInfo() == Arguments::info()) {
- if (asArguments(array)->length(exec) > Arguments::MaxArguments)
- return JSValue::encode(throwStackOverflowError(exec));
- asArguments(array)->fillArgList(exec, applyArgs);
- } else if (isJSArray(array)) {
- if (asArray(array)->length() > Arguments::MaxArguments)
- return JSValue::encode(throwStackOverflowError(exec));
- asArray(array)->fillArgList(exec, applyArgs);
- } else {
- unsigned length = asObject(array)->get(exec, exec->propertyNames().length).toUInt32(exec);
- if (length > Arguments::MaxArguments)
- return JSValue::encode(throwStackOverflowError(exec));
-
- for (unsigned i = 0; i < length; ++i)
- applyArgs.append(asObject(array)->get(exec, i));
+ if (thisValue.isObject()) {
+ JSObject* object = asObject(thisValue);
+ if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
+ CallData callData;
+ if (object->methodTable(exec->vm())->getCallData(object, callData) != CallTypeNone) {
+ if (auto* classInfo = object->classInfo())
+ return JSValue::encode(jsMakeNontrivialString(exec, "function ", classInfo->className, "() {\n [native code]\n}"));
+ }
}
}
-
- return JSValue::encode(call(exec, thisValue, callType, callData, exec->argument(0), applyArgs));
-}
-EncodedJSValue JSC_HOST_CALL functionProtoFuncCall(ExecState* exec)
-{
- JSValue thisValue = exec->hostThisValue();
- CallData callData;
- CallType callType = getCallData(thisValue, callData);
- if (callType == CallTypeNone)
- return throwVMTypeError(exec);
-
- ArgList args(exec);
- ArgList callArgs;
- args.getSlice(1, callArgs);
- return JSValue::encode(call(exec, thisValue, callType, callData, exec->argument(0), callArgs));
+ return throwVMTypeError(exec);
}
// 15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, ...]])
@@ -179,7 +129,7 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec)
JSGlobalObject* globalObject = exec->callee()->globalObject();
// Let Target be the this value.
- JSValue target = exec->hostThisValue();
+ JSValue target = exec->thisValue();
// If IsCallable(Target) is false, throw a TypeError exception.
CallData callData;
@@ -203,13 +153,18 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec)
// If the [[Class]] internal property of Target is "Function", then ...
// Else set the length own property of F to 0.
unsigned length = 0;
- if (targetObject->inherits(JSFunction::info())) {
- ASSERT(target.get(exec, exec->propertyNames().length).isNumber());
+ if (targetObject->hasOwnProperty(exec, exec->propertyNames().length)) {
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
// a. Let L be the length property of Target minus the length of A.
// b. Set the length own property of F to either 0 or L, whichever is larger.
- unsigned targetLength = (unsigned)target.get(exec, exec->propertyNames().length).asNumber();
- if (targetLength > numBoundArgs)
- length = targetLength - numBoundArgs;
+ JSValue lengthValue = target.get(exec, exec->propertyNames().length);
+ if (lengthValue.isNumber()) {
+ unsigned targetLength = (unsigned)lengthValue.asNumber();
+ if (targetLength > numBoundArgs)
+ length = targetLength - numBoundArgs;
+ }
}
JSString* name = target.get(exec, exec->propertyNames().name).toString(exec);
diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.h b/Source/JavaScriptCore/runtime/FunctionPrototype.h
index 68d2f6a81..abe533a33 100644
--- a/Source/JavaScriptCore/runtime/FunctionPrototype.h
+++ b/Source/JavaScriptCore/runtime/FunctionPrototype.h
@@ -25,33 +25,33 @@
namespace JSC {
- class FunctionPrototype : public InternalFunction {
- public:
- typedef InternalFunction Base;
-
- static FunctionPrototype* create(VM& vm, Structure* structure)
- {
- FunctionPrototype* prototype = new (NotNull, allocateCell<FunctionPrototype>(vm.heap)) FunctionPrototype(vm, structure);
- prototype->finishCreation(vm, String());
- return prototype;
- }
-
- void addFunctionProperties(ExecState*, JSGlobalObject*, JSFunction** callFunction, JSFunction** applyFunction);
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
- {
- return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info());
- }
-
- DECLARE_INFO;
-
- protected:
- void finishCreation(VM&, const String& name);
-
- private:
- FunctionPrototype(VM&, Structure*);
- static CallType getCallData(JSCell*, CallData&);
- };
+class FunctionPrototype : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+
+ static FunctionPrototype* create(VM& vm, Structure* structure)
+ {
+ FunctionPrototype* prototype = new (NotNull, allocateCell<FunctionPrototype>(vm.heap)) FunctionPrototype(vm, structure);
+ prototype->finishCreation(vm, String());
+ return prototype;
+ }
+
+ void addFunctionProperties(ExecState*, JSGlobalObject*, JSFunction** callFunction, JSFunction** applyFunction, JSFunction** hasInstanceSymbolFunction);
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ DECLARE_INFO;
+
+protected:
+ void finishCreation(VM&, const String& name);
+
+private:
+ FunctionPrototype(VM&, Structure*);
+ static CallType getCallData(JSCell*, CallData&);
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/FunctionRareData.cpp b/Source/JavaScriptCore/runtime/FunctionRareData.cpp
new file mode 100644
index 000000000..8816ecbc6
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/FunctionRareData.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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 "FunctionRareData.h"
+
+#include "JSCInlines.h"
+
+namespace JSC {
+
+const ClassInfo FunctionRareData::s_info = { "FunctionRareData", 0, 0, CREATE_METHOD_TABLE(FunctionRareData) };
+
+FunctionRareData* FunctionRareData::create(VM& vm)
+{
+ FunctionRareData* rareData = new (NotNull, allocateCell<FunctionRareData>(vm.heap)) FunctionRareData(vm);
+ rareData->finishCreation(vm);
+ return rareData;
+}
+
+void FunctionRareData::destroy(JSCell* cell)
+{
+ FunctionRareData* rareData = static_cast<FunctionRareData*>(cell);
+ rareData->FunctionRareData::~FunctionRareData();
+}
+
+Structure* FunctionRareData::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+}
+
+void FunctionRareData::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ FunctionRareData* rareData = jsCast<FunctionRareData*>(cell);
+
+ rareData->m_objectAllocationProfile.visitAggregate(visitor);
+ rareData->m_internalFunctionAllocationProfile.visitAggregate(visitor);
+}
+
+FunctionRareData::FunctionRareData(VM& vm)
+ : Base(vm, vm.functionRareDataStructure.get())
+ , m_objectAllocationProfile()
+ // We initialize blind so that changes to the prototype after function creation but before
+ // the optimizer kicks in don't disable optimizations. Once the optimizer kicks in, the
+ // watchpoint will start watching and any changes will both force deoptimization and disable
+ // future attempts to optimize. This is necessary because we are guaranteed that the
+ // allocation profile is changed exactly once prior to optimizations kicking in. We could be
+ // smarter and count the number of times the prototype is clobbered and only optimize if it
+ // was clobbered exactly once, but that seems like overkill. In almost all cases it will be
+ // clobbered once, and if it's clobbered more than once, that will probably only occur
+ // before we started optimizing, anyway.
+ , m_objectAllocationProfileWatchpoint(ClearWatchpoint)
+{
+}
+
+FunctionRareData::~FunctionRareData()
+{
+}
+
+void FunctionRareData::initializeObjectAllocationProfile(VM& vm, JSObject* prototype, size_t inlineCapacity)
+{
+ m_objectAllocationProfile.initialize(vm, this, prototype, inlineCapacity);
+}
+
+void FunctionRareData::clear(const char* reason)
+{
+ m_objectAllocationProfile.clear();
+ m_internalFunctionAllocationProfile.clear();
+ m_objectAllocationProfileWatchpoint.fireAll(reason);
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/FunctionRareData.h b/Source/JavaScriptCore/runtime/FunctionRareData.h
new file mode 100644
index 000000000..d6e97e676
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/FunctionRareData.h
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+#ifndef FunctionRareData_h
+#define FunctionRareData_h
+
+#include "InternalFunctionAllocationProfile.h"
+#include "JSCell.h"
+#include "ObjectAllocationProfile.h"
+#include "Watchpoint.h"
+
+namespace JSC {
+
+class JSGlobalObject;
+class LLIntOffsetsExtractor;
+namespace DFG {
+class SpeculativeJIT;
+class JITCompiler;
+}
+
+class FunctionRareData : public JSCell {
+ friend class JIT;
+ friend class DFG::SpeculativeJIT;
+ friend class DFG::JITCompiler;
+ friend class VM;
+
+public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = StructureIsImmortal | Base::StructureFlags;
+
+ static FunctionRareData* create(VM&);
+
+ static const bool needsDestruction = true;
+ static void destroy(JSCell*);
+
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ DECLARE_INFO;
+
+ static inline ptrdiff_t offsetOfObjectAllocationProfile()
+ {
+ return OBJECT_OFFSETOF(FunctionRareData, m_objectAllocationProfile);
+ }
+
+ ObjectAllocationProfile* objectAllocationProfile()
+ {
+ return &m_objectAllocationProfile;
+ }
+
+ Structure* objectAllocationStructure() { return m_objectAllocationProfile.structure(); }
+
+ InlineWatchpointSet& allocationProfileWatchpointSet()
+ {
+ return m_objectAllocationProfileWatchpoint;
+ }
+
+ void clear(const char* reason);
+
+ void initializeObjectAllocationProfile(VM&, JSObject* prototype, size_t inlineCapacity);
+
+ bool isObjectAllocationProfileInitialized() { return !m_objectAllocationProfile.isNull(); }
+
+ Structure* internalFunctionAllocationStructure() { return m_internalFunctionAllocationProfile.structure(); }
+ Structure* createInternalFunctionAllocationStructureFromBase(VM& vm, JSObject* prototype, Structure* baseStructure)
+ {
+ return m_internalFunctionAllocationProfile.createAllocationStructureFromBase(vm, this, prototype, baseStructure);
+ }
+
+protected:
+ FunctionRareData(VM&);
+ ~FunctionRareData();
+
+private:
+
+ friend class LLIntOffsetsExtractor;
+
+ // Ideally, there would only be one allocation profile for subclassing but due to Reflect.construct we
+ // have two. There are some pros and cons in comparison to our current system to using the same profile
+ // for both JS constructors and subclasses of builtin constructors:
+ //
+ // 1) + Uses less memory.
+ // 2) + Conceptually simplier as there is only one profile.
+ // 3) - We would need a check in all JSFunction object creations (both with classes and without) that the
+ // new.target's profiled structure has a JSFinalObject ClassInfo. This is needed, for example, if we have
+ // `Reflect.construct(Array, args, myConstructor)` since myConstructor will be the new.target of Array
+ // the Array constructor will set the allocation profile of myConstructor to hold an Array structure
+ //
+ // We don't really care about 1) since this memory is rare and small in total. 2) is unfortunate but is
+ // probably outweighed by the cost of 3).
+ ObjectAllocationProfile m_objectAllocationProfile;
+ InlineWatchpointSet m_objectAllocationProfileWatchpoint;
+ InternalFunctionAllocationProfile m_internalFunctionAllocationProfile;
+};
+
+} // namespace JSC
+
+#endif // FunctionRareData_h
diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp
deleted file mode 100644
index e1cc98867..000000000
--- a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- * 3. Neither the name of Apple Computer, 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "GCActivityCallback.h"
-
-#include "APIShims.h"
-#include "Heap.h"
-#include "VM.h"
-#include "JSLock.h"
-#include "JSObject.h"
-
-#include <wtf/RetainPtr.h>
-#include <wtf/WTFThreadData.h>
-
-#if PLATFORM(EFL)
-#include <wtf/MainThread.h>
-#endif
-
-namespace JSC {
-
-bool GCActivityCallback::s_shouldCreateGCTimer = true;
-
-#if USE(CF) || PLATFORM(EFL)
-
-const double gcTimeSlicePerMB = 0.01; // Percentage of CPU time we will spend to reclaim 1 MB
-const double maxGCTimeSlice = 0.05; // The maximum amount of CPU time we want to use for opportunistic timer-triggered collections.
-const double timerSlop = 2.0; // Fudge factor to avoid performance cost of resetting timer.
-
-#if !PLATFORM(IOS)
-const double pagingTimeOut = 0.1; // Time in seconds to allow opportunistic timer to iterate over all blocks to see if the Heap is paged out.
-#endif
-
-#if !USE(CF)
-const double hour = 60 * 60;
-#endif
-
-#if USE(CF)
-DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap)
- : GCActivityCallback(heap->vm(), CFRunLoopGetCurrent())
- , m_delay(s_decade)
-{
-}
-
-DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap, CFRunLoopRef runLoop)
- : GCActivityCallback(heap->vm(), runLoop)
- , m_delay(s_decade)
-{
-}
-#elif PLATFORM(EFL)
-DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap)
- : GCActivityCallback(heap->vm(), WTF::isMainThread())
- , m_delay(hour)
-{
-}
-#endif
-
-void DefaultGCActivityCallback::doWork()
-{
- Heap* heap = &m_vm->heap;
- if (!isEnabled())
- return;
-
- APIEntryShim shim(m_vm);
-#if !PLATFORM(IOS)
- double startTime = WTF::monotonicallyIncreasingTime();
- if (heap->isPagedOut(startTime + pagingTimeOut)) {
- heap->activityCallback()->cancel();
- heap->increaseLastGCLength(pagingTimeOut);
- return;
- }
-#endif
- heap->collect();
-}
-
-#if USE(CF)
-void DefaultGCActivityCallback::scheduleTimer(double newDelay)
-{
- if (newDelay * timerSlop > m_delay)
- return;
- double delta = m_delay - newDelay;
- m_delay = newDelay;
- CFRunLoopTimerSetNextFireDate(m_timer.get(), CFRunLoopTimerGetNextFireDate(m_timer.get()) - delta);
-}
-
-void DefaultGCActivityCallback::cancelTimer()
-{
- m_delay = s_decade;
- CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade);
-}
-#elif PLATFORM(EFL)
-void DefaultGCActivityCallback::scheduleTimer(double newDelay)
-{
- if (newDelay * timerSlop > m_delay)
- return;
-
- stop();
- m_delay = newDelay;
-
- ASSERT(!m_timer);
- m_timer = add(newDelay, this);
-}
-
-void DefaultGCActivityCallback::cancelTimer()
-{
- m_delay = hour;
- stop();
-}
-#endif
-
-void DefaultGCActivityCallback::didAllocate(size_t bytes)
-{
-#if PLATFORM(EFL)
- if (!isEnabled())
- return;
-
- ASSERT(WTF::isMainThread());
-#endif
-
- // The first byte allocated in an allocation cycle will report 0 bytes to didAllocate.
- // We pretend it's one byte so that we don't ignore this allocation entirely.
- if (!bytes)
- bytes = 1;
- Heap* heap = static_cast<Heap*>(&m_vm->heap);
- double gcTimeSlice = std::min((static_cast<double>(bytes) / MB) * gcTimeSlicePerMB, maxGCTimeSlice);
- double newDelay = heap->lastGCLength() / gcTimeSlice;
- scheduleTimer(newDelay);
-}
-
-void DefaultGCActivityCallback::willCollect()
-{
- cancelTimer();
-}
-
-void DefaultGCActivityCallback::cancel()
-{
- cancelTimer();
-}
-
-#else
-
-DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap)
- : GCActivityCallback(heap->vm())
-{
-}
-
-void DefaultGCActivityCallback::doWork()
-{
-}
-
-void DefaultGCActivityCallback::didAllocate(size_t)
-{
-}
-
-void DefaultGCActivityCallback::willCollect()
-{
-}
-
-void DefaultGCActivityCallback::cancel()
-{
-}
-
-#endif
-
-}
-
diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.h b/Source/JavaScriptCore/runtime/GCActivityCallback.h
deleted file mode 100644
index 0228c2c68..000000000
--- a/Source/JavaScriptCore/runtime/GCActivityCallback.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- * 3. Neither the name of Apple Computer, 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
- */
-
-#ifndef GCActivityCallback_h
-#define GCActivityCallback_h
-
-#include "HeapTimer.h"
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
-
-#if USE(CF)
-#include <CoreFoundation/CoreFoundation.h>
-#endif
-
-namespace JSC {
-
-class Heap;
-
-class GCActivityCallback : public HeapTimer {
- WTF_MAKE_FAST_ALLOCATED;
-public:
- virtual void didAllocate(size_t) { }
- virtual void willCollect() { }
- virtual void cancel() { }
- bool isEnabled() const { return m_enabled; }
- void setEnabled(bool enabled) { m_enabled = enabled; }
-
- static bool s_shouldCreateGCTimer;
-
-protected:
-#if USE(CF)
- GCActivityCallback(VM* vm, CFRunLoopRef runLoop)
- : HeapTimer(vm, runLoop)
- , m_enabled(true)
- {
- }
-#elif PLATFORM(EFL)
- GCActivityCallback(VM* vm, bool flag)
- : HeapTimer(vm)
- , m_enabled(flag)
- {
- }
-#else
- GCActivityCallback(VM* vm)
- : HeapTimer(vm)
- , m_enabled(true)
- {
- }
-#endif
-
- bool m_enabled;
-};
-
-class DefaultGCActivityCallback : public GCActivityCallback {
-public:
- static PassOwnPtr<DefaultGCActivityCallback> create(Heap*);
-
- DefaultGCActivityCallback(Heap*);
-
- JS_EXPORT_PRIVATE virtual void didAllocate(size_t) override;
- JS_EXPORT_PRIVATE virtual void willCollect() override;
- JS_EXPORT_PRIVATE virtual void cancel() override;
-
- JS_EXPORT_PRIVATE virtual void doWork() override;
-
-#if USE(CF)
-protected:
- JS_EXPORT_PRIVATE DefaultGCActivityCallback(Heap*, CFRunLoopRef);
-#endif
-#if USE(CF) || PLATFORM(EFL)
-protected:
- void cancelTimer();
- void scheduleTimer(double);
-
-private:
- double m_delay;
-#endif
-};
-
-inline PassOwnPtr<DefaultGCActivityCallback> DefaultGCActivityCallback::create(Heap* heap)
-{
- return GCActivityCallback::s_shouldCreateGCTimer ? adoptPtr(new DefaultGCActivityCallback(heap)) : nullptr;
-}
-
-}
-
-#endif
diff --git a/Source/JavaScriptCore/runtime/GeneratorFrame.cpp b/Source/JavaScriptCore/runtime/GeneratorFrame.cpp
new file mode 100644
index 000000000..ef6ea7a10
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorFrame.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 "GeneratorFrame.h"
+
+#include "CodeBlock.h"
+#include "HeapIterationScope.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+const ClassInfo GeneratorFrame::s_info = { "GeneratorFrame", nullptr, nullptr, CREATE_METHOD_TABLE(GeneratorFrame) };
+
+GeneratorFrame::GeneratorFrame(VM& vm, size_t numberOfCalleeLocals)
+ : Base(vm, vm.generatorFrameStructure.get())
+ , m_numberOfCalleeLocals(numberOfCalleeLocals)
+{
+}
+
+void GeneratorFrame::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ for (size_t i = 0; i < m_numberOfCalleeLocals; ++i)
+ localAt(i).clear();
+}
+
+Structure* GeneratorFrame::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+}
+
+GeneratorFrame* GeneratorFrame::create(VM& vm, size_t numberOfLocals)
+{
+ GeneratorFrame* result =
+ new (
+ NotNull,
+ allocateCell<GeneratorFrame>(vm.heap, allocationSizeForLocals(numberOfLocals)))
+ GeneratorFrame(vm, numberOfLocals);
+ result->finishCreation(vm);
+ return result;
+}
+
+void GeneratorFrame::save(ExecState* exec, const FastBitVector& liveCalleeLocals)
+{
+ // Only save callee locals.
+ // Every time a generator is called (or resumed), parameters should be replaced.
+ ASSERT(liveCalleeLocals.numBits() <= m_numberOfCalleeLocals);
+ liveCalleeLocals.forEachSetBit([&](size_t index) {
+ localAt(index).set(exec->vm(), this, exec->uncheckedR(virtualRegisterForLocal(index)).jsValue());
+ });
+}
+
+void GeneratorFrame::resume(ExecState* exec, const FastBitVector& liveCalleeLocals)
+{
+ // Only resume callee locals.
+ // Every time a generator is called (or resumed), parameters should be replaced.
+ liveCalleeLocals.forEachSetBit([&](size_t index) {
+ exec->uncheckedR(virtualRegisterForLocal(index)) = localAt(index).get();
+ localAt(index).clear();
+ });
+}
+
+void GeneratorFrame::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ GeneratorFrame* thisObject = jsCast<GeneratorFrame*>(cell);
+ Base::visitChildren(thisObject, visitor);
+ // Since only true cell pointers are stored as a cell, we can safely mark them.
+ visitor.appendValues(thisObject->locals(), thisObject->m_numberOfCalleeLocals);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/GeneratorFrame.h b/Source/JavaScriptCore/runtime/GeneratorFrame.h
new file mode 100644
index 000000000..3d545b147
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorFrame.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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.
+ */
+
+#ifndef GeneratorFrame_h
+#define GeneratorFrame_h
+
+#include "JSCell.h"
+#include <wtf/FastBitVector.h>
+
+namespace JSC {
+
+class GeneratorFrame : public JSCell {
+ friend class JIT;
+#if ENABLE(DFG_JIT)
+ friend class DFG::SpeculativeJIT;
+ friend class DFG::JITCompiler;
+#endif
+ friend class VM;
+public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = StructureIsImmortal | Base::StructureFlags;
+
+ DECLARE_EXPORT_INFO;
+
+ static GeneratorFrame* create(VM&, size_t numberOfCalleeLocals);
+
+ WriteBarrierBase<Unknown>* locals()
+ {
+ return bitwise_cast<WriteBarrierBase<Unknown>*>(bitwise_cast<char*>(this) + offsetOfLocals());
+ }
+
+ WriteBarrierBase<Unknown>& localAt(size_t index)
+ {
+ ASSERT(index < m_numberOfCalleeLocals);
+ return locals()[index];
+ }
+
+ static size_t offsetOfLocals()
+ {
+ return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(GeneratorFrame));
+ }
+
+ static size_t allocationSizeForLocals(unsigned numberOfLocals)
+ {
+ return offsetOfLocals() + numberOfLocals * sizeof(WriteBarrier<Unknown>);
+ }
+
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+
+ void save(ExecState*, const FastBitVector& liveCalleeLocals);
+ void resume(ExecState*, const FastBitVector& liveCalleeLocals);
+
+private:
+ GeneratorFrame(VM&, size_t numberOfCalleeLocals);
+
+ size_t m_numberOfCalleeLocals;
+
+ friend class LLIntOffsetsExtractor;
+
+ void finishCreation(VM&);
+
+protected:
+ static void visitChildren(JSCell*, SlotVisitor&);
+};
+
+} // namespace JSC
+
+#endif // GeneratorFrame_h
diff --git a/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.cpp b/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.cpp
new file mode 100644
index 000000000..28f58931f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 "GeneratorFunctionConstructor.h"
+
+#include "FunctionConstructor.h"
+#include "GeneratorFunctionPrototype.h"
+#include "JSCInlines.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(GeneratorFunctionConstructor);
+
+const ClassInfo GeneratorFunctionConstructor::s_info = { "GeneratorFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(GeneratorFunctionConstructor) };
+
+GeneratorFunctionConstructor::GeneratorFunctionConstructor(VM& vm, Structure* structure)
+ : InternalFunction(vm, structure)
+{
+}
+
+void GeneratorFunctionConstructor::finishCreation(VM& vm, GeneratorFunctionPrototype* generatorFunctionPrototype)
+{
+ Base::finishCreation(vm, "GeneratorFunction");
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, generatorFunctionPrototype, DontEnum | DontDelete | ReadOnly);
+
+ // Number of arguments for constructor
+ putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontDelete | DontEnum);
+}
+
+static EncodedJSValue JSC_HOST_CALL callGeneratorFunctionConstructor(ExecState* exec)
+{
+ ArgList args(exec);
+ return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args, FunctionConstructionMode::Generator));
+}
+
+static EncodedJSValue JSC_HOST_CALL constructGeneratorFunctionConstructor(ExecState* exec)
+{
+ ArgList args(exec);
+ return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args, FunctionConstructionMode::Generator));
+}
+
+CallType GeneratorFunctionConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callGeneratorFunctionConstructor;
+ return CallTypeHost;
+}
+
+ConstructType GeneratorFunctionConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructGeneratorFunctionConstructor;
+ return ConstructTypeHost;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.h b/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.h
new file mode 100644
index 000000000..c86c87ba1
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorFunctionConstructor.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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.
+ */
+
+#ifndef GeneratorFunctionConstructor_h
+#define GeneratorFunctionConstructor_h
+
+#include "InternalFunction.h"
+
+namespace WTF {
+class TextPosition;
+}
+
+namespace JSC {
+
+class GeneratorFunctionPrototype;
+
+class GeneratorFunctionConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+
+ static GeneratorFunctionConstructor* create(VM& vm, Structure* structure, GeneratorFunctionPrototype* generatorFunctionPrototype)
+ {
+ GeneratorFunctionConstructor* constructor = new (NotNull, allocateCell<GeneratorFunctionConstructor>(vm.heap)) GeneratorFunctionConstructor(vm, structure);
+ constructor->finishCreation(vm, generatorFunctionPrototype);
+ return constructor;
+ }
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+private:
+ GeneratorFunctionConstructor(VM&, Structure*);
+ void finishCreation(VM&, GeneratorFunctionPrototype*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+};
+
+} // namespace JSC
+
+#endif // GeneratorFunctionConstructor_h
diff --git a/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.cpp b/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.cpp
new file mode 100644
index 000000000..33fe8f2e3
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 "GeneratorFunctionPrototype.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 {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(GeneratorFunctionPrototype);
+
+const ClassInfo GeneratorFunctionPrototype::s_info = { "GeneratorFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(GeneratorFunctionPrototype) };
+
+GeneratorFunctionPrototype::GeneratorFunctionPrototype(VM& vm, Structure* structure)
+ : JSNonFinalObject(vm, structure)
+{
+}
+
+void GeneratorFunctionPrototype::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.h b/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.h
new file mode 100644
index 000000000..d0a034926
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorFunctionPrototype.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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.
+ */
+
+#ifndef GeneratorFunctionPrototype_h
+#define GeneratorFunctionPrototype_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class GeneratorFunctionPrototype : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+
+ static GeneratorFunctionPrototype* create(VM& vm, Structure* structure)
+ {
+ GeneratorFunctionPrototype* prototype = new (NotNull, allocateCell<GeneratorFunctionPrototype>(vm.heap)) GeneratorFunctionPrototype(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());
+ }
+
+ DECLARE_INFO;
+
+protected:
+ void finishCreation(VM&);
+
+private:
+ GeneratorFunctionPrototype(VM&, Structure*);
+};
+
+} // namespace JSC
+
+#endif // GeneratorFunctionPrototype_h
diff --git a/Source/JavaScriptCore/runtime/GeneratorPrototype.cpp b/Source/JavaScriptCore/runtime/GeneratorPrototype.cpp
new file mode 100644
index 000000000..af467b3bd
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorPrototype.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 "GeneratorPrototype.h"
+
+#include "JSCBuiltins.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSGlobalObject.h"
+#include "StructureInlines.h"
+
+#include "GeneratorPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo GeneratorPrototype::s_info = { "Generator", &Base::s_info, &generatorPrototypeTable, CREATE_METHOD_TABLE(GeneratorPrototype) };
+
+/* Source for GeneratorPrototype.lut.h
+@begin generatorPrototypeTable
+ next JSBuiltin DontEnum|Function 1
+ return JSBuiltin DontEnum|Function 1
+ throw JSBuiltin DontEnum|Function 1
+@end
+*/
+
+void GeneratorPrototype::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Generator"), DontEnum | ReadOnly);
+ vm.prototypeMap.addPrototype(this);
+}
+
+bool GeneratorPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<Base>(exec, generatorPrototypeTable, jsCast<GeneratorPrototype*>(object), propertyName, slot);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/GeneratorPrototype.h b/Source/JavaScriptCore/runtime/GeneratorPrototype.h
new file mode 100644
index 000000000..f10c44ded
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GeneratorPrototype.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 GeneratorPrototype_h
+#define GeneratorPrototype_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class GeneratorPrototype : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static GeneratorPrototype* create(VM& vm, JSGlobalObject*, Structure* structure)
+ {
+ GeneratorPrototype* prototype = new (NotNull, allocateCell<GeneratorPrototype>(vm.heap)) GeneratorPrototype(vm, structure);
+ prototype->finishCreation(vm);
+ return prototype;
+ }
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+
+private:
+ GeneratorPrototype(VM& vm, Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+ void finishCreation(VM&);
+};
+
+}
+
+#endif // !defined(GeneratorPrototype_h)
diff --git a/Source/JavaScriptCore/runtime/GenericArguments.h b/Source/JavaScriptCore/runtime/GenericArguments.h
new file mode 100644
index 000000000..67f1b0345
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GenericArguments.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef GenericArguments_h
+#define GenericArguments_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+// This is a mixin for the two kinds of Arguments-class objects that arise when you say
+// "arguments" inside a function. This class doesn't show up in the JSCell inheritance hierarchy.
+template<typename Type>
+class GenericArguments : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames;
+
+protected:
+ GenericArguments(VM& vm, Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ 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 copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length);
+};
+
+} // namespace JSC
+
+#endif // GenericArguments_h
+
diff --git a/Source/JavaScriptCore/runtime/GenericArgumentsInlines.h b/Source/JavaScriptCore/runtime/GenericArgumentsInlines.h
new file mode 100644
index 000000000..9b1800185
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GenericArgumentsInlines.h
@@ -0,0 +1,233 @@
+/*
+ * 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.
+ */
+
+#ifndef GenericArgumentsInlines_h
+#define GenericArgumentsInlines_h
+
+#include "GenericArguments.h"
+#include "JSCInlines.h"
+
+namespace JSC {
+
+template<typename Type>
+bool GenericArguments<Type>::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName ident, PropertySlot& slot)
+{
+ Type* thisObject = jsCast<Type*>(object);
+ VM& vm = exec->vm();
+
+ if (!thisObject->overrodeThings()) {
+ if (ident == vm.propertyNames->length) {
+ slot.setValue(thisObject, DontEnum, jsNumber(thisObject->internalLength()));
+ return true;
+ }
+ if (ident == vm.propertyNames->callee) {
+ slot.setValue(thisObject, DontEnum, thisObject->callee().get());
+ return true;
+ }
+ if (ident == vm.propertyNames->iteratorSymbol) {
+ slot.setValue(thisObject, DontEnum, thisObject->globalObject()->arrayProtoValuesFunction());
+ return true;
+ }
+ }
+
+ Optional<uint32_t> index = parseIndex(ident);
+ if (index && thisObject->canAccessIndexQuickly(index.value())) {
+ slot.setValue(thisObject, None, thisObject->getIndexQuickly(index.value()));
+ return true;
+ }
+
+ return Base::getOwnPropertySlot(thisObject, exec, ident, slot);
+}
+
+template<typename Type>
+bool GenericArguments<Type>::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)
+{
+ Type* thisObject = jsCast<Type*>(object);
+
+ if (thisObject->canAccessIndexQuickly(index)) {
+ slot.setValue(thisObject, None, thisObject->getIndexQuickly(index));
+ return true;
+ }
+
+ return Base::getOwnPropertySlotByIndex(object, exec, index, slot);
+}
+
+template<typename Type>
+void GenericArguments<Type>::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode)
+{
+ Type* thisObject = jsCast<Type*>(object);
+
+ if (array.includeStringProperties()) {
+ for (unsigned i = 0; i < thisObject->internalLength(); ++i) {
+ if (!thisObject->canAccessIndexQuickly(i))
+ continue;
+ array.add(Identifier::from(exec, i));
+ }
+ }
+
+ if (mode.includeDontEnumProperties() && !thisObject->overrodeThings()) {
+ array.add(exec->propertyNames().length);
+ array.add(exec->propertyNames().callee);
+ if (array.includeSymbolProperties())
+ array.add(exec->propertyNames().iteratorSymbol);
+ }
+ Base::getOwnPropertyNames(thisObject, exec, array, mode);
+}
+
+template<typename Type>
+void GenericArguments<Type>::put(JSCell* cell, ExecState* exec, PropertyName ident, JSValue value, PutPropertySlot& slot)
+{
+ Type* thisObject = jsCast<Type*>(cell);
+ VM& vm = exec->vm();
+
+ if (!thisObject->overrodeThings()
+ && (ident == vm.propertyNames->length
+ || ident == vm.propertyNames->callee
+ || ident == vm.propertyNames->iteratorSymbol)) {
+ thisObject->overrideThings(vm);
+ PutPropertySlot dummy = slot; // This put is not cacheable, so we shadow the slot that was given to us.
+ Base::put(thisObject, exec, ident, value, dummy);
+ return;
+ }
+
+ Optional<uint32_t> index = parseIndex(ident);
+ if (index && thisObject->canAccessIndexQuickly(index.value())) {
+ thisObject->setIndexQuickly(vm, index.value(), value);
+ return;
+ }
+
+ Base::put(thisObject, exec, ident, value, slot);
+}
+
+template<typename Type>
+void GenericArguments<Type>::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow)
+{
+ Type* thisObject = jsCast<Type*>(cell);
+ VM& vm = exec->vm();
+
+ if (thisObject->canAccessIndexQuickly(index)) {
+ thisObject->setIndexQuickly(vm, index, value);
+ return;
+ }
+
+ return Base::putByIndex(cell, exec, index, value, shouldThrow);
+}
+
+template<typename Type>
+bool GenericArguments<Type>::deleteProperty(JSCell* cell, ExecState* exec, PropertyName ident)
+{
+ Type* thisObject = jsCast<Type*>(cell);
+ VM& vm = exec->vm();
+
+ if (!thisObject->overrodeThings()
+ && (ident == vm.propertyNames->length
+ || ident == vm.propertyNames->callee
+ || ident == vm.propertyNames->iteratorSymbol))
+ thisObject->overrideThings(vm);
+
+ Optional<uint32_t> index = parseIndex(ident);
+ if (index && thisObject->canAccessIndexQuickly(index.value())) {
+ thisObject->overrideArgument(vm, index.value());
+ return true;
+ }
+
+ return Base::deleteProperty(thisObject, exec, ident);
+}
+
+template<typename Type>
+bool GenericArguments<Type>::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned index)
+{
+ Type* thisObject = jsCast<Type*>(cell);
+ VM& vm = exec->vm();
+
+ if (thisObject->canAccessIndexQuickly(index)) {
+ thisObject->overrideArgument(vm, index);
+ return true;
+ }
+
+ return Base::deletePropertyByIndex(cell, exec, index);
+}
+
+template<typename Type>
+bool GenericArguments<Type>::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName ident, const PropertyDescriptor& descriptor, bool shouldThrow)
+{
+ Type* thisObject = jsCast<Type*>(object);
+ VM& vm = exec->vm();
+
+ if (ident == vm.propertyNames->length
+ || ident == vm.propertyNames->callee
+ || ident == vm.propertyNames->iteratorSymbol)
+ thisObject->overrideThingsIfNecessary(vm);
+ else {
+ Optional<uint32_t> optionalIndex = parseIndex(ident);
+ if (optionalIndex && thisObject->canAccessIndexQuickly(optionalIndex.value())) {
+ uint32_t index = optionalIndex.value();
+ if (!descriptor.isAccessorDescriptor()) {
+ // If the property is not deleted and we are using a non-accessor descriptor, then
+ // make sure that the aliased argument sees the value.
+ if (descriptor.value())
+ thisObject->setIndexQuickly(vm, index, descriptor.value());
+
+ // If the property is not deleted and we are using a non-accessor, writable
+ // descriptor, then we are done. The argument continues to be aliased. Note that we
+ // ignore the request to change enumerability. We appear to have always done so, in
+ // cases where the argument was still aliased.
+ // FIXME: https://bugs.webkit.org/show_bug.cgi?id=141952
+ if (descriptor.writable())
+ return true;
+ }
+
+ // If the property is a non-deleted argument, then move it into the base object and
+ // then delete it.
+ JSValue value = thisObject->getIndexQuickly(index);
+ ASSERT(value);
+ object->putDirectMayBeIndex(exec, ident, value);
+ thisObject->overrideArgument(vm, index);
+ }
+ }
+
+ // Now just let the normal object machinery do its thing.
+ return Base::defineOwnProperty(object, exec, ident, descriptor, shouldThrow);
+}
+
+template<typename Type>
+void GenericArguments<Type>::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length)
+{
+ Type* thisObject = static_cast<Type*>(this);
+ for (unsigned i = 0; i < length; ++i) {
+ if (thisObject->canAccessIndexQuickly(i + offset))
+ exec->r(firstElementDest + i) = thisObject->getIndexQuickly(i + offset);
+ else {
+ exec->r(firstElementDest + i) = get(exec, i + offset);
+ if (UNLIKELY(exec->vm().exception()))
+ return;
+ }
+ }
+}
+
+} // namespace JSC
+
+#endif // GenericArgumentsInlines_h
+
diff --git a/Source/JavaScriptCore/runtime/GenericOffset.h b/Source/JavaScriptCore/runtime/GenericOffset.h
new file mode 100644
index 000000000..2ac5d421d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GenericOffset.h
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#ifndef GenericOffset_h
+#define GenericOffset_h
+
+#include <limits.h>
+#include <wtf/Assertions.h>
+
+namespace JSC {
+
+// A mixin for creating the various kinds of variable offsets that our engine supports.
+template<typename T>
+class GenericOffset {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ static const unsigned invalidOffset = UINT_MAX;
+
+ GenericOffset()
+ : m_offset(invalidOffset)
+ {
+ }
+
+ explicit GenericOffset(unsigned offset)
+ : m_offset(offset)
+ {
+ }
+
+ bool operator!() const { return m_offset == invalidOffset; }
+
+ unsigned offsetUnchecked() const
+ {
+ return m_offset;
+ }
+
+ unsigned offset() const
+ {
+ ASSERT(m_offset != invalidOffset);
+ return m_offset;
+ }
+
+ bool operator==(const T& other) const
+ {
+ return m_offset == other.offsetUnchecked();
+ }
+ bool operator!=(const T& other) const
+ {
+ return m_offset != other.offsetUnchecked();
+ }
+ bool operator<(const T& other) const
+ {
+ return m_offset < other.offsetUnchecked();
+ }
+ bool operator>(const T& other) const
+ {
+ return m_offset > other.offsetUnchecked();
+ }
+ bool operator<=(const T& other) const
+ {
+ return m_offset <= other.offsetUnchecked();
+ }
+ bool operator>=(const T& other) const
+ {
+ return m_offset >= other.offsetUnchecked();
+ }
+
+ T operator+(int value) const
+ {
+ return T(offset() + value);
+ }
+ T operator-(int value) const
+ {
+ return T(offset() - value);
+ }
+ T& operator+=(int value)
+ {
+ return *this = *this + value;
+ }
+ T& operator-=(int value)
+ {
+ return *this = *this - value;
+ }
+
+private:
+ unsigned m_offset;
+};
+
+} // namespace JSC
+
+#endif // GenericOffset_h
+
diff --git a/Source/JavaScriptCore/runtime/GenericTypedArrayView.h b/Source/JavaScriptCore/runtime/GenericTypedArrayView.h
index 0069b386d..36e37ca32 100644
--- a/Source/JavaScriptCore/runtime/GenericTypedArrayView.h
+++ b/Source/JavaScriptCore/runtime/GenericTypedArrayView.h
@@ -37,11 +37,11 @@ protected:
GenericTypedArrayView(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length);
public:
- static PassRefPtr<GenericTypedArrayView> create(unsigned length);
- static PassRefPtr<GenericTypedArrayView> create(const typename Adaptor::Type* array, unsigned length);
- static PassRefPtr<GenericTypedArrayView> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length);
+ static RefPtr<GenericTypedArrayView> create(unsigned length);
+ static RefPtr<GenericTypedArrayView> create(const typename Adaptor::Type* array, unsigned length);
+ static RefPtr<GenericTypedArrayView> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length);
- static PassRefPtr<GenericTypedArrayView> createUninitialized(unsigned length);
+ static RefPtr<GenericTypedArrayView> createUninitialized(unsigned length);
typename Adaptor::Type* data() const { return static_cast<typename Adaptor::Type*>(baseAddress()); }
@@ -98,8 +98,8 @@ public:
&& offset + pos >= offset);
}
- PassRefPtr<GenericTypedArrayView> subarray(int start) const;
- PassRefPtr<GenericTypedArrayView> subarray(int start, int end) const;
+ RefPtr<GenericTypedArrayView> subarray(int start) const;
+ RefPtr<GenericTypedArrayView> subarray(int start, int end) const;
virtual TypedArrayType getType() const override
{
diff --git a/Source/JavaScriptCore/runtime/GenericTypedArrayViewInlines.h b/Source/JavaScriptCore/runtime/GenericTypedArrayViewInlines.h
index 1289c5035..253726965 100644
--- a/Source/JavaScriptCore/runtime/GenericTypedArrayViewInlines.h
+++ b/Source/JavaScriptCore/runtime/GenericTypedArrayViewInlines.h
@@ -40,16 +40,16 @@ GenericTypedArrayView<Adaptor>::GenericTypedArrayView(
}
template<typename Adaptor>
-PassRefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::create(unsigned length)
+RefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::create(unsigned length)
{
RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(length, sizeof(typename Adaptor::Type));
if (!buffer)
- return 0;
- return create(buffer, 0, length);
+ return nullptr;
+ return create(buffer.release(), 0, length);
}
template<typename Adaptor>
-PassRefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::create(
+RefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::create(
const typename Adaptor::Type* array, unsigned length)
{
RefPtr<GenericTypedArrayView> result = create(length);
@@ -58,36 +58,38 @@ PassRefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::creat
}
template<typename Adaptor>
-PassRefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::create(
+RefPtr<GenericTypedArrayView<Adaptor>> GenericTypedArrayView<Adaptor>::create(
PassRefPtr<ArrayBuffer> passedBuffer, unsigned byteOffset, unsigned length)
{
RefPtr<ArrayBuffer> buffer = passedBuffer;
- if (!verifySubRange<typename Adaptor::Type>(buffer, byteOffset, length))
- return 0;
+ if (!verifySubRangeLength(buffer, byteOffset, length, sizeof(typename Adaptor::Type))
+ || !verifyByteOffsetAlignment(byteOffset, sizeof(typename Adaptor::Type))) {
+ return nullptr;
+ }
- return adoptRef(new GenericTypedArrayView(buffer, byteOffset, length));
+ return adoptRef(new GenericTypedArrayView(buffer.release(), byteOffset, length));
}
template<typename Adaptor>
-PassRefPtr<GenericTypedArrayView<Adaptor>>
+RefPtr<GenericTypedArrayView<Adaptor>>
GenericTypedArrayView<Adaptor>::createUninitialized(unsigned length)
{
RefPtr<ArrayBuffer> buffer =
ArrayBuffer::createUninitialized(length, sizeof(typename Adaptor::Type));
if (!buffer)
- return 0;
- return create(buffer, 0, length);
+ return nullptr;
+ return create(buffer.release(), 0, length);
}
template<typename Adaptor>
-PassRefPtr<GenericTypedArrayView<Adaptor>>
+RefPtr<GenericTypedArrayView<Adaptor>>
GenericTypedArrayView<Adaptor>::subarray(int start) const
{
return subarray(start, length());
}
template<typename Adaptor>
-PassRefPtr<GenericTypedArrayView<Adaptor>>
+RefPtr<GenericTypedArrayView<Adaptor>>
GenericTypedArrayView<Adaptor>::subarray(int start, int end) const
{
unsigned offset, length;
diff --git a/Source/JavaScriptCore/runtime/GetPutInfo.h b/Source/JavaScriptCore/runtime/GetPutInfo.h
new file mode 100644
index 000000000..f499bcd89
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GetPutInfo.h
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ */
+
+#ifndef GetPutInfo_h
+#define GetPutInfo_h
+
+#include <wtf/text/UniquedStringImpl.h>
+
+namespace JSC {
+
+class Structure;
+class WatchpointSet;
+class JSLexicalEnvironment;
+
+enum ResolveMode {
+ ThrowIfNotFound,
+ DoNotThrowIfNotFound
+};
+
+enum ResolveType {
+ // Lexical scope guaranteed a certain type of variable access.
+ GlobalProperty,
+ GlobalVar,
+ GlobalLexicalVar,
+ ClosureVar,
+ LocalClosureVar,
+ ModuleVar,
+
+ // Ditto, but at least one intervening scope used non-strict eval, which
+ // can inject an intercepting var delcaration at runtime.
+ GlobalPropertyWithVarInjectionChecks,
+ GlobalVarWithVarInjectionChecks,
+ GlobalLexicalVarWithVarInjectionChecks,
+ ClosureVarWithVarInjectionChecks,
+
+ // We haven't found which scope this belongs to, and we also
+ // haven't ruled out the possibility of it being cached. Ideally,
+ // we want to transition this to GlobalVar/GlobalLexicalVar/GlobalProperty <with/without injection>
+ UnresolvedProperty,
+ UnresolvedPropertyWithVarInjectionChecks,
+
+ // Lexical scope didn't prove anything -- probably because of a 'with' scope.
+ Dynamic
+};
+
+enum InitializationMode {
+ Initialization, // "let x = 20;"
+ NotInitialization // "x = 20;"
+};
+
+ALWAYS_INLINE const char* resolveModeName(ResolveMode resolveMode)
+{
+ static const char* const names[] = {
+ "ThrowIfNotFound",
+ "DoNotThrowIfNotFound"
+ };
+ return names[resolveMode];
+}
+
+ALWAYS_INLINE const char* resolveTypeName(ResolveType type)
+{
+ static const char* const names[] = {
+ "GlobalProperty",
+ "GlobalVar",
+ "GlobalLexicalVar",
+ "ClosureVar",
+ "LocalClosureVar",
+ "ModuleVar",
+ "GlobalPropertyWithVarInjectionChecks",
+ "GlobalVarWithVarInjectionChecks",
+ "GlobalLexicalVarWithVarInjectionChecks",
+ "ClosureVarWithVarInjectionChecks",
+ "UnresolvedProperty",
+ "UnresolvedPropertyWithVarInjectionChecks",
+ "Dynamic"
+ };
+ return names[type];
+}
+
+ALWAYS_INLINE const char* initializationModeName(InitializationMode initializationMode)
+{
+ static const char* const names[] = {
+ "Initialization",
+ "NotInitialization"
+ };
+ return names[initializationMode];
+}
+
+
+ALWAYS_INLINE ResolveType makeType(ResolveType type, bool needsVarInjectionChecks)
+{
+ if (!needsVarInjectionChecks)
+ return type;
+
+ switch (type) {
+ case GlobalProperty:
+ return GlobalPropertyWithVarInjectionChecks;
+ case GlobalVar:
+ return GlobalVarWithVarInjectionChecks;
+ case GlobalLexicalVar:
+ return GlobalLexicalVarWithVarInjectionChecks;
+ case ClosureVar:
+ case LocalClosureVar:
+ return ClosureVarWithVarInjectionChecks;
+ case UnresolvedProperty:
+ return UnresolvedPropertyWithVarInjectionChecks;
+ case ModuleVar:
+ case GlobalPropertyWithVarInjectionChecks:
+ case GlobalVarWithVarInjectionChecks:
+ case GlobalLexicalVarWithVarInjectionChecks:
+ case ClosureVarWithVarInjectionChecks:
+ case UnresolvedPropertyWithVarInjectionChecks:
+ case Dynamic:
+ return type;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+ return type;
+}
+
+ALWAYS_INLINE bool needsVarInjectionChecks(ResolveType type)
+{
+ switch (type) {
+ case GlobalProperty:
+ case GlobalVar:
+ case GlobalLexicalVar:
+ case ClosureVar:
+ case LocalClosureVar:
+ case ModuleVar:
+ case UnresolvedProperty:
+ return false;
+ case GlobalPropertyWithVarInjectionChecks:
+ case GlobalVarWithVarInjectionChecks:
+ case GlobalLexicalVarWithVarInjectionChecks:
+ case ClosureVarWithVarInjectionChecks:
+ case UnresolvedPropertyWithVarInjectionChecks:
+ case Dynamic:
+ return true;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return true;
+ }
+}
+
+struct ResolveOp {
+ ResolveOp(ResolveType type, size_t depth, Structure* structure, JSLexicalEnvironment* lexicalEnvironment, WatchpointSet* watchpointSet, uintptr_t operand, UniquedStringImpl* importedName = nullptr)
+ : type(type)
+ , depth(depth)
+ , structure(structure)
+ , lexicalEnvironment(lexicalEnvironment)
+ , watchpointSet(watchpointSet)
+ , operand(operand)
+ , importedName(importedName)
+ {
+ }
+
+ ResolveType type;
+ size_t depth;
+ Structure* structure;
+ JSLexicalEnvironment* lexicalEnvironment;
+ WatchpointSet* watchpointSet;
+ uintptr_t operand;
+ RefPtr<UniquedStringImpl> importedName;
+};
+
+class GetPutInfo {
+ typedef unsigned Operand;
+public:
+ // Give each field 10 bits for simplicity.
+ static_assert(sizeof(Operand) * 8 > 30, "Not enough bits for GetPutInfo");
+ static const unsigned modeShift = 20;
+ static const unsigned initializationShift = 10;
+ static const unsigned typeBits = (1 << initializationShift) - 1;
+ static const unsigned initializationBits = ((1 << modeShift) - 1) & ~typeBits;
+ static const unsigned modeBits = ((1 << 30) - 1) & ~initializationBits & ~typeBits;
+ static_assert((modeBits & initializationBits & typeBits) == 0x0, "There should be no intersection between ResolveMode ResolveType and InitializationMode");
+
+ GetPutInfo(ResolveMode resolveMode, ResolveType resolveType, InitializationMode initializationMode)
+ : m_operand((resolveMode << modeShift) | (initializationMode << initializationShift) | resolveType)
+ {
+ }
+
+ explicit GetPutInfo(unsigned operand)
+ : m_operand(operand)
+ {
+ }
+
+ ResolveType resolveType() const { return static_cast<ResolveType>(m_operand & typeBits); }
+ InitializationMode initializationMode() const { return static_cast<InitializationMode>((m_operand & initializationBits) >> initializationShift); }
+ ResolveMode resolveMode() const { return static_cast<ResolveMode>((m_operand & modeBits) >> modeShift); }
+ unsigned operand() { return m_operand; }
+
+private:
+ Operand m_operand;
+};
+
+enum GetOrPut { Get, Put };
+
+} // namespace JSC
+
+#endif // GetPutInfo_h
diff --git a/Source/JavaScriptCore/runtime/GetterSetter.cpp b/Source/JavaScriptCore/runtime/GetterSetter.cpp
index 21a7153c0..2cd66e5cd 100644
--- a/Source/JavaScriptCore/runtime/GetterSetter.cpp
+++ b/Source/JavaScriptCore/runtime/GetterSetter.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2004, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2007, 2008, 2009, 2014 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
@@ -24,57 +24,84 @@
#include "GetterSetter.h"
#include "Error.h"
+#include "Exception.h"
#include "JSObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include <wtf/Assertions.h>
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(GetterSetter);
-const ClassInfo GetterSetter::s_info = { "GetterSetter", 0, 0, 0, CREATE_METHOD_TABLE(GetterSetter) };
+const ClassInfo GetterSetter::s_info = { "GetterSetter", 0, 0, CREATE_METHOD_TABLE(GetterSetter) };
void GetterSetter::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
GetterSetter* thisObject = jsCast<GetterSetter*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
JSCell::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_getter);
visitor.append(&thisObject->m_setter);
}
+GetterSetter* GetterSetter::withGetter(VM& vm, JSGlobalObject* globalObject, JSObject* newGetter)
+{
+ if (isGetterNull()) {
+ setGetter(vm, globalObject, newGetter);
+ return this;
+ }
+
+ GetterSetter* result = GetterSetter::create(vm, globalObject);
+ result->setGetter(vm, globalObject, newGetter);
+ result->setSetter(vm, globalObject, setter());
+ return result;
+}
+
+GetterSetter* GetterSetter::withSetter(VM& vm, JSGlobalObject* globalObject, JSObject* newSetter)
+{
+ if (isSetterNull()) {
+ setSetter(vm, globalObject, newSetter);
+ return this;
+ }
+
+ GetterSetter* result = GetterSetter::create(vm, globalObject);
+ result->setGetter(vm, globalObject, getter());
+ result->setSetter(vm, globalObject, newSetter);
+ return result;
+}
+
JSValue callGetter(ExecState* exec, JSValue base, JSValue getterSetter)
{
// FIXME: Some callers may invoke get() without checking for an exception first.
// We work around that by checking here.
if (exec->hadException())
- return exec->exception();
+ return exec->exception()->value();
JSObject* getter = jsCast<GetterSetter*>(getterSetter)->getter();
- if (!getter)
- return jsUndefined();
CallData callData;
- CallType callType = getter->methodTable()->getCallData(getter, callData);
+ CallType callType = getter->methodTable(exec->vm())->getCallData(getter, callData);
return call(exec, getter, callType, callData, base, ArgList());
}
void callSetter(ExecState* exec, JSValue base, JSValue getterSetter, JSValue value, ECMAMode ecmaMode)
{
- JSObject* setter = jsCast<GetterSetter*>(getterSetter)->setter();
- if (!setter) {
+ GetterSetter* getterSetterObj = jsCast<GetterSetter*>(getterSetter);
+
+ if (getterSetterObj->isSetterNull()) {
if (ecmaMode == StrictMode)
throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
return;
}
+ JSObject* setter = getterSetterObj->setter();
+
MarkedArgumentBuffer args;
args.append(value);
CallData callData;
- CallType callType = setter->methodTable()->getCallData(setter, callData);
+ CallType callType = setter->methodTable(exec->vm())->getCallData(setter, callData);
call(exec, setter, callType, callData, base, args);
}
diff --git a/Source/JavaScriptCore/runtime/GetterSetter.h b/Source/JavaScriptCore/runtime/GetterSetter.h
index 5695bb9e7..cd204028e 100644
--- a/Source/JavaScriptCore/runtime/GetterSetter.h
+++ b/Source/JavaScriptCore/runtime/GetterSetter.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, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2014 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
@@ -26,61 +26,125 @@
#include "JSCell.h"
#include "CallFrame.h"
+#include "JSGlobalObject.h"
+#include "NullGetterFunction.h"
+#include "NullSetterFunction.h"
#include "Structure.h"
namespace JSC {
- class JSObject;
-
- // This is an internal value object which stores getter and setter functions
- // for a property.
- class GetterSetter : public JSCell {
- friend class JIT;
-
- private:
- GetterSetter(VM& vm)
- : JSCell(vm, vm.getterSetterStructure.get())
- {
- }
-
- public:
- typedef JSCell Base;
-
- static GetterSetter* create(VM& vm)
- {
- GetterSetter* getterSetter = new (NotNull, allocateCell<GetterSetter>(vm.heap)) GetterSetter(vm);
- getterSetter->finishCreation(vm);
- return getterSetter;
- }
-
- static void visitChildren(JSCell*, SlotVisitor&);
-
- JSObject* getter() const { return m_getter.get(); }
- void setGetter(VM& vm, JSObject* getter) { m_getter.setMayBeNull(vm, this, getter); }
- JSObject* setter() const { return m_setter.get(); }
- void setSetter(VM& vm, JSObject* setter) { m_setter.setMayBeNull(vm, this, setter); }
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(GetterSetterType, OverridesVisitChildren), info());
- }
-
- DECLARE_INFO;
-
- private:
- WriteBarrier<JSObject> m_getter;
- WriteBarrier<JSObject> m_setter;
- };
-
- GetterSetter* asGetterSetter(JSValue);
-
- inline GetterSetter* asGetterSetter(JSValue value)
+class JSObject;
+
+// This is an internal value object which stores getter and setter functions
+// for a property. Instances of this class have the property that once a getter
+// or setter is set to a non-null value, then they cannot be changed. This means
+// that if a property holding a GetterSetter reference is constant-inferred and
+// that constant is observed to have a non-null setter (or getter) then we can
+// constant fold that setter (or getter).
+class GetterSetter final : public JSCell {
+ friend class JIT;
+
+private:
+ GetterSetter(VM& vm, JSGlobalObject* globalObject)
+ : JSCell(vm, vm.getterSetterStructure.get())
+ {
+ m_getter.set(vm, this, globalObject->nullGetterFunction());
+ m_setter.set(vm, this, globalObject->nullSetterFunction());
+ }
+
+public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+ static GetterSetter* create(VM& vm, JSGlobalObject* globalObject)
+ {
+ GetterSetter* getterSetter = new (NotNull, allocateCell<GetterSetter>(vm.heap)) GetterSetter(vm, globalObject);
+ getterSetter->finishCreation(vm);
+ return getterSetter;
+ }
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ JSObject* getter() const { return m_getter.get(); }
+
+ JSObject* getterConcurrently() const
+ {
+ JSObject* result = getter();
+ WTF::loadLoadFence();
+ return result;
+ }
+
+ bool isGetterNull() const { return !!jsDynamicCast<NullGetterFunction*>(m_getter.get()); }
+ bool isSetterNull() const { return !!jsDynamicCast<NullSetterFunction*>(m_setter.get()); }
+
+ // Set the getter. It's only valid to call this if you've never set the getter on this
+ // object.
+ void setGetter(VM& vm, JSGlobalObject* globalObject, JSObject* getter)
+ {
+ if (!getter)
+ getter = jsCast<JSObject*>(globalObject->nullGetterFunction());
+
+ RELEASE_ASSERT(isGetterNull());
+ WTF::storeStoreFence();
+ m_getter.set(vm, this, getter);
+ }
+
+ JSObject* setter() const { return m_setter.get(); }
+
+ JSObject* setterConcurrently() const
+ {
+ JSObject* result = setter();
+ WTF::loadLoadFence();
+ return result;
+ }
+
+ // Set the setter. It's only valid to call this if you've never set the setter on this
+ // object.
+ void setSetter(VM& vm, JSGlobalObject* globalObject, JSObject* setter)
+ {
+ if (!setter)
+ setter = jsCast<JSObject*>(globalObject->nullSetterFunction());
+
+ RELEASE_ASSERT(isSetterNull());
+ WTF::storeStoreFence();
+ m_setter.set(vm, this, setter);
+ }
+
+ GetterSetter* withGetter(VM&, JSGlobalObject*, JSObject* getter);
+ GetterSetter* withSetter(VM&, JSGlobalObject*, JSObject* setter);
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- ASSERT(value.asCell()->isGetterSetter());
- return static_cast<GetterSetter*>(value.asCell());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(GetterSetterType), info());
}
- JSValue callGetter(ExecState*, JSValue base, JSValue getterSetter);
- void callSetter(ExecState*, JSValue base, JSValue getterSetter, JSValue value, ECMAMode);
+ static ptrdiff_t offsetOfGetter()
+ {
+ return OBJECT_OFFSETOF(GetterSetter, m_getter);
+ }
+
+ static ptrdiff_t offsetOfSetter()
+ {
+ return OBJECT_OFFSETOF(GetterSetter, m_setter);
+ }
+
+ DECLARE_INFO;
+
+private:
+ WriteBarrier<JSObject> m_getter;
+ WriteBarrier<JSObject> m_setter;
+};
+
+GetterSetter* asGetterSetter(JSValue);
+
+inline GetterSetter* asGetterSetter(JSValue value)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(value.asCell()->isGetterSetter());
+ return static_cast<GetterSetter*>(value.asCell());
+}
+
+JSValue callGetter(ExecState*, JSValue base, JSValue getterSetter);
+JS_EXPORT_PRIVATE void callSetter(ExecState*, JSValue base, JSValue getterSetter, JSValue, ECMAMode);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Identifier.cpp b/Source/JavaScriptCore/runtime/Identifier.cpp
index 3658d8772..d26d9567c 100644
--- a/Source/JavaScriptCore/runtime/Identifier.cpp
+++ b/Source/JavaScriptCore/runtime/Identifier.cpp
@@ -25,7 +25,7 @@
#include "JSObject.h"
#include "JSScope.h"
#include "NumericStrings.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include <new>
#include <string.h>
#include <wtf/Assertions.h>
@@ -38,121 +38,33 @@ using WTF::ThreadSpecific;
namespace JSC {
-IdentifierTable* createIdentifierTable()
-{
- return new IdentifierTable;
-}
-
-void deleteIdentifierTable(IdentifierTable* table)
-{
- delete table;
-}
-
-struct IdentifierASCIIStringTranslator {
- static unsigned hash(const LChar* c)
- {
- return StringHasher::computeHashAndMaskTop8Bits(c);
- }
-
- static bool equal(StringImpl* r, const LChar* s)
- {
- return Identifier::equal(r, s);
- }
-
- static void translate(StringImpl*& location, const LChar* c, unsigned hash)
- {
- size_t length = strlen(reinterpret_cast<const char*>(c));
- location = &StringImpl::createFromLiteral(reinterpret_cast<const char*>(c), length).leakRef();
- location->setHash(hash);
- }
-};
-
-struct IdentifierLCharFromUCharTranslator {
- static unsigned hash(const CharBuffer<UChar>& buf)
- {
- return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length);
- }
-
- static bool equal(StringImpl* str, const CharBuffer<UChar>& buf)
- {
- return Identifier::equal(str, buf.s, buf.length);
- }
-
- static void translate(StringImpl*& location, const CharBuffer<UChar>& buf, unsigned hash)
- {
- LChar* d;
- StringImpl& r = StringImpl::createUninitialized(buf.length, d).leakRef();
- WTF::copyLCharsFromUCharSource(d, buf.s, buf.length);
- r.setHash(hash);
- location = &r;
- }
-};
-
-PassRefPtr<StringImpl> Identifier::add(VM* vm, const char* c)
+Ref<StringImpl> Identifier::add(VM* vm, const char* c)
{
ASSERT(c);
ASSERT(c[0]);
if (!c[1])
- return add(vm, vm->smallStrings.singleCharacterStringRep(c[0]));
-
- IdentifierTable& identifierTable = *vm->identifierTable;
-
- HashSet<StringImpl*>::AddResult addResult = identifierTable.add<const LChar*, IdentifierASCIIStringTranslator>(reinterpret_cast<const LChar*>(c));
-
- // If the string is newly-translated, then we need to adopt it.
- // The boolean in the pair tells us if that is so.
- RefPtr<StringImpl> addedString = addResult.isNewEntry ? adoptRef(*addResult.iterator) : *addResult.iterator;
+ return *vm->smallStrings.singleCharacterStringRep(c[0]);
- return addedString.release();
+ return *AtomicStringImpl::add(c);
}
-PassRefPtr<StringImpl> Identifier::add(ExecState* exec, const char* c)
+Ref<StringImpl> Identifier::add(ExecState* exec, const char* c)
{
return add(&exec->vm(), c);
}
-PassRefPtr<StringImpl> Identifier::add8(VM* vm, const UChar* s, int length)
+Ref<StringImpl> Identifier::add8(VM* vm, const UChar* s, int length)
{
if (length == 1) {
UChar c = s[0];
ASSERT(c <= 0xff);
if (canUseSingleCharacterString(c))
- return add(vm, vm->smallStrings.singleCharacterStringRep(c));
+ return *vm->smallStrings.singleCharacterStringRep(c);
}
-
if (!length)
- return StringImpl::empty();
- CharBuffer<UChar> buf = { s, static_cast<unsigned>(length) };
- HashSet<StringImpl*>::AddResult addResult = vm->identifierTable->add<CharBuffer<UChar>, IdentifierLCharFromUCharTranslator >(buf);
-
- // If the string is newly-translated, then we need to adopt it.
- // The boolean in the pair tells us if that is so.
- return addResult.isNewEntry ? adoptRef(*addResult.iterator) : *addResult.iterator;
-}
-
-PassRefPtr<StringImpl> Identifier::addSlowCase(VM* vm, StringImpl* r)
-{
- if (r->isEmptyUnique())
- return r;
- ASSERT(!r->isIdentifier());
- // The empty & null strings are static singletons, and static strings are handled
- // in ::add() in the header, so we should never get here with a zero length string.
- ASSERT(r->length());
-
- if (r->length() == 1) {
- UChar c = (*r)[0];
- if (c <= maxSingleCharacterString)
- r = vm->smallStrings.singleCharacterStringRep(c);
- if (r->isIdentifier())
- return r;
- }
-
- return *vm->identifierTable->add(r).iterator;
-}
+ return *StringImpl::empty();
-PassRefPtr<StringImpl> Identifier::addSlowCase(ExecState* exec, StringImpl* r)
-{
- return addSlowCase(&exec->vm(), r);
+ return *AtomicStringImpl::add(s, length);
}
Identifier Identifier::from(ExecState* exec, unsigned value)
@@ -185,26 +97,34 @@ Identifier Identifier::from(VM* vm, double value)
return Identifier(vm, vm->numericStrings.add(value));
}
+void Identifier::dump(PrintStream& out) const
+{
+ if (impl())
+ out.print(impl());
+ else
+ out.print("<null identifier>");
+}
+
#ifndef NDEBUG
-void Identifier::checkCurrentIdentifierTable(VM* vm)
+void Identifier::checkCurrentAtomicStringTable(VM* vm)
{
// Check the identifier table accessible through the threadspecific matches the
// vm's identifier table.
- ASSERT_UNUSED(vm, vm->identifierTable == wtfThreadData().currentIdentifierTable());
+ ASSERT_UNUSED(vm, vm->atomicStringTable() == wtfThreadData().atomicStringTable());
}
-void Identifier::checkCurrentIdentifierTable(ExecState* exec)
+void Identifier::checkCurrentAtomicStringTable(ExecState* exec)
{
- checkCurrentIdentifierTable(&exec->vm());
+ checkCurrentAtomicStringTable(&exec->vm());
}
#else
// These only exists so that our exports are the same for debug and release builds.
// This would be an RELEASE_ASSERT_NOT_REACHED(), but we're in NDEBUG only code here!
-NO_RETURN_DUE_TO_CRASH void Identifier::checkCurrentIdentifierTable(VM*) { CRASH(); }
-NO_RETURN_DUE_TO_CRASH void Identifier::checkCurrentIdentifierTable(ExecState*) { CRASH(); }
+NO_RETURN_DUE_TO_CRASH void Identifier::checkCurrentAtomicStringTable(VM*) { CRASH(); }
+NO_RETURN_DUE_TO_CRASH void Identifier::checkCurrentAtomicStringTable(ExecState*) { CRASH(); }
#endif
diff --git a/Source/JavaScriptCore/runtime/Identifier.h b/Source/JavaScriptCore/runtime/Identifier.h
index 6733ec5f2..4fb1a2ffa 100644
--- a/Source/JavaScriptCore/runtime/Identifier.h
+++ b/Source/JavaScriptCore/runtime/Identifier.h
@@ -22,248 +22,288 @@
#define Identifier_h
#include "VM.h"
+#include <wtf/Optional.h>
#include <wtf/ThreadSpecific.h>
#include <wtf/WTFThreadData.h>
#include <wtf/text/CString.h>
+#include <wtf/text/UniquedStringImpl.h>
#include <wtf/text/WTFString.h>
namespace JSC {
- class ExecState;
-
- class Identifier {
- friend class Structure;
- public:
- Identifier() { }
- enum EmptyIdentifierFlag { EmptyIdentifier };
- Identifier(EmptyIdentifierFlag) : m_string(StringImpl::empty()) { }
-
- // Only to be used with string literals.
- template<unsigned charactersCount>
- Identifier(ExecState* exec, const char (&characters)[charactersCount]) : m_string(add(exec, characters)) { }
- template<unsigned charactersCount>
- Identifier(VM* vm, const char (&characters)[charactersCount]) : m_string(add(vm, characters)) { }
-
- Identifier(ExecState* exec, StringImpl* rep) : m_string(add(exec, rep)) { }
- Identifier(ExecState* exec, const String& s) : m_string(add(exec, s.impl())) { }
-
- Identifier(VM* vm, const LChar* s, int length) : m_string(add(vm, s, length)) { }
- Identifier(VM* vm, const UChar* s, int length) : m_string(add(vm, s, length)) { }
- Identifier(VM* vm, StringImpl* rep) : m_string(add(vm, rep)) { }
- Identifier(VM* vm, const String& s) : m_string(add(vm, s.impl())) { }
-
- const String& string() const { return m_string; }
- StringImpl* impl() const { return m_string.impl(); }
-
- const UChar* deprecatedCharacters() const { return m_string.deprecatedCharacters(); }
- int length() const { return m_string.length(); }
-
- CString ascii() const { return m_string.ascii(); }
- CString utf8() const { return m_string.utf8(); }
-
- static Identifier from(const PrivateName& name)
- {
- Identifier result;
- result.m_string = name.uid();
- return result;
- }
-
- static Identifier createLCharFromUChar(VM* vm, const UChar* s, int length) { return Identifier(vm, add8(vm, s, length)); }
-
- JS_EXPORT_PRIVATE static Identifier from(ExecState* exec, unsigned y);
- JS_EXPORT_PRIVATE static Identifier from(ExecState* exec, int y);
- static Identifier from(ExecState* exec, double y);
- static Identifier from(VM*, unsigned y);
- static Identifier from(VM*, int y);
- static Identifier from(VM*, double y);
-
- bool isNull() const { return m_string.isNull(); }
- bool isEmpty() const { return m_string.isEmpty(); }
-
- friend bool operator==(const Identifier&, const Identifier&);
- friend bool operator!=(const Identifier&, const Identifier&);
-
- friend bool operator==(const Identifier&, const LChar*);
- friend bool operator==(const Identifier&, const char*);
- friend bool operator!=(const Identifier&, const LChar*);
- friend bool operator!=(const Identifier&, const char*);
-
- static bool equal(const StringImpl*, const LChar*);
- static inline bool equal(const StringImpl*a, const char*b) { return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); };
- static bool equal(const StringImpl*, const LChar*, unsigned length);
- static bool equal(const StringImpl*, const UChar*, unsigned length);
- static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); }
-
- // Only to be used with string literals.
- static PassRefPtr<StringImpl> add(VM*, const char*);
- JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> add(ExecState*, const char*);
-
- private:
- String m_string;
-
- template <typename CharType>
- ALWAYS_INLINE static uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length, bool& ok);
-
- static bool equal(const Identifier& a, const Identifier& b) { return a.m_string.impl() == b.m_string.impl(); }
- static bool equal(const Identifier& a, const LChar* b) { return equal(a.m_string.impl(), b); }
-
- template <typename T> static PassRefPtr<StringImpl> add(VM*, const T*, int length);
- static PassRefPtr<StringImpl> add8(VM*, const UChar*, int length);
- template <typename T> ALWAYS_INLINE static bool canUseSingleCharacterString(T);
-
- static PassRefPtr<StringImpl> add(ExecState* exec, StringImpl* r)
- {
-#ifndef NDEBUG
- checkCurrentIdentifierTable(exec);
-#endif
- if (r->isIdentifier())
- return r;
- return addSlowCase(exec, r);
- }
- static PassRefPtr<StringImpl> add(VM* vm, StringImpl* r)
- {
-#ifndef NDEBUG
- checkCurrentIdentifierTable(vm);
-#endif
- if (r->isIdentifier())
- return r;
- return addSlowCase(vm, r);
- }
-
- JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> addSlowCase(ExecState*, StringImpl* r);
- JS_EXPORT_PRIVATE static PassRefPtr<StringImpl> addSlowCase(VM*, StringImpl* r);
-
- JS_EXPORT_PRIVATE static void checkCurrentIdentifierTable(ExecState*);
- JS_EXPORT_PRIVATE static void checkCurrentIdentifierTable(VM*);
- };
-
- template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(LChar)
- {
- ASSERT(maxSingleCharacterString == 0xff);
- return true;
- }
-
- template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(UChar c)
- {
- return (c <= maxSingleCharacterString);
- }
-
- template <typename T>
- struct CharBuffer {
- const T* s;
- unsigned int length;
- };
-
- template <typename T>
- struct IdentifierCharBufferTranslator {
- static unsigned hash(const CharBuffer<T>& buf)
- {
- return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length);
- }
-
- static bool equal(StringImpl* str, const CharBuffer<T>& buf)
- {
- return Identifier::equal(str, buf.s, buf.length);
- }
-
- static void translate(StringImpl*& location, const CharBuffer<T>& buf, unsigned hash)
- {
- T* d;
- StringImpl& r = StringImpl::createUninitialized(buf.length, d).leakRef();
- for (unsigned i = 0; i != buf.length; i++)
- d[i] = buf.s[i];
- r.setHash(hash);
- location = &r;
- }
- };
-
- template <typename T>
- PassRefPtr<StringImpl> Identifier::add(VM* vm, const T* s, int length)
- {
- if (length == 1) {
- T c = s[0];
- if (canUseSingleCharacterString(c))
- return add(vm, vm->smallStrings.singleCharacterStringRep(c));
- }
-
- if (!length)
- return StringImpl::empty();
- CharBuffer<T> buf = { s, static_cast<unsigned>(length) };
- HashSet<StringImpl*>::AddResult addResult = vm->identifierTable->add<CharBuffer<T>, IdentifierCharBufferTranslator<T>>(buf);
-
- // If the string is newly-translated, then we need to adopt it.
- // The boolean in the pair tells us if that is so.
- return addResult.isNewEntry ? adoptRef(*addResult.iterator) : *addResult.iterator;
- }
-
- inline bool operator==(const Identifier& a, const Identifier& b)
- {
- return Identifier::equal(a, b);
- }
-
- inline bool operator!=(const Identifier& a, const Identifier& b)
- {
- return !Identifier::equal(a, b);
+class ExecState;
+
+ALWAYS_INLINE bool isIndex(uint32_t index)
+{
+ return index != 0xFFFFFFFFU;
+}
+
+template <typename CharType>
+ALWAYS_INLINE Optional<uint32_t> parseIndex(const CharType* characters, unsigned length)
+{
+ // An empty string is not a number.
+ if (!length)
+ return Nullopt;
+
+ // Get the first character, turning it into a digit.
+ uint32_t value = characters[0] - '0';
+ if (value > 9)
+ return Nullopt;
+
+ // Check for leading zeros. If the first characher is 0, then the
+ // length of the string must be one - e.g. "042" is not equal to "42".
+ if (!value && length > 1)
+ return Nullopt;
+
+ while (--length) {
+ // Multiply value by 10, checking for overflow out of 32 bits.
+ if (value > 0xFFFFFFFFU / 10)
+ return Nullopt;
+ value *= 10;
+
+ // Get the next character, turning it into a digit.
+ uint32_t newValue = *(++characters) - '0';
+ if (newValue > 9)
+ return Nullopt;
+
+ // Add in the old value, checking for overflow out of 32 bits.
+ newValue += value;
+ if (newValue < value)
+ return Nullopt;
+ value = newValue;
}
- inline bool operator==(const Identifier& a, const LChar* b)
+ if (!isIndex(value))
+ return Nullopt;
+ return value;
+}
+
+ALWAYS_INLINE Optional<uint32_t> parseIndex(StringImpl& impl)
+{
+ if (impl.is8Bit())
+ return parseIndex(impl.characters8(), impl.length());
+ return parseIndex(impl.characters16(), impl.length());
+}
+
+class Identifier {
+ friend class Structure;
+public:
+ Identifier() { }
+ enum EmptyIdentifierFlag { EmptyIdentifier };
+ Identifier(EmptyIdentifierFlag) : m_string(StringImpl::empty()) { ASSERT(m_string.impl()->isAtomic()); }
+
+ const String& string() const { return m_string; }
+ UniquedStringImpl* impl() const { return static_cast<UniquedStringImpl*>(m_string.impl()); }
+
+ int length() const { return m_string.length(); }
+
+ CString ascii() const { return m_string.ascii(); }
+ CString utf8() const { return m_string.utf8(); }
+
+ // There's 2 functions to construct Identifier from string, (1) fromString and (2) fromUid.
+ // They have different meanings in keeping or discarding symbol-ness of strings.
+ // (1): fromString
+ // Just construct Identifier from string. String held by Identifier is always atomized.
+ // Symbol-ness of StringImpl*, which represents that the string is inteded to be used for ES6 Symbols, is discarded.
+ // So a constructed Identifier never represents a symbol.
+ // (2): fromUid
+ // `StringImpl* uid` represents ether String or Symbol property.
+ // fromUid keeps symbol-ness of provided StringImpl* while fromString discards it.
+ // Use fromUid when constructing Identifier from StringImpl* which may represent symbols.
+
+ // Only to be used with string literals.
+ template<unsigned charactersCount>
+ static Identifier fromString(VM*, const char (&characters)[charactersCount]);
+ template<unsigned charactersCount>
+ static Identifier fromString(ExecState*, const char (&characters)[charactersCount]);
+ static Identifier fromString(VM*, const LChar*, int length);
+ static Identifier fromString(VM*, const UChar*, int length);
+ static Identifier fromString(VM*, const String&);
+ static Identifier fromString(ExecState*, AtomicStringImpl*);
+ static Identifier fromString(ExecState*, const AtomicString&);
+ static Identifier fromString(ExecState*, const String&);
+ static Identifier fromString(ExecState*, const char*);
+
+ static Identifier fromUid(VM*, UniquedStringImpl* uid);
+ static Identifier fromUid(ExecState*, UniquedStringImpl* uid);
+ static Identifier fromUid(const PrivateName&);
+
+ static Identifier createLCharFromUChar(VM* vm, const UChar* s, int length) { return Identifier(vm, add8(vm, s, length)); }
+
+ JS_EXPORT_PRIVATE static Identifier from(ExecState*, unsigned y);
+ JS_EXPORT_PRIVATE static Identifier from(ExecState*, int y);
+ static Identifier from(ExecState*, double y);
+ static Identifier from(VM*, unsigned y);
+ static Identifier from(VM*, int y);
+ static Identifier from(VM*, double y);
+
+ bool isNull() const { return m_string.isNull(); }
+ bool isEmpty() const { return m_string.isEmpty(); }
+ bool isSymbol() const { return !isNull() && impl()->isSymbol(); }
+
+ friend bool operator==(const Identifier&, const Identifier&);
+ friend bool operator!=(const Identifier&, const Identifier&);
+
+ friend bool operator==(const Identifier&, const LChar*);
+ friend bool operator==(const Identifier&, const char*);
+ friend bool operator!=(const Identifier&, const LChar*);
+ friend bool operator!=(const Identifier&, const char*);
+
+ static bool equal(const StringImpl*, const LChar*);
+ static inline bool equal(const StringImpl*a, const char*b) { return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); };
+ static bool equal(const StringImpl*, const LChar*, unsigned length);
+ static bool equal(const StringImpl*, const UChar*, unsigned length);
+ static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); }
+
+ // Only to be used with string literals.
+ JS_EXPORT_PRIVATE static Ref<StringImpl> add(VM*, const char*);
+ JS_EXPORT_PRIVATE static Ref<StringImpl> add(ExecState*, const char*);
+
+ void dump(PrintStream&) const;
+
+private:
+ String m_string;
+
+ // Only to be used with string literals.
+ template<unsigned charactersCount>
+ Identifier(VM* vm, const char (&characters)[charactersCount]) : m_string(add(vm, characters)) { ASSERT(m_string.impl()->isAtomic()); }
+
+ Identifier(VM* vm, const LChar* s, int length) : m_string(add(vm, s, length)) { ASSERT(m_string.impl()->isAtomic()); }
+ Identifier(VM* vm, const UChar* s, int length) : m_string(add(vm, s, length)) { ASSERT(m_string.impl()->isAtomic()); }
+ Identifier(ExecState*, AtomicStringImpl*);
+ Identifier(ExecState*, const AtomicString&);
+ Identifier(VM* vm, const String& string) : m_string(add(vm, string.impl())) { ASSERT(m_string.impl()->isAtomic()); }
+ Identifier(VM* vm, StringImpl* rep) : m_string(add(vm, rep)) { ASSERT(m_string.impl()->isAtomic()); }
+
+ Identifier(SymbolImpl& uid)
+ : m_string(&uid)
{
- return Identifier::equal(a, b);
}
- inline bool operator==(const Identifier& a, const char* b)
- {
- return Identifier::equal(a, reinterpret_cast<const LChar*>(b));
- }
-
- inline bool operator!=(const Identifier& a, const LChar* b)
- {
- return !Identifier::equal(a, b);
- }
+ template <typename CharType>
+ ALWAYS_INLINE static uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length, bool& ok);
- inline bool operator!=(const Identifier& a, const char* b)
- {
- return !Identifier::equal(a, reinterpret_cast<const LChar*>(b));
- }
-
- inline bool Identifier::equal(const StringImpl* r, const LChar* s)
- {
- return WTF::equal(r, s);
- }
+ static bool equal(const Identifier& a, const Identifier& b) { return a.m_string.impl() == b.m_string.impl(); }
+ static bool equal(const Identifier& a, const LChar* b) { return equal(a.m_string.impl(), b); }
- inline bool Identifier::equal(const StringImpl* r, const LChar* s, unsigned length)
- {
- return WTF::equal(r, s, length);
- }
-
- inline bool Identifier::equal(const StringImpl* r, const UChar* s, unsigned length)
- {
- return WTF::equal(r, s, length);
- }
-
- IdentifierTable* createIdentifierTable();
- void deleteIdentifierTable(IdentifierTable*);
-
- struct IdentifierRepHash : PtrHash<RefPtr<StringImpl>> {
- static unsigned hash(const RefPtr<StringImpl>& key) { return key->existingHash(); }
- static unsigned hash(StringImpl* key) { return key->existingHash(); }
- };
+ template <typename T> static Ref<StringImpl> add(VM*, const T*, int length);
+ static Ref<StringImpl> add8(VM*, const UChar*, int length);
+ template <typename T> ALWAYS_INLINE static bool canUseSingleCharacterString(T);
- struct IdentifierMapIndexHashTraits : HashTraits<int> {
- static int emptyValue() { return std::numeric_limits<int>::max(); }
- static const bool emptyValueIsZero = false;
- };
+ static Ref<StringImpl> add(ExecState*, StringImpl*);
+ static Ref<StringImpl> add(VM*, StringImpl*);
- typedef HashMap<RefPtr<StringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<StringImpl>>, IdentifierMapIndexHashTraits> IdentifierMap;
- typedef HashMap<StringImpl*, int, IdentifierRepHash, HashTraits<StringImpl*>, IdentifierMapIndexHashTraits> BorrowedIdentifierMap;
-
- template<typename U, typename V>
- HashSet<StringImpl*>::AddResult IdentifierTable::add(U value)
- {
- HashSet<StringImpl*>::AddResult result = m_table.add<V>(value);
- (*result.iterator)->setIsIdentifier(true);
- return result;
+#ifndef NDEBUG
+ JS_EXPORT_PRIVATE static void checkCurrentAtomicStringTable(ExecState*);
+ JS_EXPORT_PRIVATE static void checkCurrentAtomicStringTable(VM*);
+#else
+ JS_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH static void checkCurrentAtomicStringTable(ExecState*);
+ JS_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH static void checkCurrentAtomicStringTable(VM*);
+#endif
+};
+
+template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(LChar)
+{
+ ASSERT(maxSingleCharacterString == 0xff);
+ return true;
+}
+
+template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(UChar c)
+{
+ return (c <= maxSingleCharacterString);
+}
+
+template <typename T>
+Ref<StringImpl> Identifier::add(VM* vm, const T* s, int length)
+{
+ if (length == 1) {
+ T c = s[0];
+ if (canUseSingleCharacterString(c))
+ return *vm->smallStrings.singleCharacterStringRep(c);
}
+ if (!length)
+ return *StringImpl::empty();
+
+ return *AtomicStringImpl::add(s, length);
+}
+
+inline bool operator==(const Identifier& a, const Identifier& b)
+{
+ return Identifier::equal(a, b);
+}
+
+inline bool operator!=(const Identifier& a, const Identifier& b)
+{
+ return !Identifier::equal(a, b);
+}
+
+inline bool operator==(const Identifier& a, const LChar* b)
+{
+ return Identifier::equal(a, b);
+}
+
+inline bool operator==(const Identifier& a, const char* b)
+{
+ return Identifier::equal(a, reinterpret_cast<const LChar*>(b));
+}
+
+inline bool operator!=(const Identifier& a, const LChar* b)
+{
+ return !Identifier::equal(a, b);
+}
+
+inline bool operator!=(const Identifier& a, const char* b)
+{
+ return !Identifier::equal(a, reinterpret_cast<const LChar*>(b));
+}
+
+inline bool Identifier::equal(const StringImpl* r, const LChar* s)
+{
+ return WTF::equal(r, s);
+}
+
+inline bool Identifier::equal(const StringImpl* r, const LChar* s, unsigned length)
+{
+ return WTF::equal(r, s, length);
+}
+
+inline bool Identifier::equal(const StringImpl* r, const UChar* s, unsigned length)
+{
+ return WTF::equal(r, s, length);
+}
+
+ALWAYS_INLINE Optional<uint32_t> parseIndex(const Identifier& identifier)
+{
+ auto uid = identifier.impl();
+ if (!uid)
+ return Nullopt;
+ if (uid->isSymbol())
+ return Nullopt;
+ return parseIndex(*uid);
+}
+
+JSValue identifierToJSValue(VM&, const Identifier&);
+// This will stringify private symbols. When leaking JSValues to
+// non-internal code, make sure to use this function and not the above one.
+JSValue identifierToSafePublicJSValue(VM&, const Identifier&);
+
+// FIXME: It may be better for this to just be a typedef for PtrHash, since PtrHash may be cheaper to
+// compute than loading the StringImpl's hash from memory. That change would also reduce the likelihood of
+// crashes in code that somehow dangled a StringImpl.
+// https://bugs.webkit.org/show_bug.cgi?id=150137
+struct IdentifierRepHash : PtrHash<RefPtr<UniquedStringImpl>> {
+ static unsigned hash(const RefPtr<UniquedStringImpl>& key) { return key->existingSymbolAwareHash(); }
+ static unsigned hash(UniquedStringImpl* key) { return key->existingSymbolAwareHash(); }
+};
+
+struct IdentifierMapIndexHashTraits : HashTraits<int> {
+ static int emptyValue() { return std::numeric_limits<int>::max(); }
+ static const bool emptyValueIsZero = false;
+};
+
+typedef HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> IdentifierSet;
+typedef HashMap<RefPtr<UniquedStringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, IdentifierMapIndexHashTraits> IdentifierMap;
+typedef HashMap<UniquedStringImpl*, int, IdentifierRepHash, HashTraits<UniquedStringImpl*>, IdentifierMapIndexHashTraits> BorrowedIdentifierMap;
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/IdentifierInlines.h b/Source/JavaScriptCore/runtime/IdentifierInlines.h
new file mode 100644
index 000000000..52c11df1d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IdentifierInlines.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef IdentifierInlines_h
+#define IdentifierInlines_h
+
+#include "CallFrame.h"
+#include "Identifier.h"
+#include "Symbol.h"
+
+namespace JSC {
+
+inline Identifier::Identifier(ExecState* exec, AtomicStringImpl* string)
+ : m_string(string)
+{
+#ifndef NDEBUG
+ checkCurrentAtomicStringTable(exec);
+ if (string)
+ ASSERT_WITH_MESSAGE(!string->length() || string->isSymbol() || AtomicStringImpl::isInAtomicStringTable(string), "The atomic string comes from an other thread!");
+#else
+ UNUSED_PARAM(exec);
+#endif
+}
+
+inline Identifier::Identifier(ExecState* exec, const AtomicString& string)
+ : m_string(string.string())
+{
+#ifndef NDEBUG
+ checkCurrentAtomicStringTable(exec);
+ if (!string.isNull())
+ ASSERT_WITH_MESSAGE(!string.length() || string.impl()->isSymbol() || AtomicStringImpl::isInAtomicStringTable(string.impl()), "The atomic string comes from an other thread!");
+#else
+ UNUSED_PARAM(exec);
+#endif
+}
+
+inline Ref<StringImpl> Identifier::add(ExecState* exec, StringImpl* r)
+{
+#ifndef NDEBUG
+ checkCurrentAtomicStringTable(exec);
+#endif
+ return *AtomicStringImpl::addWithStringTableProvider(*exec, r);
+}
+inline Ref<StringImpl> Identifier::add(VM* vm, StringImpl* r)
+{
+#ifndef NDEBUG
+ checkCurrentAtomicStringTable(vm);
+#endif
+ return *AtomicStringImpl::addWithStringTableProvider(*vm, r);
+}
+
+inline Identifier Identifier::fromUid(VM* vm, UniquedStringImpl* uid)
+{
+ if (!uid || !uid->isSymbol())
+ return Identifier(vm, uid);
+ return static_cast<SymbolImpl&>(*uid);
+}
+
+inline Identifier Identifier::fromUid(ExecState* exec, UniquedStringImpl* uid)
+{
+ return fromUid(&exec->vm(), uid);
+}
+
+inline Identifier Identifier::fromUid(const PrivateName& name)
+{
+ return *name.uid();
+}
+
+template<unsigned charactersCount>
+inline Identifier Identifier::fromString(VM* vm, const char (&characters)[charactersCount])
+{
+ return Identifier(vm, characters);
+}
+
+template<unsigned charactersCount>
+inline Identifier Identifier::fromString(ExecState* exec, const char (&characters)[charactersCount])
+{
+ return Identifier(&exec->vm(), characters);
+}
+
+inline Identifier Identifier::fromString(VM* vm, const LChar* s, int length)
+{
+ return Identifier(vm, s, length);
+}
+
+inline Identifier Identifier::fromString(VM* vm, const UChar* s, int length)
+{
+ return Identifier(vm, s, length);
+}
+
+inline Identifier Identifier::fromString(VM* vm, const String& string)
+{
+ return Identifier(vm, string.impl());
+}
+
+inline Identifier Identifier::fromString(ExecState* exec, const String& string)
+{
+ return Identifier(&exec->vm(), string.impl());
+}
+
+inline Identifier Identifier::fromString(ExecState* exec, AtomicStringImpl* atomicString)
+{
+ return Identifier(exec, atomicString);
+}
+
+inline Identifier Identifier::fromString(ExecState* exec, const AtomicString& atomicString)
+{
+ return Identifier(exec, atomicString);
+}
+
+inline Identifier Identifier::fromString(ExecState* exec, const char* s)
+{
+ return Identifier(exec, AtomicString(s));
+}
+
+inline JSValue identifierToJSValue(VM& vm, const Identifier& identifier)
+{
+ if (identifier.isSymbol())
+ return Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl()));
+ return jsString(&vm, identifier.impl());
+}
+
+inline JSValue identifierToSafePublicJSValue(VM& vm, const Identifier& identifier)
+{
+ if (identifier.isSymbol() && !vm.propertyNames->isPrivateName(identifier))
+ return Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl()));
+ return jsString(&vm, identifier.impl());
+}
+
+} // namespace JSC
+
+#endif // IdentifierInlines_h
diff --git a/Source/JavaScriptCore/runtime/IndexingHeader.h b/Source/JavaScriptCore/runtime/IndexingHeader.h
index 27881297b..a88643239 100644
--- a/Source/JavaScriptCore/runtime/IndexingHeader.h
+++ b/Source/JavaScriptCore/runtime/IndexingHeader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 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
@@ -27,7 +27,6 @@
#define IndexingHeader_h
#include "PropertyStorage.h"
-#include <wtf/Platform.h>
namespace JSC {
@@ -63,7 +62,7 @@ public:
u.lengths.vectorLength = length;
}
- uint32_t publicLength() { return u.lengths.publicLength; }
+ uint32_t publicLength() const { return u.lengths.publicLength; }
void setPublicLength(uint32_t auxWord) { u.lengths.publicLength = auxWord; }
ArrayBuffer* arrayBuffer() { return u.typedArray.buffer; }
@@ -81,7 +80,12 @@ public:
static IndexingHeader* from(ArrayStorage* arrayStorage)
{
- return reinterpret_cast<IndexingHeader*>(arrayStorage) - 1;
+ return const_cast<IndexingHeader*>(from(const_cast<const ArrayStorage*>(arrayStorage)));
+ }
+
+ static const IndexingHeader* from(const ArrayStorage* arrayStorage)
+ {
+ return reinterpret_cast<const IndexingHeader*>(arrayStorage) - 1;
}
static IndexingHeader* fromEndOf(PropertyStorage propertyStorage)
diff --git a/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h b/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h
index cfad1c8c2..b188741c3 100644
--- a/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h
+++ b/Source/JavaScriptCore/runtime/IndexingHeaderInlines.h
@@ -34,7 +34,7 @@ namespace JSC {
inline size_t IndexingHeader::preCapacity(Structure* structure)
{
- if (LIKELY(!hasArrayStorage(structure->indexingType())))
+ if (LIKELY(!hasAnyArrayStorage(structure->indexingType())))
return 0;
return arrayStorage()->m_indexBias;
diff --git a/Source/JavaScriptCore/runtime/IndexingType.h b/Source/JavaScriptCore/runtime/IndexingType.h
index 66a75f8aa..3f9fdd1ed 100644
--- a/Source/JavaScriptCore/runtime/IndexingType.h
+++ b/Source/JavaScriptCore/runtime/IndexingType.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 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
@@ -31,27 +31,43 @@
namespace JSC {
+/*
+ Structure of the IndexingType
+ =============================
+ Conceptually, the IndexingType looks like this:
+
+ struct IndexingType {
+ uint8_t isArray:1; // bit 0
+ uint8_t shape:4; // bit 1 - 3
+ uint8_t mayHaveIndexedAccessors:1; // bit 4
+ };
+
+ The shape values (e.g. Int32Shape, ContiguousShape, etc) are an enumeration of
+ various shapes (though not necessarily sequential in terms of their values).
+ Hence, shape values are not bitwise exclusive with respect to each other.
+*/
+
typedef uint8_t IndexingType;
// Flags for testing the presence of capabilities.
static const IndexingType IsArray = 0x01;
// The shape of the indexed property storage.
-static const IndexingType IndexingShapeMask = 0x1E;
+static const IndexingType IndexingShapeMask = 0x0E;
static const IndexingType NoIndexingShape = 0x00;
static const IndexingType UndecidedShape = 0x02; // Only useful for arrays.
-static const IndexingType Int32Shape = 0x14;
-static const IndexingType DoubleShape = 0x16;
-static const IndexingType ContiguousShape = 0x1A;
-static const IndexingType ArrayStorageShape = 0x1C;
-static const IndexingType SlowPutArrayStorageShape = 0x1E;
+static const IndexingType Int32Shape = 0x04;
+static const IndexingType DoubleShape = 0x06;
+static const IndexingType ContiguousShape = 0x08;
+static const IndexingType ArrayStorageShape = 0x0A;
+static const IndexingType SlowPutArrayStorageShape = 0x0C;
static const IndexingType IndexingShapeShift = 1;
-static const IndexingType NumberOfIndexingShapes = 16;
+static const IndexingType NumberOfIndexingShapes = 7;
// Additional flags for tracking the history of the type. These are usually
// masked off unless you ask for them directly.
-static const IndexingType MayHaveIndexedAccessors = 0x20;
+static const IndexingType MayHaveIndexedAccessors = 0x10;
// List of acceptable array types.
static const IndexingType NonArray = 0x0;
@@ -121,16 +137,14 @@ static inline bool hasContiguous(IndexingType indexingType)
return (indexingType & IndexingShapeMask) == ContiguousShape;
}
-// FIXME: This is an awkward name. This should really be called hasArrayStorage()
-// and then next method down should be called hasAnyArrayStorage().
-static inline bool hasFastArrayStorage(IndexingType indexingType)
+static inline bool hasArrayStorage(IndexingType indexingType)
{
return (indexingType & IndexingShapeMask) == ArrayStorageShape;
}
-static inline bool hasArrayStorage(IndexingType indexingType)
+static inline bool hasAnyArrayStorage(IndexingType indexingType)
{
- return static_cast<uint8_t>((indexingType & IndexingShapeMask) - ArrayStorageShape) <= static_cast<uint8_t>(SlowPutArrayStorageShape - ArrayStorageShape);
+ return static_cast<uint8_t>(indexingType & IndexingShapeMask) >= ArrayStorageShape;
}
static inline bool shouldUseSlowPut(IndexingType indexingType)
@@ -148,10 +162,10 @@ void dumpIndexingType(PrintStream&, IndexingType);
MAKE_PRINT_ADAPTOR(IndexingTypeDump, IndexingType, dumpIndexingType);
// Mask of all possible types.
-static const IndexingType AllArrayTypes = 31;
+static const IndexingType AllArrayTypes = IndexingShapeMask | IsArray;
// Mask of all possible types including the history.
-static const IndexingType AllArrayTypesAndHistory = 127;
+static const IndexingType AllArrayTypesAndHistory = AllArrayTypes | MayHaveIndexedAccessors;
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/InferredType.cpp b/Source/JavaScriptCore/runtime/InferredType.cpp
new file mode 100644
index 000000000..d513522c4
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/InferredType.cpp
@@ -0,0 +1,600 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "InferredType.h"
+
+#include "JSCInlines.h"
+
+namespace JSC {
+
+namespace {
+
+class InferredTypeFireDetail : public FireDetail {
+public:
+ InferredTypeFireDetail(
+ InferredType* inferredType, UniquedStringImpl* uid,
+ const InferredType::Descriptor& oldDescriptor, const InferredType::Descriptor& newDescriptor,
+ JSValue offendingValue)
+ : m_inferredType(inferredType)
+ , m_uid(uid)
+ , m_oldDescriptor(oldDescriptor)
+ , m_newDescriptor(newDescriptor)
+ , m_offendingValue(offendingValue)
+ {
+ }
+
+protected:
+ void dump(PrintStream& out) const override
+ {
+ out.print(
+ "Inferred type changed on ", RawPointer(m_inferredType), " for property ", m_uid, ": "
+ "old type was ", m_oldDescriptor, " while desired type is ", m_newDescriptor);
+ if (m_offendingValue)
+ out.print(" due to ", m_offendingValue);
+ }
+
+private:
+ InferredType* m_inferredType;
+ RefPtr<UniquedStringImpl> m_uid;
+ InferredType::Descriptor m_oldDescriptor;
+ InferredType::Descriptor m_newDescriptor;
+ JSValue m_offendingValue;
+};
+
+} // anonymous namespace
+
+const ClassInfo InferredType::s_info = { "InferredType", 0, 0, CREATE_METHOD_TABLE(InferredType) };
+
+InferredType* InferredType::create(VM& vm)
+{
+ InferredType* result = new (NotNull, allocateCell<InferredType>(vm.heap)) InferredType(vm);
+ result->finishCreation(vm);
+ return result;
+}
+
+void InferredType::destroy(JSCell* cell)
+{
+ InferredType* inferredType = static_cast<InferredType*>(cell);
+ inferredType->InferredType::~InferredType();
+}
+
+Structure* InferredType::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+}
+
+void InferredType::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ InferredType* inferredType = jsCast<InferredType*>(cell);
+
+ if (inferredType->m_structure)
+ visitor.addUnconditionalFinalizer(&inferredType->m_structure->m_finalizer);
+}
+
+InferredType::Kind InferredType::kindForFlags(PutByIdFlags flags)
+{
+ switch (flags & PutByIdPrimaryTypeMask) {
+ case PutByIdPrimaryTypeSecondary:
+ switch (flags & PutByIdSecondaryTypeMask) {
+ case PutByIdSecondaryTypeBottom:
+ return Bottom;
+ case PutByIdSecondaryTypeBoolean:
+ return Boolean;
+ case PutByIdSecondaryTypeOther:
+ return Other;
+ case PutByIdSecondaryTypeInt32:
+ return Int32;
+ case PutByIdSecondaryTypeNumber:
+ return Number;
+ case PutByIdSecondaryTypeString:
+ return String;
+ case PutByIdSecondaryTypeSymbol:
+ return Symbol;
+ case PutByIdSecondaryTypeObject:
+ return Object;
+ case PutByIdSecondaryTypeObjectOrOther:
+ return ObjectOrOther;
+ case PutByIdSecondaryTypeTop:
+ return Top;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return Bottom;
+ }
+ case PutByIdPrimaryTypeObjectWithStructure:
+ return ObjectWithStructure;
+ case PutByIdPrimaryTypeObjectWithStructureOrOther:
+ return ObjectWithStructureOrOther;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return Bottom;
+ }
+}
+
+InferredType::Descriptor InferredType::Descriptor::forValue(JSValue value)
+{
+ if (value.isBoolean())
+ return Boolean;
+ if (value.isUndefinedOrNull())
+ return Other;
+ if (value.isInt32())
+ return Int32;
+ if (value.isNumber())
+ return Number;
+ if (value.isCell()) {
+ JSCell* cell = value.asCell();
+ if (cell->isString())
+ return String;
+ if (cell->isSymbol())
+ return Symbol;
+ if (cell->isObject()) {
+ if (cell->structure()->transitionWatchpointSetIsStillValid())
+ return Descriptor(ObjectWithStructure, cell->structure());
+ return Object;
+ }
+ }
+ return Top;
+}
+
+InferredType::Descriptor InferredType::Descriptor::forFlags(VM& vm, PutByIdFlags flags)
+{
+ Kind kind = kindForFlags(flags);
+ Structure* structure;
+ if (hasStructure(kind))
+ structure = vm.heap.structureIDTable().get(decodeStructureID(flags));
+ else
+ structure = nullptr;
+ return Descriptor(kind, structure);
+}
+
+PutByIdFlags InferredType::Descriptor::putByIdFlags() const
+{
+ switch (m_kind) {
+ case Bottom:
+ return static_cast<PutByIdFlags>(PutByIdPrimaryTypeSecondary | PutByIdSecondaryTypeBottom);
+ case Boolean:
+ return static_cast<PutByIdFlags>(PutByIdPrimaryTypeSecondary | PutByIdSecondaryTypeBoolean);
+ case Other:
+ return static_cast<PutByIdFlags>(PutByIdPrimaryTypeSecondary | PutByIdSecondaryTypeOther);
+ case Int32:
+ return static_cast<PutByIdFlags>(PutByIdPrimaryTypeSecondary | PutByIdSecondaryTypeInt32);
+ case Number:
+ return static_cast<PutByIdFlags>(PutByIdPrimaryTypeSecondary | PutByIdSecondaryTypeNumber);
+ case String:
+ return static_cast<PutByIdFlags>(PutByIdPrimaryTypeSecondary | PutByIdSecondaryTypeString);
+ case Symbol:
+ return static_cast<PutByIdFlags>(PutByIdPrimaryTypeSecondary | PutByIdSecondaryTypeSymbol);
+ case Object:
+ return static_cast<PutByIdFlags>(PutByIdPrimaryTypeSecondary | PutByIdSecondaryTypeObject);
+ case ObjectOrOther:
+ return static_cast<PutByIdFlags>(PutByIdPrimaryTypeSecondary | PutByIdSecondaryTypeObjectOrOther);
+ case Top:
+ return static_cast<PutByIdFlags>(PutByIdPrimaryTypeSecondary | PutByIdSecondaryTypeTop);
+ case ObjectWithStructure:
+ return static_cast<PutByIdFlags>(
+ PutByIdPrimaryTypeObjectWithStructure | encodeStructureID(m_structure->id()));
+ case ObjectWithStructureOrOther:
+ return static_cast<PutByIdFlags>(
+ PutByIdPrimaryTypeObjectWithStructureOrOther | encodeStructureID(m_structure->id()));
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return PutByIdNone;
+}
+
+void InferredType::Descriptor::merge(const Descriptor& other)
+{
+ // Filter out common things to simplify the switch statement below.
+ if (*this == other)
+ return;
+ if (other.m_kind == Bottom)
+ return;
+
+ switch (m_kind) {
+ case Bottom:
+ *this = other;
+ return;
+ case Boolean:
+ case String:
+ case Symbol:
+ *this = Top;
+ return;
+ case Other:
+ switch (other.m_kind) {
+ case ObjectWithStructure:
+ case ObjectWithStructureOrOther:
+ *this = Descriptor(ObjectWithStructureOrOther, other.structure());
+ return;
+ case Object:
+ case ObjectOrOther:
+ *this = ObjectOrOther;
+ return;
+ default:
+ *this = Top;
+ return;
+ }
+ case Int32:
+ switch (other.m_kind) {
+ case Number:
+ *this = Number;
+ return;
+ default:
+ *this = Top;
+ return;
+ }
+ case Number:
+ switch (other.m_kind) {
+ case Int32:
+ return;
+ default:
+ *this = Top;
+ return;
+ }
+ case ObjectWithStructure:
+ switch (other.m_kind) {
+ case ObjectWithStructure: // If we see this here, then we know that the structures didn't match.
+ case Object:
+ *this = Object;
+ return;
+ case ObjectWithStructureOrOther:
+ if (m_structure == other.m_structure) {
+ *this = other;
+ return;
+ }
+ *this = ObjectOrOther;
+ return;
+ case ObjectOrOther:
+ *this = ObjectOrOther;
+ return;
+ case Other:
+ m_kind = ObjectWithStructureOrOther;
+ return;
+ default:
+ *this = Top;
+ return;
+ }
+ case ObjectWithStructureOrOther:
+ switch (other.m_kind) {
+ case ObjectWithStructure:
+ if (m_structure == other.m_structure)
+ return;
+ *this = ObjectOrOther;
+ return;
+ case Object:
+ case ObjectWithStructureOrOther: // If we see this here, then we know that the structures didn't match.
+ case ObjectOrOther:
+ *this = ObjectOrOther;
+ return;
+ case Other:
+ return;
+ default:
+ *this = Top;
+ return;
+ }
+ case Object:
+ switch (other.m_kind) {
+ case ObjectWithStructure:
+ return;
+ case ObjectWithStructureOrOther:
+ case ObjectOrOther:
+ case Other:
+ *this = ObjectOrOther;
+ return;
+ default:
+ *this = Top;
+ return;
+ }
+ case ObjectOrOther:
+ switch (other.m_kind) {
+ case ObjectWithStructure:
+ case ObjectWithStructureOrOther:
+ case Object:
+ case Other:
+ return;
+ default:
+ *this = Top;
+ return;
+ }
+ case Top:
+ return;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+void InferredType::Descriptor::removeStructure()
+{
+ switch (m_kind) {
+ case ObjectWithStructure:
+ *this = Object;
+ return;
+ case ObjectWithStructureOrOther:
+ *this = ObjectOrOther;
+ return;
+ default:
+ return;
+ }
+}
+
+bool InferredType::Descriptor::subsumes(const Descriptor& other) const
+{
+ Descriptor merged = *this;
+ merged.merge(other);
+ return *this == merged;
+}
+
+void InferredType::Descriptor::dumpInContext(PrintStream& out, DumpContext* context) const
+{
+ out.print(m_kind);
+ if (m_structure)
+ out.print(":", inContext(*m_structure, context));
+}
+
+void InferredType::Descriptor::dump(PrintStream& out) const
+{
+ dumpInContext(out, nullptr);
+}
+
+InferredType::InferredType(VM& vm)
+ : Base(vm, vm.inferredTypeStructure.get())
+ , m_watchpointSet(ClearWatchpoint)
+{
+}
+
+InferredType::~InferredType()
+{
+}
+
+bool InferredType::canWatch(const ConcurrentJITLocker& locker, const Descriptor& expected)
+{
+ if (expected.kind() == Top)
+ return false;
+
+ return descriptor(locker) == expected;
+}
+
+bool InferredType::canWatch(const Descriptor& expected)
+{
+ ConcurrentJITLocker locker(m_lock);
+ return canWatch(locker, expected);
+}
+
+void InferredType::addWatchpoint(const ConcurrentJITLocker& locker, Watchpoint* watchpoint)
+{
+ RELEASE_ASSERT(descriptor(locker).kind() != Top);
+
+ m_watchpointSet.add(watchpoint);
+}
+
+void InferredType::addWatchpoint(Watchpoint* watchpoint)
+{
+ ConcurrentJITLocker locker(m_lock);
+ addWatchpoint(locker, watchpoint);
+}
+
+void InferredType::dump(PrintStream& out) const
+{
+ out.print(RawPointer(this), ":", descriptor());
+}
+
+bool InferredType::willStoreValueSlow(VM& vm, PropertyName propertyName, JSValue value)
+{
+ Descriptor oldType;
+ Descriptor myType;
+ bool result;
+ {
+ ConcurrentJITLocker locker(m_lock);
+ oldType = descriptor(locker);
+ myType = Descriptor::forValue(value);
+
+ myType.merge(oldType);
+
+ ASSERT(oldType != myType); // The type must have changed if we're on the slow path.
+
+ bool setResult = set(locker, vm, myType);
+ result = kind(locker) != Top;
+ if (!setResult)
+ return result;
+ }
+
+ InferredTypeFireDetail detail(this, propertyName.uid(), oldType, myType, value);
+ m_watchpointSet.fireAll(detail);
+ return result;
+}
+
+void InferredType::makeTopSlow(VM& vm, PropertyName propertyName)
+{
+ Descriptor oldType;
+ {
+ ConcurrentJITLocker locker(m_lock);
+ oldType = descriptor(locker);
+ if (!set(locker, vm, Top))
+ return;
+ }
+
+ InferredTypeFireDetail detail(this, propertyName.uid(), oldType, Top, JSValue());
+ m_watchpointSet.fireAll(detail);
+}
+
+bool InferredType::set(const ConcurrentJITLocker& locker, VM& vm, Descriptor newDescriptor)
+{
+ // We will trigger write barriers while holding our lock. Currently, write barriers don't GC, but that
+ // could change. If it does, we don't want to deadlock. Note that we could have used
+ // GCSafeConcurrentJITLocker in the caller, but the caller is on a fast path so maybe that wouldn't be
+ // a good idea.
+ DeferGCForAWhile deferGC(vm.heap);
+
+ // Be defensive: if we're not really changing the type, then we don't have to do anything.
+ if (descriptor(locker) == newDescriptor)
+ return false;
+
+ bool shouldFireWatchpointSet = false;
+
+ // The new descriptor must be more general than the previous one.
+ ASSERT(newDescriptor.subsumes(descriptor(locker)));
+
+ // If the new descriptors have different structures, then it can only be because one is null.
+ if (descriptor(locker).structure() != newDescriptor.structure())
+ ASSERT(!descriptor(locker).structure() || !newDescriptor.structure());
+
+ // We are changing the type, so make sure that if anyone was watching, they find out about it now. If
+ // anyone is watching, we make sure to go to Top so that we don't do this sort of thing again.
+ if (m_watchpointSet.state() != ClearWatchpoint) {
+ // We cannot have been invalidated, since if we were, then we'd already be at Top.
+ ASSERT(m_watchpointSet.state() != IsInvalidated);
+
+ // We're about to do expensive things because some compiler thread decided to watch this type and
+ // then the type changed. Assume that this property is crazy, and don't ever do any more things for
+ // it.
+ newDescriptor = Top;
+
+ shouldFireWatchpointSet = true;
+ }
+
+ // Remove the old InferredStructure object if we no longer need it.
+ if (!newDescriptor.structure())
+ m_structure = nullptr;
+
+ // Add a new InferredStructure object if we need one now.
+ if (newDescriptor.structure()) {
+ if (m_structure) {
+ // We should agree on the structures if we get here.
+ ASSERT(newDescriptor.structure() == m_structure->structure());
+ } else {
+ m_structure = std::make_unique<InferredStructure>(vm, this, newDescriptor.structure());
+ newDescriptor.structure()->addTransitionWatchpoint(&m_structure->m_watchpoint);
+ }
+ }
+
+ // Finally, set the descriptor kind.
+ m_kind = newDescriptor.kind();
+
+ // Assert that we did things.
+ ASSERT(descriptor(locker) == newDescriptor);
+
+ return shouldFireWatchpointSet;
+}
+
+void InferredType::removeStructure()
+{
+ // FIXME: Find an elegant and cheap way to thread information about why we got here into the fire
+ // detail in set().
+
+ VM& vm = *Heap::heap(this)->vm();
+
+ Descriptor oldDescriptor;
+ Descriptor newDescriptor;
+ {
+ ConcurrentJITLocker locker(m_lock);
+ oldDescriptor = descriptor(locker);
+ newDescriptor = oldDescriptor;
+ newDescriptor.removeStructure();
+
+ if (!set(locker, vm, newDescriptor))
+ return;
+ }
+
+ InferredTypeFireDetail detail(this, nullptr, oldDescriptor, newDescriptor, JSValue());
+ m_watchpointSet.fireAll(detail);
+}
+
+void InferredType::InferredStructureWatchpoint::fireInternal(const FireDetail&)
+{
+ InferredStructure* inferredStructure =
+ bitwise_cast<InferredStructure*>(
+ bitwise_cast<char*>(this) - OBJECT_OFFSETOF(InferredStructure, m_watchpoint));
+
+ inferredStructure->m_parent->removeStructure();
+}
+
+void InferredType::InferredStructureFinalizer::finalizeUnconditionally()
+{
+ InferredStructure* inferredStructure =
+ bitwise_cast<InferredStructure*>(
+ bitwise_cast<char*>(this) - OBJECT_OFFSETOF(InferredStructure, m_finalizer));
+
+ ASSERT(Heap::isMarked(inferredStructure->m_parent));
+
+ if (!Heap::isMarked(inferredStructure->m_structure.get()))
+ inferredStructure->m_parent->removeStructure();
+}
+
+InferredType::InferredStructure::InferredStructure(VM& vm, InferredType* parent, Structure* structure)
+ : m_parent(parent)
+ , m_structure(vm, parent, structure)
+{
+}
+
+} // namespace JSC
+
+namespace WTF {
+
+using namespace JSC;
+
+void printInternal(PrintStream& out, InferredType::Kind kind)
+{
+ switch (kind) {
+ case InferredType::Bottom:
+ out.print("Bottom");
+ return;
+ case InferredType::Boolean:
+ out.print("Boolean");
+ return;
+ case InferredType::Other:
+ out.print("Other");
+ return;
+ case InferredType::Int32:
+ out.print("Int32");
+ return;
+ case InferredType::Number:
+ out.print("Number");
+ return;
+ case InferredType::String:
+ out.print("String");
+ return;
+ case InferredType::Symbol:
+ out.print("Symbol");
+ return;
+ case InferredType::ObjectWithStructure:
+ out.print("ObjectWithStructure");
+ return;
+ case InferredType::ObjectWithStructureOrOther:
+ out.print("ObjectWithStructureOrOther");
+ return;
+ case InferredType::Object:
+ out.print("Object");
+ return;
+ case InferredType::ObjectOrOther:
+ out.print("ObjectOrOther");
+ return;
+ case InferredType::Top:
+ out.print("Top");
+ return;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace WTF
+
diff --git a/Source/JavaScriptCore/runtime/InferredType.h b/Source/JavaScriptCore/runtime/InferredType.h
new file mode 100644
index 000000000..88f41d37b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/InferredType.h
@@ -0,0 +1,293 @@
+/*
+ * 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.
+ */
+
+#ifndef InferredType_h
+#define InferredType_h
+
+#include "ConcurrentJITLock.h"
+#include "JSCell.h"
+#include "PropertyName.h"
+#include "PutByIdFlags.h"
+#include "Watchpoint.h"
+
+namespace JSC {
+
+// This is an object used for the inference of the types of object properties.
+
+class InferredType final : public JSCell {
+public:
+ typedef JSCell Base;
+
+ static InferredType* create(VM&);
+
+ static const bool needsDestruction = true;
+ static void destroy(JSCell*);
+
+ static const unsigned StructureFlags = StructureIsImmortal | Base::StructureFlags;
+
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ DECLARE_INFO;
+
+ enum Kind : uint8_t {
+ Bottom,
+ Boolean,
+ Other,
+ Int32,
+ Number,
+ String,
+ Symbol,
+ ObjectWithStructure,
+ ObjectWithStructureOrOther,
+ Object,
+ ObjectOrOther,
+ Top
+ };
+
+ static Kind kindForFlags(PutByIdFlags);
+
+ static bool hasStructure(Kind kind)
+ {
+ switch (kind) {
+ case ObjectWithStructure:
+ case ObjectWithStructureOrOther:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ class Descriptor {
+ public:
+ Descriptor()
+ : m_kind(Bottom)
+ , m_structure(nullptr)
+ {
+ }
+
+ Descriptor(Kind kind, Structure* structure = nullptr)
+ : m_kind(kind)
+ , m_structure(structure)
+ {
+ if (hasStructure(kind))
+ ASSERT(structure);
+ }
+
+ static Descriptor forValue(JSValue);
+
+ static Descriptor forFlags(VM&, PutByIdFlags);
+
+ explicit operator bool() const
+ {
+ return m_kind != Bottom || m_structure;
+ }
+
+ Kind kind() const { return m_kind; }
+ Structure* structure() const { return m_structure; }
+
+ PutByIdFlags putByIdFlags() const;
+
+ ALWAYS_INLINE bool includesValue(JSValue value)
+ {
+ switch (m_kind) {
+ case Bottom:
+ return false;
+ case Boolean:
+ return value.isBoolean();
+ case Other:
+ return value.isUndefinedOrNull();
+ case Int32:
+ return value.isInt32();
+ case Number:
+ return value.isNumber();
+ case String:
+ return value.isString();
+ case Symbol:
+ return value.isSymbol();
+ case ObjectWithStructure:
+ return value.isCell() && value.asCell()->structure() == m_structure;
+ case ObjectWithStructureOrOther:
+ return value.isUndefinedOrNull()
+ || (value.isCell() && value.asCell()->structure() == m_structure);
+ case Object:
+ return value.isObject();
+ case ObjectOrOther:
+ return value.isUndefinedOrNull() || value.isObject();
+ case Top:
+ return true;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
+ bool operator==(const Descriptor& other) const
+ {
+ return m_kind == other.m_kind
+ && m_structure == other.m_structure;
+ }
+
+ bool operator!=(const Descriptor& other) const
+ {
+ return !(*this == other);
+ }
+
+ unsigned hash() const
+ {
+ return WTF::PtrHash<Structure*>::hash(m_structure) ^ static_cast<unsigned>(m_kind);
+ }
+
+ void merge(const Descriptor&);
+ void removeStructure();
+
+ // Returns true if this descriptor is more general than the other one.
+ bool subsumes(const Descriptor&) const;
+
+ void dumpInContext(PrintStream&, DumpContext*) const;
+ void dump(PrintStream&) const;
+
+ private:
+ Kind m_kind;
+ Structure* m_structure;
+ };
+
+ ConcurrentJITLock& lock() const { return m_lock; }
+
+ Descriptor descriptorMainThread() const
+ {
+ return Descriptor(m_kind, m_structure ? m_structure->structure() : nullptr);
+ }
+
+ Descriptor descriptor(const ConcurrentJITLocker&) const
+ {
+ return descriptorMainThread();
+ }
+ Descriptor descriptor() const
+ {
+ ConcurrentJITLocker locker(m_lock);
+ return descriptor(locker);
+ }
+
+ Kind kind(const ConcurrentJITLocker& locker) const { return descriptor(locker).kind(); }
+
+ bool isTop() const { return m_kind == Top; }
+ bool isRelevant() const { return m_kind != Top; }
+
+ // Returns true if the InferredType is still relevant after the store. It's not relevant if it's Top.
+ ALWAYS_INLINE bool willStoreValue(VM& vm, PropertyName propertyName, JSValue value)
+ {
+ Descriptor currentDescriptor = descriptorMainThread();
+ if (currentDescriptor.includesValue(value))
+ return currentDescriptor.kind() != Top;
+ return willStoreValueSlow(vm, propertyName, value);
+ }
+
+ // Immediately makes this type irrelevant.
+ void makeTop(VM& vm, PropertyName propertyName)
+ {
+ if (isTop())
+ return;
+ makeTopSlow(vm, propertyName);
+ }
+
+ // Returns true if it currently makes sense to watch this InferredType for this descriptor. Note that
+ // this will always return false for Top.
+ bool canWatch(const ConcurrentJITLocker&, const Descriptor&);
+ bool canWatch(const Descriptor&);
+
+ void addWatchpoint(const ConcurrentJITLocker&, Watchpoint*);
+ void addWatchpoint(Watchpoint*);
+
+ void dump(PrintStream&) const;
+
+private:
+ InferredType(VM&);
+ ~InferredType();
+
+ bool willStoreValueSlow(VM&, PropertyName, JSValue);
+ void makeTopSlow(VM&, PropertyName);
+
+ // Helper for willStoreValueSlow() and makeTopSlow(). This returns true if we should fire the
+ // watchpoint set.
+ bool set(const ConcurrentJITLocker&, VM&, Descriptor);
+
+ void removeStructure();
+
+ mutable ConcurrentJITLock m_lock;
+
+ Kind m_kind { Bottom };
+
+ class InferredStructureWatchpoint : public Watchpoint {
+ public:
+ InferredStructureWatchpoint() { }
+ protected:
+ void fireInternal(const FireDetail&) override;
+ };
+
+ class InferredStructureFinalizer : public UnconditionalFinalizer {
+ public:
+ InferredStructureFinalizer() { }
+ protected:
+ void finalizeUnconditionally() override;
+ };
+
+ class InferredStructure {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ InferredStructure(VM&, InferredType* parent, Structure*);
+
+ Structure* structure() const { return m_structure.get(); };
+
+ private:
+ friend class InferredType;
+ friend class InferredStructureWatchpoint;
+ friend class InferredStructureFinalizer;
+
+ InferredType* m_parent;
+ WriteBarrier<Structure> m_structure;
+
+ InferredStructureWatchpoint m_watchpoint;
+ InferredStructureFinalizer m_finalizer;
+ };
+
+ std::unique_ptr<InferredStructure> m_structure;
+
+ // NOTE: If this is being watched, we transform to Top because that implies that it wouldn't be
+ // profitable to watch it again. Also, this set is initialized clear, and is never exposed to the DFG
+ // thread. The DFG will use the InferredType as the thing that it watches.
+ InlineWatchpointSet m_watchpointSet;
+};
+
+} // namespace JSC
+
+namespace WTF {
+
+void printInternal(PrintStream&, JSC::InferredType::Kind);
+
+} // namespace WTF
+
+#endif // InferredType_h
+
diff --git a/Source/JavaScriptCore/runtime/InferredTypeTable.cpp b/Source/JavaScriptCore/runtime/InferredTypeTable.cpp
new file mode 100644
index 000000000..f76936867
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/InferredTypeTable.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "InferredTypeTable.h"
+
+#include "JSCInlines.h"
+
+namespace JSC {
+
+const ClassInfo InferredTypeTable::s_info = { "InferredTypeTable", 0, 0, CREATE_METHOD_TABLE(InferredTypeTable) };
+
+InferredTypeTable* InferredTypeTable::create(VM& vm)
+{
+ InferredTypeTable* result = new (NotNull, allocateCell<InferredTypeTable>(vm.heap)) InferredTypeTable(vm);
+ result->finishCreation(vm);
+ return result;
+}
+
+void InferredTypeTable::destroy(JSCell* cell)
+{
+ InferredTypeTable* inferredTypeTable = static_cast<InferredTypeTable*>(cell);
+ inferredTypeTable->InferredTypeTable::~InferredTypeTable();
+}
+
+Structure* InferredTypeTable::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+}
+
+void InferredTypeTable::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ InferredTypeTable* inferredTypeTable = jsCast<InferredTypeTable*>(cell);
+
+ ConcurrentJITLocker locker(inferredTypeTable->m_lock);
+
+ for (auto& entry : inferredTypeTable->m_table) {
+ if (!entry.value)
+ continue;
+ if (entry.value->isRelevant())
+ visitor.append(&entry.value);
+ else
+ entry.value.clear();
+ }
+}
+
+InferredType* InferredTypeTable::get(const ConcurrentJITLocker&, UniquedStringImpl* uid)
+{
+ auto iter = m_table.find(uid);
+ if (iter == m_table.end() || !iter->value)
+ return nullptr;
+
+ // Take this opportunity to prune invalidated types.
+ if (!iter->value->isRelevant()) {
+ iter->value.clear();
+ return nullptr;
+ }
+
+ return iter->value.get();
+}
+
+InferredType* InferredTypeTable::get(UniquedStringImpl* uid)
+{
+ ConcurrentJITLocker locker(m_lock);
+ return get(locker, uid);
+}
+
+InferredType* InferredTypeTable::get(PropertyName propertyName)
+{
+ return get(propertyName.uid());
+}
+
+bool InferredTypeTable::willStoreValue(
+ VM& vm, PropertyName propertyName, JSValue value, StoredPropertyAge age)
+{
+ // The algorithm here relies on the fact that only one thread modifies the hash map.
+
+ if (age == OldProperty) {
+ TableType::iterator iter = m_table.find(propertyName.uid());
+ if (iter == m_table.end() || !iter->value)
+ return false; // Absence on replace => top.
+
+ if (iter->value->willStoreValue(vm, propertyName, value))
+ return true;
+
+ iter->value.clear();
+ return false;
+ }
+
+ TableType::AddResult result;
+ {
+ ConcurrentJITLocker locker(m_lock);
+ result = m_table.add(propertyName.uid(), WriteBarrier<InferredType>());
+ }
+ if (result.isNewEntry) {
+ InferredType* inferredType = InferredType::create(vm);
+ WTF::storeStoreFence();
+ result.iterator->value.set(vm, this, inferredType);
+ } else if (!result.iterator->value)
+ return false;
+
+ if (result.iterator->value->willStoreValue(vm, propertyName, value))
+ return true;
+
+ result.iterator->value.clear();
+ return false;
+}
+
+void InferredTypeTable::makeTop(VM& vm, PropertyName propertyName, StoredPropertyAge age)
+{
+ // The algorithm here relies on the fact that only one thread modifies the hash map.
+ if (age == OldProperty) {
+ TableType::iterator iter = m_table.find(propertyName.uid());
+ if (iter == m_table.end() || !iter->value)
+ return; // Absence on replace => top.
+
+ iter->value->makeTop(vm, propertyName);
+ iter->value.clear();
+ return;
+ }
+
+ TableType::AddResult result;
+ {
+ ConcurrentJITLocker locker(m_lock);
+ result = m_table.add(propertyName.uid(), WriteBarrier<InferredType>());
+ }
+ if (!result.iterator->value)
+ return;
+
+ result.iterator->value->makeTop(vm, propertyName);
+ result.iterator->value.clear();
+}
+
+InferredTypeTable::InferredTypeTable(VM& vm)
+ : Base(vm, vm.inferredTypeTableStructure.get())
+{
+}
+
+InferredTypeTable::~InferredTypeTable()
+{
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/runtime/InferredTypeTable.h b/Source/JavaScriptCore/runtime/InferredTypeTable.h
new file mode 100644
index 000000000..61bf9b698
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/InferredTypeTable.h
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#ifndef InferredTypeTable_h
+#define InferredTypeTable_h
+
+#include "Identifier.h"
+#include "InferredType.h"
+#include "JSCell.h"
+
+namespace JSC {
+
+// A table of inferred types for some structure. This is a JSCell because that simplifies the Structure
+// destructor and makes lifetime easier to manage. For example, since it's a cell, we know that this thing
+// cannot be deleted while the DFG is running. This is separate from PropertyTable because most properties
+// will not have an InferredType, since most properties are in dictionaries (if you think of "a property"
+// as being "a property in some Structure"). Also, this will happily conflate the types of properties from
+// different structures even if the structures represent disjoint sets of objects.
+
+class InferredTypeTable final : public JSCell {
+public:
+ typedef JSCell Base;
+
+ static InferredTypeTable* create(VM&);
+
+ static const bool needsDestruction = true;
+ static void destroy(JSCell*);
+
+ static const unsigned StructureFlags = StructureIsImmortal | Base::StructureFlags;
+
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ DECLARE_INFO;
+
+ ConcurrentJITLock& lock() { return m_lock; }
+
+ bool isEmpty() const { return m_table.isEmpty(); }
+
+ // Get the current inferred type. Returns nullptr for both Top and Bottom. Null means Bottom if the
+ // owning Structure doesn't know about the property.
+ InferredType* get(const ConcurrentJITLocker&, UniquedStringImpl*);
+ InferredType* get(UniquedStringImpl*);
+ InferredType* get(PropertyName);
+
+ enum StoredPropertyAge {
+ NewProperty,
+ OldProperty
+ };
+
+ // Returns true if the InferredType for this property is still relevant after the store. It's not
+ // relevant if it's Top. Note that this table will internally prune Top entries.
+ bool willStoreValue(VM&, PropertyName, JSValue, StoredPropertyAge);
+
+ // Invalidates the type for the property. Useful if we detect a store in a reflective context.
+ void makeTop(VM&, PropertyName, StoredPropertyAge);
+
+private:
+ InferredTypeTable(VM&);
+ ~InferredTypeTable();
+
+ // Bottom: absence from table.
+ // Top: null value in table, !value->isRelevant(), or absence from table.
+ //
+ // We know how to determine if absence from the table is bottom or top depending on whether the
+ // property is present in the owning structure. Hence, depending on the structure, absence may have
+ // different meanings. The way that this class determines if the owning structure knows of the property
+ // is that we differentiate between actions: replace or transition. If we're adding a new property
+ // (transition), then absence means bottom. If we're storing to an existing property (replace), then
+ // absence means top. To make this work, we have to watch out for the case where two structures, S1 and
+ // S2, share the same InferredTypeTable and neither of them initially know about property P. S1 may
+ // want to add P without a type, while S2 may want to add P with a type. If S1 added P and used absence
+ // to indicate Top, then S2 would use that absence to mean Bottom and would end up creating a non-Top
+ // entry in the table. Then S1 would forget that it wanted Top, and would use S2's type. Clearly,
+ // that's bad. We avoid such confusion by ensuring that a transition always adds an entry. Hence,
+ // absence-means-bottom only comes into play for properties added before the InferredTypeTable was
+ // created.
+ typedef HashMap<RefPtr<UniquedStringImpl>, WriteBarrier<InferredType>, IdentifierRepHash> TableType;
+
+ TableType m_table;
+
+ // We only grab this lock when we're doing modifications on the main thread, or reads on the compiler
+ // thread. The compiler thread is not allowed to do modifications.
+ ConcurrentJITLock m_lock;
+};
+
+} // namespace JSC
+
+#endif // InferredTypeTable_h
+
+
diff --git a/Source/JavaScriptCore/runtime/InferredValue.cpp b/Source/JavaScriptCore/runtime/InferredValue.cpp
new file mode 100644
index 000000000..73c6bc76b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/InferredValue.cpp
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "InferredValue.h"
+
+#include "JSCInlines.h"
+
+namespace JSC {
+
+const ClassInfo InferredValue::s_info = { "InferredValue", 0, 0, CREATE_METHOD_TABLE(InferredValue) };
+
+InferredValue* InferredValue::create(VM& vm)
+{
+ InferredValue* result = new (NotNull, allocateCell<InferredValue>(vm.heap)) InferredValue(vm);
+ result->finishCreation(vm);
+ return result;
+}
+
+void InferredValue::destroy(JSCell* cell)
+{
+ InferredValue* inferredValue = static_cast<InferredValue*>(cell);
+ inferredValue->InferredValue::~InferredValue();
+}
+
+Structure* InferredValue::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+}
+
+void InferredValue::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ InferredValue* inferredValue = jsCast<InferredValue*>(cell);
+
+ if (inferredValue->m_set.hasBeenInvalidated()) {
+ inferredValue->m_cleanup = nullptr;
+ return;
+ }
+
+ if (!inferredValue->m_value)
+ return;
+ if (!inferredValue->m_value.get().isCell())
+ return;
+
+ if (!inferredValue->m_cleanup)
+ inferredValue->m_cleanup = std::make_unique<ValueCleanup>(inferredValue);
+ visitor.addUnconditionalFinalizer(inferredValue->m_cleanup.get());
+}
+
+InferredValue::InferredValue(VM& vm)
+ : Base(vm, vm.inferredValueStructure.get())
+ , m_set(ClearWatchpoint)
+{
+}
+
+InferredValue::~InferredValue()
+{
+}
+
+void InferredValue::notifyWriteSlow(VM& vm, JSValue value, const FireDetail& detail)
+{
+ ASSERT(!!value);
+ switch (m_set.state()) {
+ case ClearWatchpoint:
+ m_value.set(vm, this, value);
+ m_set.startWatching();
+ return;
+
+ case IsWatched:
+ ASSERT(!!m_value);
+ if (m_value.get() == value)
+ return;
+ invalidate(detail);
+ return;
+
+ case IsInvalidated:
+ ASSERT_NOT_REACHED();
+ return;
+ }
+
+ ASSERT_NOT_REACHED();
+}
+
+void InferredValue::notifyWriteSlow(VM& vm, JSValue value, const char* reason)
+{
+ notifyWriteSlow(vm, value, StringFireDetail(reason));
+}
+
+InferredValue::ValueCleanup::ValueCleanup(InferredValue* owner)
+ : m_owner(owner)
+{
+}
+
+InferredValue::ValueCleanup::~ValueCleanup()
+{
+}
+
+void InferredValue::ValueCleanup::finalizeUnconditionally()
+{
+ ASSERT(m_owner->m_value);
+ ASSERT(m_owner->m_value.get().isCell());
+
+ if (Heap::isMarked(m_owner->m_value.get().asCell()))
+ return;
+
+ m_owner->invalidate(StringFireDetail("InferredValue clean-up during GC"));
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/runtime/InferredValue.h b/Source/JavaScriptCore/runtime/InferredValue.h
new file mode 100644
index 000000000..28318e992
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/InferredValue.h
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+#ifndef InferredValue_h
+#define InferredValue_h
+
+#include "JSCell.h"
+#include "Watchpoint.h"
+#include "WriteBarrier.h"
+
+namespace JSC {
+
+// Allocate one of these if you'd like to infer a constant value. Writes to the value should use
+// notifyWrite(). So long as exactly one value had ever been written and invalidate() has never been
+// called, and you register a watchpoint, you can rely on the inferredValue() being the one true
+// value.
+//
+// Commonly used for inferring singletons - in that case each allocation does notifyWrite(). But you
+// can use it for other things as well.
+
+class InferredValue : public JSCell {
+public:
+ typedef JSCell Base;
+
+ static InferredValue* create(VM&);
+
+ static const bool needsDestruction = true;
+ static void destroy(JSCell*);
+
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ DECLARE_INFO;
+
+ // For the purpose of deciding whether or not to watch this variable, you only need
+ // to inspect inferredValue(). If this returns something other than the empty
+ // value, then it means that at all future safepoints, this watchpoint set will be
+ // in one of these states:
+ //
+ // IsWatched: in this case, the variable's value must still be the
+ // inferredValue.
+ //
+ // IsInvalidated: in this case the variable's value may be anything but you'll
+ // either notice that it's invalidated and not install the watchpoint, or
+ // you will have been notified that the watchpoint was fired.
+ JSValue inferredValue() { return m_value.get(); }
+
+ // Forwards some WatchpointSet methods.
+ WatchpointState state() const { return m_set.state(); }
+ bool isStillValid() const { return m_set.isStillValid(); }
+ bool hasBeenInvalidated() const { return m_set.hasBeenInvalidated(); }
+ void add(Watchpoint* watchpoint) { m_set.add(watchpoint); }
+
+ void notifyWrite(VM& vm, JSValue value, const FireDetail& detail)
+ {
+ if (LIKELY(m_set.stateOnJSThread() == IsInvalidated))
+ return;
+ notifyWriteSlow(vm, value, detail);
+ }
+
+ void notifyWrite(VM& vm, JSValue value, const char* reason)
+ {
+ if (LIKELY(m_set.stateOnJSThread() == IsInvalidated))
+ return;
+ notifyWriteSlow(vm, value, reason);
+ }
+
+ void invalidate(const FireDetail& detail)
+ {
+ m_value.clear();
+ m_set.invalidate(detail);
+ }
+
+ static const unsigned StructureFlags = StructureIsImmortal | Base::StructureFlags;
+
+ // We could have used Weak<>. But we want arbitrary JSValues, not just cells. It's also somewhat
+ // convenient to have eager notification of death.
+ //
+ // Also note that this should be a private class, but it isn't because Windows.
+ class ValueCleanup : public UnconditionalFinalizer {
+ WTF_MAKE_FAST_ALLOCATED;
+
+ public:
+ ValueCleanup(InferredValue*);
+ virtual ~ValueCleanup();
+
+ protected:
+ void finalizeUnconditionally() override;
+
+ private:
+ InferredValue* m_owner;
+ };
+
+private:
+ InferredValue(VM&);
+ ~InferredValue();
+
+ JS_EXPORT_PRIVATE void notifyWriteSlow(VM&, JSValue, const FireDetail&);
+ JS_EXPORT_PRIVATE void notifyWriteSlow(VM&, JSValue, const char* reason);
+
+ friend class ValueCleanup;
+
+ InlineWatchpointSet m_set;
+ WriteBarrier<Unknown> m_value;
+ std::unique_ptr<ValueCleanup> m_cleanup;
+};
+
+// FIXME: We could have an InlineInferredValue, which only allocates the InferredValue object when
+// a notifyWrite() transitions us towards watching, and then clears the reference (allowing the object
+// to die) when we get invalidated.
+
+} // namespace JSC
+
+#endif // InferredValue_h
+
diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.cpp b/Source/JavaScriptCore/runtime/InitializeThreading.cpp
index 1cb5e7abf..d74460f20 100644
--- a/Source/JavaScriptCore/runtime/InitializeThreading.cpp
+++ b/Source/JavaScriptCore/runtime/InitializeThreading.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 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
@@ -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.
*
@@ -38,6 +38,7 @@
#include "JSGlobalObject.h"
#include "JSLock.h"
#include "LLIntData.h"
+#include "StructureIDTable.h"
#include "WriteBarrier.h"
#include <mutex>
#include <wtf/dtoa.h>
@@ -55,7 +56,6 @@ void initializeThreading()
std::call_once(initializeThreadingOnceFlag, []{
WTF::double_conversion::initialize();
WTF::initializeThreading();
- GlobalJSLock::initialize();
Options::initialize();
if (Options::recordGCPauseTimes())
HeapStatistics::initialize();
@@ -65,13 +65,12 @@ void initializeThreading()
#if ENABLE(ASSEMBLER)
ExecutableAllocator::initializeAllocator();
#endif
- JSStack::initializeThreading();
-#if ENABLE(LLINT)
LLInt::initialize();
-#endif
#ifndef NDEBUG
DisallowGC::initialize();
#endif
+ WTFThreadData& threadData = wtfThreadData();
+ threadData.setSavedLastStackTop(threadData.stack().origin());
});
}
diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.h b/Source/JavaScriptCore/runtime/InitializeThreading.h
index 91301a0d8..39845c243 100644
--- a/Source/JavaScriptCore/runtime/InitializeThreading.h
+++ b/Source/JavaScriptCore/runtime/InitializeThreading.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.
*
@@ -31,9 +31,9 @@
namespace JSC {
- // This function must be called from the main thread. It is safe to call it repeatedly.
- // Darwin is an exception to this rule: it is OK to call this function from any thread, even reentrantly.
- JS_EXPORT_PRIVATE void initializeThreading();
+// This function must be called from the main thread. It is safe to call it repeatedly.
+// Darwin is an exception to this rule: it is OK to call this function from any thread, even reentrantly.
+JS_EXPORT_PRIVATE void initializeThreading();
}
diff --git a/Source/JavaScriptCore/runtime/InspectorInstrumentationObject.cpp b/Source/JavaScriptCore/runtime/InspectorInstrumentationObject.cpp
new file mode 100644
index 000000000..1c0b28aaf
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/InspectorInstrumentationObject.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "InspectorInstrumentationObject.h"
+
+#include "JSCInlines.h"
+#include "Lookup.h"
+#include <wtf/DataLog.h>
+
+namespace JSC {
+
+EncodedJSValue JSC_HOST_CALL inspectorInstrumentationObjectLog(ExecState*);
+
+}
+
+#include "InspectorInstrumentationObject.lut.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(InspectorInstrumentationObject);
+
+const ClassInfo InspectorInstrumentationObject::s_info = { "InspectorInstrumentation", &Base::s_info, &inspectorInstrumentationObjectTable, CREATE_METHOD_TABLE(InspectorInstrumentationObject) };
+
+/* Source for InspectorInstrumentationObject.lut.h
+@begin inspectorInstrumentationObjectTable
+ log inspectorInstrumentationObjectLog DontEnum|Function 1
+ promiseFulfilled JSBuiltin DontEnum|Function 3
+ promiseRejected JSBuiltin DontEnum|Function 3
+@end
+*/
+
+InspectorInstrumentationObject::InspectorInstrumentationObject(VM& vm, Structure* structure)
+ : JSNonFinalObject(vm, structure)
+{
+}
+
+void InspectorInstrumentationObject::finishCreation(VM& vm, JSGlobalObject*)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+ putDirectWithoutTransition(vm, vm.propertyNames->isEnabled, jsBoolean(false));
+}
+
+bool InspectorInstrumentationObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<Base>(exec, inspectorInstrumentationObjectTable, jsCast<InspectorInstrumentationObject*>(object), propertyName, slot);
+}
+
+bool InspectorInstrumentationObject::isEnabled(VM& vm) const
+{
+ return getDirect(vm, vm.propertyNames->isEnabled).asBoolean();
+}
+
+void InspectorInstrumentationObject::enable(VM& vm)
+{
+ putDirect(vm, vm.propertyNames->isEnabled, jsBoolean(true));
+}
+
+void InspectorInstrumentationObject::disable(VM& vm)
+{
+ putDirect(vm, vm.propertyNames->isEnabled, jsBoolean(false));
+}
+
+// ------------------------------ Functions --------------------------------
+
+EncodedJSValue JSC_HOST_CALL inspectorInstrumentationObjectLog(ExecState* exec)
+{
+ JSValue target = exec->argument(0);
+ String value = target.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ dataLog(value, "\n");
+ return JSValue::encode(jsUndefined());
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/InspectorInstrumentationObject.h b/Source/JavaScriptCore/runtime/InspectorInstrumentationObject.h
new file mode 100644
index 000000000..37207160c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/InspectorInstrumentationObject.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#ifndef InspectorInstrumentationObject_h
+#define InspectorInstrumentationObject_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class InspectorInstrumentationObject : public JSNonFinalObject {
+private:
+ InspectorInstrumentationObject(VM&, Structure*);
+
+public:
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static InspectorInstrumentationObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+ {
+ InspectorInstrumentationObject* object = new (NotNull, allocateCell<InspectorInstrumentationObject>(vm.heap)) InspectorInstrumentationObject(vm, structure);
+ object->finishCreation(vm, globalObject);
+ return object;
+ }
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+
+ void enable(VM&);
+ void disable(VM&);
+ bool isEnabled(VM&) const;
+
+protected:
+ void finishCreation(VM&, JSGlobalObject*);
+};
+
+} // namespace JSC
+
+#endif // InspectorInstrumentationObject_h
diff --git a/Source/JavaScriptCore/runtime/IntegralTypedArrayBase.h b/Source/JavaScriptCore/runtime/IntegralTypedArrayBase.h
index 99c989ec7..466ff8cde 100644
--- a/Source/JavaScriptCore/runtime/IntegralTypedArrayBase.h
+++ b/Source/JavaScriptCore/runtime/IntegralTypedArrayBase.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
diff --git a/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp b/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp
deleted file mode 100644
index b38dae9f8..000000000
--- a/Source/JavaScriptCore/runtime/IntendedStructureChain.cpp
+++ /dev/null
@@ -1,141 +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 COMPUTER, 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
- * 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 "IntendedStructureChain.h"
-
-#include "CodeBlock.h"
-#include "Operations.h"
-#include "StructureChain.h"
-
-namespace JSC {
-
-IntendedStructureChain::IntendedStructureChain(JSGlobalObject* globalObject, Structure* head)
- : m_globalObject(globalObject)
- , m_head(head)
-{
- JSValue prototype = head->prototypeForLookup(globalObject);
- if (prototype.isNull())
- return;
- for (Structure* current = asObject(prototype)->structure(); current; current = current->storedPrototypeStructure())
- m_vector.append(current);
-}
-
-IntendedStructureChain::IntendedStructureChain(CodeBlock* codeBlock, Structure* head, Structure* prototypeStructure)
- : m_globalObject(codeBlock->globalObject())
- , m_head(head)
-{
- m_vector.append(prototypeStructure);
-}
-
-IntendedStructureChain::IntendedStructureChain(CodeBlock* codeBlock, Structure* head, StructureChain* chain)
- : m_globalObject(codeBlock->globalObject())
- , m_head(head)
-{
- for (unsigned i = 0; chain->head()[i]; ++i)
- m_vector.append(chain->head()[i].get());
-}
-
-IntendedStructureChain::IntendedStructureChain(CodeBlock* codeBlock, Structure* head, StructureChain* chain, unsigned count)
- : m_globalObject(codeBlock->globalObject())
- , m_head(head)
-{
- for (unsigned i = 0; i < count; ++i)
- m_vector.append(chain->head()[i].get());
-}
-
-IntendedStructureChain::~IntendedStructureChain()
-{
-}
-
-bool IntendedStructureChain::isStillValid() const
-{
- JSValue currentPrototype = m_head->prototypeForLookup(m_globalObject);
- for (unsigned i = 0; i < m_vector.size(); ++i) {
- if (asObject(currentPrototype)->structure() != m_vector[i])
- return false;
- currentPrototype = m_vector[i]->storedPrototype();
- }
- return true;
-}
-
-bool IntendedStructureChain::matches(StructureChain* chain) const
-{
- for (unsigned i = 0; i < m_vector.size(); ++i) {
- if (m_vector[i] != chain->head()[i].get())
- return false;
- }
- if (chain->head()[m_vector.size()])
- return false;
- return true;
-}
-
-StructureChain* IntendedStructureChain::chain(VM& vm) const
-{
- ASSERT(isStillValid());
- StructureChain* result = StructureChain::create(vm, m_head);
- ASSERT(matches(result));
- return result;
-}
-
-bool IntendedStructureChain::mayInterceptStoreTo(VM& vm, StringImpl* uid)
-{
- for (unsigned i = 0; i < m_vector.size(); ++i) {
- unsigned attributes;
- JSCell* specificValue;
- PropertyOffset offset = m_vector[i]->getConcurrently(vm, uid, attributes, specificValue);
- if (!isValidOffset(offset))
- continue;
- if (attributes & (ReadOnly | Accessor))
- return true;
- return false;
- }
- return false;
-}
-
-bool IntendedStructureChain::isNormalized()
-{
- if (m_head->typeInfo().type() == ProxyType)
- return false;
- for (unsigned i = 0; i < m_vector.size(); ++i) {
- Structure* structure = m_vector[i];
- if (structure->typeInfo().type() == ProxyType)
- return false;
- if (structure->isDictionary())
- return false;
- }
- return true;
-}
-
-JSObject* IntendedStructureChain::terminalPrototype() const
-{
- ASSERT(!m_vector.isEmpty());
- if (m_vector.size() == 1)
- return asObject(m_head->prototypeForLookup(m_globalObject));
- return asObject(m_vector[m_vector.size() - 2]->storedPrototype());
-}
-
-} // namespace JSC
-
diff --git a/Source/JavaScriptCore/runtime/IntendedStructureChain.h b/Source/JavaScriptCore/runtime/IntendedStructureChain.h
deleted file mode 100644
index 40af95c65..000000000
--- a/Source/JavaScriptCore/runtime/IntendedStructureChain.h
+++ /dev/null
@@ -1,70 +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 COMPUTER, 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
- * 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 IntendedStructureChain_h
-#define IntendedStructureChain_h
-
-#include "Structure.h"
-#include <wtf/RefCounted.h>
-
-namespace JSC {
-
-class CodeBlock;
-class JSGlobalObject;
-class StructureChain;
-class VM;
-
-class IntendedStructureChain : public RefCounted<IntendedStructureChain> {
-public:
- IntendedStructureChain(JSGlobalObject* globalObject, Structure* head);
- IntendedStructureChain(CodeBlock* codeBlock, Structure* head, Structure* prototypeStructure);
- IntendedStructureChain(CodeBlock* codeBlock, Structure* head, StructureChain* chain);
- IntendedStructureChain(CodeBlock* codeBlock, Structure* head, StructureChain* chain, unsigned count);
- ~IntendedStructureChain();
-
- bool isStillValid() const;
- bool matches(StructureChain*) const;
- StructureChain* chain(VM&) const;
- bool mayInterceptStoreTo(VM&, StringImpl* uid);
- bool isNormalized();
-
- Structure* head() const { return m_head; }
-
- size_t size() const { return m_vector.size(); }
- Structure* at(size_t index) { return m_vector[index]; }
- Structure* operator[](size_t index) { return at(index); }
-
- JSObject* terminalPrototype() const;
-
- Structure* last() const { return m_vector.last(); }
-private:
- JSGlobalObject* m_globalObject;
- Structure* m_head;
- Vector<Structure*> m_vector;
-};
-
-} // namespace JSC
-
-#endif // IntendedStructureChain_h
diff --git a/Source/JavaScriptCore/runtime/InternalFunction.cpp b/Source/JavaScriptCore/runtime/InternalFunction.cpp
index 69120bea5..bb23d45ed 100644
--- a/Source/JavaScriptCore/runtime/InternalFunction.cpp
+++ b/Source/JavaScriptCore/runtime/InternalFunction.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2007, 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 Library General Public
@@ -26,13 +26,13 @@
#include "FunctionPrototype.h"
#include "JSGlobalObject.h"
#include "JSString.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(InternalFunction);
-const ClassInfo InternalFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(InternalFunction) };
+const ClassInfo InternalFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(InternalFunction) };
InternalFunction::InternalFunction(VM& vm, Structure* structure)
: JSDestructibleObject(vm, structure)
@@ -78,4 +78,39 @@ const String InternalFunction::calculatedDisplayName(ExecState* exec)
return name(exec);
}
+Structure* InternalFunction::createSubclassStructure(ExecState* exec, JSValue newTarget, Structure* baseClass)
+{
+
+ VM& vm = exec->vm();
+ // We allow newTarget == JSValue() because the API needs to be able to create classes without having a real JS frame.
+ // Since we don't allow subclassing in the API we just treat newTarget == JSValue() as newTarget == exec->callee()
+ ASSERT(!newTarget || newTarget.isFunction());
+
+ if (newTarget && newTarget != exec->callee()) {
+ // newTarget may be an InternalFunction if we were called from Reflect.construct.
+ JSFunction* targetFunction = jsDynamicCast<JSFunction*>(newTarget);
+
+ if (LIKELY(targetFunction)) {
+ Structure* structure = targetFunction->rareData(vm)->internalFunctionAllocationStructure();
+ if (LIKELY(structure && structure->classInfo() == baseClass->classInfo()))
+ return structure;
+
+ // Note, Reflect.construct might cause the profile to churn but we don't care.
+ JSObject* prototype = jsDynamicCast<JSObject*>(newTarget.get(exec, exec->propertyNames().prototype));
+ if (prototype)
+ return targetFunction->rareData(vm)->createInternalFunctionAllocationStructureFromBase(vm, prototype, baseClass);
+ } else {
+ JSObject* prototype = jsDynamicCast<JSObject*>(newTarget.get(exec, exec->propertyNames().prototype));
+ if (prototype) {
+ // This only happens if someone Reflect.constructs our builtin constructor with another builtin constructor as the new.target.
+ // Thus, we don't care about the cost of looking up the structure from our hash table every time.
+ return vm.prototypeMap.emptyStructureForPrototypeFromBaseStructure(prototype, baseClass);
+ }
+ }
+ }
+
+ return baseClass;
+}
+
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/InternalFunction.h b/Source/JavaScriptCore/runtime/InternalFunction.h
index e216c2f82..e392214a1 100644
--- a/Source/JavaScriptCore/runtime/InternalFunction.h
+++ b/Source/JavaScriptCore/runtime/InternalFunction.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2006, 2007, 2008, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
* Copyright (C) 2007 Maks Orlovich
*
@@ -29,40 +29,41 @@
namespace JSC {
- class FunctionPrototype;
+class FunctionPrototype;
- class InternalFunction : public JSDestructibleObject {
- public:
- typedef JSDestructibleObject Base;
+class InternalFunction : public JSDestructibleObject {
+public:
+ typedef JSDestructibleObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | ImplementsHasInstance | ImplementsDefaultHasInstance | TypeOfShouldCallGetCallData;
- DECLARE_EXPORT_INFO;
+ DECLARE_EXPORT_INFO;
- JS_EXPORT_PRIVATE const String& name(ExecState*);
- const String displayName(ExecState*);
- const String calculatedDisplayName(ExecState*);
+ JS_EXPORT_PRIVATE const String& name(ExecState*);
+ const String displayName(ExecState*);
+ const String calculatedDisplayName(ExecState*);
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
- {
- return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info());
- }
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info());
+ }
- protected:
- static const unsigned StructureFlags = ImplementsHasInstance | JSObject::StructureFlags;
+ JS_EXPORT_PRIVATE static Structure* createSubclassStructure(ExecState*, JSValue newTarget, Structure*);
- JS_EXPORT_PRIVATE InternalFunction(VM&, Structure*);
+protected:
+ JS_EXPORT_PRIVATE InternalFunction(VM&, Structure*);
- JS_EXPORT_PRIVATE void finishCreation(VM&, const String& name);
+ JS_EXPORT_PRIVATE void finishCreation(VM&, const String& name);
- static CallType getCallData(JSCell*, CallData&);
- };
+ static CallType getCallData(JSCell*, CallData&);
+};
- InternalFunction* asInternalFunction(JSValue);
+InternalFunction* asInternalFunction(JSValue);
- inline InternalFunction* asInternalFunction(JSValue value)
- {
- ASSERT(asObject(value)->inherits(InternalFunction::info()));
- return static_cast<InternalFunction*>(asObject(value));
- }
+inline InternalFunction* asInternalFunction(JSValue value)
+{
+ ASSERT(asObject(value)->inherits(InternalFunction::info()));
+ return static_cast<InternalFunction*>(asObject(value));
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/IntlCollator.cpp b/Source/JavaScriptCore/runtime/IntlCollator.cpp
new file mode 100644
index 000000000..2b9d41d7e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlCollator.cpp
@@ -0,0 +1,450 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ * Copyright (C) 2015 Sukolsak Sakshuwong (sukolsak@gmail.com)
+ *
+ * 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 "IntlCollator.h"
+
+#if ENABLE(INTL)
+
+#include "Error.h"
+#include "IntlCollatorConstructor.h"
+#include "IntlObject.h"
+#include "JSBoundFunction.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "ObjectConstructor.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+#include <unicode/ucol.h>
+#include <wtf/unicode/Collator.h>
+
+namespace JSC {
+
+const ClassInfo IntlCollator::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(IntlCollator) };
+
+// FIXME: Implement kf (caseFirst).
+static const char* const relevantExtensionKeys[2] = { "co", "kn" };
+static const size_t indexOfExtensionKeyCo = 0;
+static const size_t indexOfExtensionKeyKn = 1;
+
+IntlCollator* IntlCollator::create(VM& vm, IntlCollatorConstructor* constructor)
+{
+ IntlCollator* format = new (NotNull, allocateCell<IntlCollator>(vm.heap)) IntlCollator(vm, constructor->collatorStructure());
+ format->finishCreation(vm);
+ return format;
+}
+
+Structure* IntlCollator::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlCollator::IntlCollator(VM& vm, Structure* structure)
+ : JSDestructibleObject(vm, structure)
+{
+}
+
+IntlCollator::~IntlCollator()
+{
+ if (m_collator)
+ ucol_close(m_collator);
+}
+
+void IntlCollator::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+}
+
+void IntlCollator::destroy(JSCell* cell)
+{
+ static_cast<IntlCollator*>(cell)->IntlCollator::~IntlCollator();
+}
+
+void IntlCollator::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ IntlCollator* thisObject = jsCast<IntlCollator*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_boundCompare);
+}
+
+static Vector<String> sortLocaleData(const String& locale, size_t keyIndex)
+{
+ // 9.1 Internal slots of Service Constructors & 10.2.3 Internal slots (ECMA-402 2.0)
+ Vector<String> keyLocaleData;
+ switch (keyIndex) {
+ case indexOfExtensionKeyCo: {
+ // 10.2.3 "The first element of [[sortLocaleData]][locale].co and [[searchLocaleData]][locale].co must be null for all locale values."
+ keyLocaleData.append({ });
+
+ UErrorCode status = U_ZERO_ERROR;
+ UEnumeration* enumeration = ucol_getKeywordValuesForLocale("collation", locale.utf8().data(), false, &status);
+ if (U_SUCCESS(status)) {
+ const char* collation;
+ while ((collation = uenum_next(enumeration, nullptr, &status)) && U_SUCCESS(status)) {
+ // 10.2.3 "The values "standard" and "search" must not be used as elements in any [[sortLocaleData]][locale].co and [[searchLocaleData]][locale].co array."
+ if (!strcmp(collation, "standard") || !strcmp(collation, "search"))
+ continue;
+
+ // Map keyword values to BCP 47 equivalents.
+ if (!strcmp(collation, "dictionary"))
+ collation = "dict";
+ else if (!strcmp(collation, "gb2312han"))
+ collation = "gb2312";
+ else if (!strcmp(collation, "phonebook"))
+ collation = "phonebk";
+ else if (!strcmp(collation, "traditional"))
+ collation = "trad";
+
+ keyLocaleData.append(collation);
+ }
+ uenum_close(enumeration);
+ }
+ break;
+ }
+ case indexOfExtensionKeyKn:
+ keyLocaleData.reserveInitialCapacity(2);
+ keyLocaleData.uncheckedAppend(ASCIILiteral("false"));
+ keyLocaleData.uncheckedAppend(ASCIILiteral("true"));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ return keyLocaleData;
+}
+
+static Vector<String> searchLocaleData(const String&, size_t keyIndex)
+{
+ // 9.1 Internal slots of Service Constructors & 10.2.3 Internal slots (ECMA-402 2.0)
+ Vector<String> keyLocaleData;
+ switch (keyIndex) {
+ case indexOfExtensionKeyCo:
+ // 10.2.3 "The first element of [[sortLocaleData]][locale].co and [[searchLocaleData]][locale].co must be null for all locale values."
+ keyLocaleData.reserveInitialCapacity(1);
+ keyLocaleData.append({ });
+ break;
+ case indexOfExtensionKeyKn:
+ keyLocaleData.reserveInitialCapacity(2);
+ keyLocaleData.uncheckedAppend(ASCIILiteral("false"));
+ keyLocaleData.uncheckedAppend(ASCIILiteral("true"));
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ return keyLocaleData;
+}
+
+void IntlCollator::initializeCollator(ExecState& state, JSValue locales, JSValue optionsValue)
+{
+ // 10.1.1 InitializeCollator (collator, locales, options) (ECMA-402 2.0)
+ // 1. If collator has an [[initializedIntlObject]] internal slot with value true, throw a TypeError exception.
+ // 2. Set collator.[[initializedIntlObject]] to true.
+
+ // 3. Let requestedLocales be CanonicalizeLocaleList(locales).
+ auto requestedLocales = canonicalizeLocaleList(state, locales);
+ // 4. ReturnIfAbrupt(requestedLocales).
+ if (state.hadException())
+ return;
+
+ // 5. If options is undefined, then
+ JSObject* options;
+ if (optionsValue.isUndefined()) {
+ // a. Let options be ObjectCreate(%ObjectPrototype%).
+ options = constructEmptyObject(&state);
+ } else { // 6. Else
+ // a. Let options be ToObject(options).
+ options = optionsValue.toObject(&state);
+ // b. ReturnIfAbrupt(options).
+ if (state.hadException())
+ return;
+ }
+
+ // 7. Let u be GetOption(options, "usage", "string", «"sort", "search"», "sort").
+ String usageString = intlStringOption(state, options, state.vm().propertyNames->usage, { "sort", "search" }, "usage must be either \"sort\" or \"search\"", "sort");
+ // 8. ReturnIfAbrupt(u).
+ if (state.hadException())
+ return;
+ // 9. Set collator.[[usage]] to u.
+ if (usageString == "sort")
+ m_usage = Usage::Sort;
+ else if (usageString == "search")
+ m_usage = Usage::Search;
+ else
+ ASSERT_NOT_REACHED();
+
+ // 10. If u is "sort", then
+ // a. Let localeData be the value of %Collator%.[[sortLocaleData]];
+ // 11. Else
+ // a. Let localeData be the value of %Collator%.[[searchLocaleData]].
+ Vector<String> (*localeData)(const String&, size_t);
+ if (m_usage == Usage::Sort)
+ localeData = sortLocaleData;
+ else
+ localeData = searchLocaleData;
+
+ // 12. Let opt be a new Record.
+ HashMap<String, String> opt;
+
+ // 13. Let matcher be GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit").
+ String matcher = intlStringOption(state, options, state.vm().propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit");
+ // 14. ReturnIfAbrupt(matcher).
+ if (state.hadException())
+ return;
+ // 15. Set opt.[[localeMatcher]] to matcher.
+ opt.add(ASCIILiteral("localeMatcher"), matcher);
+
+ // 16. For each row in Table 1, except the header row, do:
+ // a. Let key be the name given in the Key column of the row.
+ // b. Let prop be the name given in the Property column of the row.
+ // c. Let type be the string given in the Type column of the row.
+ // d. Let list be a List containing the Strings given in the Values column of the row, or undefined if no strings are given.
+ // e. Let value be GetOption(options, prop, type, list, undefined).
+ // f. ReturnIfAbrupt(value).
+ // g. If the string given in the Type column of the row is "boolean" and value is not undefined, then
+ // i. Let value be ToString(value).
+ // ii. ReturnIfAbrupt(value).
+ // h. Set opt.[[<key>]] to value.
+ {
+ String numericString;
+ bool usesFallback;
+ bool numeric = intlBooleanOption(state, options, state.vm().propertyNames->numeric, usesFallback);
+ if (state.hadException())
+ return;
+ if (!usesFallback)
+ numericString = ASCIILiteral(numeric ? "true" : "false");
+ opt.add(ASCIILiteral("kn"), numericString);
+ }
+ {
+ String caseFirst = intlStringOption(state, options, state.vm().propertyNames->caseFirst, { "upper", "lower", "false" }, "caseFirst must be either \"upper\", \"lower\", or \"false\"", nullptr);
+ if (state.hadException())
+ return;
+ opt.add(ASCIILiteral("kf"), caseFirst);
+ }
+
+ // 17. Let relevantExtensionKeys be the value of %Collator%.[[relevantExtensionKeys]].
+ // 18. Let r be ResolveLocale(%Collator%.[[availableLocales]], requestedLocales, opt, relevantExtensionKeys, localeData).
+ auto& availableLocales = state.callee()->globalObject()->intlCollatorAvailableLocales();
+ auto result = resolveLocale(availableLocales, requestedLocales, opt, relevantExtensionKeys, WTF_ARRAY_LENGTH(relevantExtensionKeys), localeData);
+
+ // 19. Set collator.[[locale]] to the value of r.[[locale]].
+ m_locale = result.get(ASCIILiteral("locale"));
+
+ // 20. Let k be 0.
+ // 21. Let lenValue be Get(relevantExtensionKeys, "length").
+ // 22. Let len be ToLength(lenValue).
+ // 23. Repeat while k < len:
+ // a. Let Pk be ToString(k).
+ // b. Let key be Get(relevantExtensionKeys, Pk).
+ // c. ReturnIfAbrupt(key).
+ // d. If key is "co", then
+ // i. Let property be "collation".
+ // ii. Let value be the value of r.[[co]].
+ // iii. If value is null, let value be "default".
+ // e. Else use the row of Table 1 that contains the value of key in the Key column:
+ // i. Let property be the name given in the Property column of the row.
+ // ii. Let value be the value of r.[[<key>]].
+ // iii. If the name given in the Type column of the row is "boolean", let value be the result of comparing value with "true".
+ // f. Set collator.[[<property>]] to value.
+ // g. Increase k by 1.
+ const String& collation = result.get(ASCIILiteral("co"));
+ m_collation = collation.isNull() ? ASCIILiteral("default") : collation;
+ m_numeric = (result.get(ASCIILiteral("kn")) == "true");
+
+ // 24. Let s be GetOption(options, "sensitivity", "string", «"base", "accent", "case", "variant"», undefined).
+ String sensitivityString = intlStringOption(state, options, state.vm().propertyNames->sensitivity, { "base", "accent", "case", "variant" }, "sensitivity must be either \"base\", \"accent\", \"case\", or \"variant\"", nullptr);
+ // 25. ReturnIfAbrupt(s).
+ if (state.hadException())
+ return;
+ // 26. If s is undefined, then
+ // a. If u is "sort", then let s be "variant".
+ // b. Else
+ // i. Let dataLocale be the value of r.[[dataLocale]].
+ // ii. Let dataLocaleData be Get(localeData, dataLocale).
+ // iii. Let s be Get(dataLocaleData, "sensitivity").
+ // 10.2.3 "[[searchLocaleData]][locale] must have a sensitivity property with a String value equal to "base", "accent", "case", or "variant" for all locale values."
+ // 27. Set collator.[[sensitivity]] to s.
+ if (sensitivityString == "base")
+ m_sensitivity = Sensitivity::Base;
+ else if (sensitivityString == "accent")
+ m_sensitivity = Sensitivity::Accent;
+ else if (sensitivityString == "case")
+ m_sensitivity = Sensitivity::Case;
+ else
+ m_sensitivity = Sensitivity::Variant;
+
+ // 28. Let ip be GetOption(options, "ignorePunctuation", "boolean", undefined, false).
+ bool usesFallback;
+ bool ignorePunctuation = intlBooleanOption(state, options, state.vm().propertyNames->ignorePunctuation, usesFallback);
+ if (usesFallback)
+ ignorePunctuation = false;
+ // 29. ReturnIfAbrupt(ip).
+ if (state.hadException())
+ return;
+ // 30. Set collator.[[ignorePunctuation]] to ip.
+ m_ignorePunctuation = ignorePunctuation;
+
+ // 31. Set collator.[[boundCompare]] to undefined.
+ // 32. Set collator.[[initializedCollator]] to true.
+ m_initializedCollator = true;
+
+ // 33. Return collator.
+}
+
+void IntlCollator::createCollator(ExecState& state)
+{
+ ASSERT(!m_collator);
+
+ if (!m_initializedCollator) {
+ initializeCollator(state, jsUndefined(), jsUndefined());
+ ASSERT(!state.hadException());
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ UCollator* collator = ucol_open(m_locale.utf8().data(), &status);
+ if (U_FAILURE(status))
+ return;
+
+ UColAttributeValue strength = UCOL_PRIMARY;
+ UColAttributeValue caseLevel = UCOL_OFF;
+ switch (m_sensitivity) {
+ case Sensitivity::Base:
+ break;
+ case Sensitivity::Accent:
+ strength = UCOL_SECONDARY;
+ break;
+ case Sensitivity::Case:
+ caseLevel = UCOL_ON;
+ break;
+ case Sensitivity::Variant:
+ strength = UCOL_TERTIARY;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ ucol_setAttribute(collator, UCOL_STRENGTH, strength, &status);
+ ucol_setAttribute(collator, UCOL_CASE_LEVEL, caseLevel, &status);
+
+ ucol_setAttribute(collator, UCOL_NUMERIC_COLLATION, m_numeric ? UCOL_ON : UCOL_OFF, &status);
+
+ // FIXME: Setting UCOL_ALTERNATE_HANDLING to UCOL_SHIFTED causes punctuation and whitespace to be
+ // ignored. There is currently no way to ignore only punctuation.
+ ucol_setAttribute(collator, UCOL_ALTERNATE_HANDLING, m_ignorePunctuation ? UCOL_SHIFTED : UCOL_DEFAULT, &status);
+
+ // "The method is required to return 0 when comparing Strings that are considered canonically
+ // equivalent by the Unicode standard."
+ ucol_setAttribute(collator, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
+ if (U_FAILURE(status)) {
+ ucol_close(collator);
+ return;
+ }
+
+ m_collator = collator;
+}
+
+JSValue IntlCollator::compareStrings(ExecState& state, StringView x, StringView y)
+{
+ // 10.3.4 CompareStrings abstract operation (ECMA-402 2.0)
+ if (!m_collator) {
+ createCollator(state);
+ if (!m_collator)
+ return state.vm().throwException(&state, createError(&state, ASCIILiteral("Failed to compare strings.")));
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ UCharIterator iteratorX = createIterator(x);
+ UCharIterator iteratorY = createIterator(y);
+ auto result = ucol_strcollIter(m_collator, &iteratorX, &iteratorY, &status);
+ if (U_FAILURE(status))
+ return state.vm().throwException(&state, createError(&state, ASCIILiteral("Failed to compare strings.")));
+ return jsNumber(result);
+}
+
+const char* IntlCollator::usageString(Usage usage)
+{
+ switch (usage) {
+ case Usage::Sort:
+ return "sort";
+ case Usage::Search:
+ return "search";
+ }
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+const char* IntlCollator::sensitivityString(Sensitivity sensitivity)
+{
+ switch (sensitivity) {
+ case Sensitivity::Base:
+ return "base";
+ case Sensitivity::Accent:
+ return "accent";
+ case Sensitivity::Case:
+ return "case";
+ case Sensitivity::Variant:
+ return "variant";
+ }
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+JSObject* IntlCollator::resolvedOptions(ExecState& state)
+{
+ // 10.3.5 Intl.Collator.prototype.resolvedOptions() (ECMA-402 2.0)
+ // The function returns a new object whose properties and attributes are set as if
+ // constructed by an object literal assigning to each of the following properties the
+ // value of the corresponding internal slot of this Collator object (see 10.4): locale,
+ // usage, sensitivity, ignorePunctuation, collation, as well as those properties shown
+ // in Table 1 whose keys are included in the %Collator%[[relevantExtensionKeys]]
+ // internal slot of the standard built-in object that is the initial value of
+ // Intl.Collator.
+
+ if (!m_initializedCollator) {
+ initializeCollator(state, jsUndefined(), jsUndefined());
+ ASSERT(!state.hadException());
+ }
+
+ VM& vm = state.vm();
+ JSObject* options = constructEmptyObject(&state);
+ options->putDirect(vm, vm.propertyNames->locale, jsString(&state, m_locale));
+ options->putDirect(vm, vm.propertyNames->usage, jsNontrivialString(&state, ASCIILiteral(usageString(m_usage))));
+ options->putDirect(vm, vm.propertyNames->sensitivity, jsNontrivialString(&state, ASCIILiteral(sensitivityString(m_sensitivity))));
+ options->putDirect(vm, vm.propertyNames->ignorePunctuation, jsBoolean(m_ignorePunctuation));
+ options->putDirect(vm, vm.propertyNames->collation, jsString(&state, m_collation));
+ options->putDirect(vm, vm.propertyNames->numeric, jsBoolean(m_numeric));
+ return options;
+}
+
+void IntlCollator::setBoundCompare(VM& vm, JSBoundFunction* format)
+{
+ m_boundCompare.set(vm, this, format);
+}
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
diff --git a/Source/JavaScriptCore/runtime/IntlCollator.h b/Source/JavaScriptCore/runtime/IntlCollator.h
new file mode 100644
index 000000000..d39e5d234
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlCollator.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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.
+ */
+
+#ifndef IntlCollator_h
+#define IntlCollator_h
+
+#if ENABLE(INTL)
+
+#include "JSDestructibleObject.h"
+
+struct UCollator;
+
+namespace JSC {
+
+class IntlCollatorConstructor;
+class JSBoundFunction;
+
+class IntlCollator : public JSDestructibleObject {
+public:
+ typedef JSDestructibleObject Base;
+
+ static IntlCollator* create(VM&, IntlCollatorConstructor*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+ void initializeCollator(ExecState&, JSValue locales, JSValue optionsValue);
+ JSValue compareStrings(ExecState&, StringView, StringView);
+ JSObject* resolvedOptions(ExecState&);
+
+ JSBoundFunction* boundCompare() const { return m_boundCompare.get(); }
+ void setBoundCompare(VM&, JSBoundFunction*);
+
+protected:
+ IntlCollator(VM&, Structure*);
+ ~IntlCollator();
+ void finishCreation(VM&);
+ static void destroy(JSCell*);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+private:
+ enum class Usage { Sort, Search };
+ enum class Sensitivity { Base, Accent, Case, Variant };
+
+ void createCollator(ExecState&);
+ static const char* usageString(Usage);
+ static const char* sensitivityString(Sensitivity);
+
+ Usage m_usage;
+ String m_locale;
+ String m_collation;
+ Sensitivity m_sensitivity;
+ WriteBarrier<JSBoundFunction> m_boundCompare;
+ UCollator* m_collator { nullptr };
+ bool m_numeric;
+ bool m_ignorePunctuation;
+ bool m_initializedCollator { false };
+};
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
+
+#endif // IntlCollator_h
diff --git a/Source/JavaScriptCore/runtime/IntlCollatorConstructor.cpp b/Source/JavaScriptCore/runtime/IntlCollatorConstructor.cpp
new file mode 100644
index 000000000..0741485a5
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlCollatorConstructor.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ * Copyright (C) 2015 Sukolsak Sakshuwong (sukolsak@gmail.com)
+ *
+ * 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 "IntlCollatorConstructor.h"
+
+#if ENABLE(INTL)
+
+#include "Error.h"
+#include "IntlCollator.h"
+#include "IntlCollatorPrototype.h"
+#include "IntlObject.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "Lookup.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlCollatorConstructor);
+
+static EncodedJSValue JSC_HOST_CALL IntlCollatorConstructorFuncSupportedLocalesOf(ExecState*);
+
+}
+
+#include "IntlCollatorConstructor.lut.h"
+
+namespace JSC {
+
+const ClassInfo IntlCollatorConstructor::s_info = { "Function", &InternalFunction::s_info, &collatorConstructorTable, CREATE_METHOD_TABLE(IntlCollatorConstructor) };
+
+/* Source for IntlCollatorConstructor.lut.h
+@begin collatorConstructorTable
+ supportedLocalesOf IntlCollatorConstructorFuncSupportedLocalesOf DontEnum|Function 1
+@end
+*/
+
+IntlCollatorConstructor* IntlCollatorConstructor::create(VM& vm, Structure* structure, IntlCollatorPrototype* collatorPrototype, Structure* collatorStructure)
+{
+ IntlCollatorConstructor* constructor = new (NotNull, allocateCell<IntlCollatorConstructor>(vm.heap)) IntlCollatorConstructor(vm, structure);
+ constructor->finishCreation(vm, collatorPrototype, collatorStructure);
+ return constructor;
+}
+
+Structure* IntlCollatorConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlCollatorConstructor::IntlCollatorConstructor(VM& vm, Structure* structure)
+ : InternalFunction(vm, structure)
+{
+}
+
+void IntlCollatorConstructor::finishCreation(VM& vm, IntlCollatorPrototype* collatorPrototype, Structure* collatorStructure)
+{
+ Base::finishCreation(vm, ASCIILiteral("Collator"));
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, collatorPrototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum | DontDelete);
+ m_collatorStructure.set(vm, this, collatorStructure);
+}
+
+static EncodedJSValue JSC_HOST_CALL constructIntlCollator(ExecState* state)
+{
+ // 10.1.2 Intl.Collator ([locales [, options]]) (ECMA-402 2.0)
+ // 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
+ JSValue newTarget = state->newTarget();
+ if (newTarget.isUndefined())
+ newTarget = state->callee();
+
+ // 2. Let collator be OrdinaryCreateFromConstructor(newTarget, %CollatorPrototype%).
+ VM& vm = state->vm();
+ IntlCollator* collator = IntlCollator::create(vm, jsCast<IntlCollatorConstructor*>(state->callee()));
+ if (collator && !jsDynamicCast<IntlCollatorConstructor*>(newTarget)) {
+ JSValue proto = asObject(newTarget)->getDirect(vm, vm.propertyNames->prototype);
+ asObject(collator)->setPrototypeWithCycleCheck(state, proto);
+ }
+
+ // 3. ReturnIfAbrupt(collator).
+ ASSERT(collator);
+
+ // 4. Return InitializeCollator(collator, locales, options).
+ JSValue locales = state->argument(0);
+ JSValue options = state->argument(1);
+ collator->initializeCollator(*state, locales, options);
+ return JSValue::encode(collator);
+}
+
+static EncodedJSValue JSC_HOST_CALL callIntlCollator(ExecState* state)
+{
+ // 10.1.2 Intl.Collator ([locales [, options]]) (ECMA-402 2.0)
+ // 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
+ // NewTarget is always undefined when called as a function.
+
+ // 2. Let collator be OrdinaryCreateFromConstructor(newTarget, %CollatorPrototype%).
+ VM& vm = state->vm();
+ IntlCollator* collator = IntlCollator::create(vm, jsCast<IntlCollatorConstructor*>(state->callee()));
+
+ // 3. ReturnIfAbrupt(collator).
+ ASSERT(collator);
+
+ // 4. Return InitializeCollator(collator, locales, options).
+ JSValue locales = state->argument(0);
+ JSValue options = state->argument(1);
+ collator->initializeCollator(*state, locales, options);
+ return JSValue::encode(collator);
+}
+
+ConstructType IntlCollatorConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructIntlCollator;
+ return ConstructTypeHost;
+}
+
+CallType IntlCollatorConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callIntlCollator;
+ return CallTypeHost;
+}
+
+bool IntlCollatorConstructor::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<InternalFunction>(state, collatorConstructorTable, jsCast<IntlCollatorConstructor*>(object), propertyName, slot);
+}
+
+EncodedJSValue JSC_HOST_CALL IntlCollatorConstructorFuncSupportedLocalesOf(ExecState* state)
+{
+ // 10.2.2 Intl.Collator.supportedLocalesOf(locales [, options]) (ECMA-402 2.0)
+
+ // 1. Let requestedLocales be CanonicalizeLocaleList(locales).
+ Vector<String> requestedLocales = canonicalizeLocaleList(*state, state->argument(0));
+
+ // 2. ReturnIfAbrupt(requestedLocales).
+ if (state->hadException())
+ return JSValue::encode(jsUndefined());
+
+ // 3. Return SupportedLocales(%Collator%.[[availableLocales]], requestedLocales, options).
+ JSGlobalObject* globalObject = state->callee()->globalObject();
+ return JSValue::encode(supportedLocales(*state, globalObject->intlCollatorAvailableLocales(), requestedLocales, state->argument(1)));
+}
+
+void IntlCollatorConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ IntlCollatorConstructor* thisObject = jsCast<IntlCollatorConstructor*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_collatorStructure);
+}
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
diff --git a/Source/JavaScriptCore/runtime/IntlCollatorConstructor.h b/Source/JavaScriptCore/runtime/IntlCollatorConstructor.h
new file mode 100644
index 000000000..33853a061
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlCollatorConstructor.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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.
+ */
+
+#ifndef IntlCollatorConstructor_h
+#define IntlCollatorConstructor_h
+
+#if ENABLE(INTL)
+
+#include "InternalFunction.h"
+
+namespace JSC {
+
+class IntlCollator;
+class IntlCollatorPrototype;
+
+class IntlCollatorConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static IntlCollatorConstructor* create(VM&, Structure*, IntlCollatorPrototype*, Structure*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+ Structure* collatorStructure() const { return m_collatorStructure.get(); }
+
+protected:
+ void finishCreation(VM&, IntlCollatorPrototype*, Structure*);
+
+private:
+ IntlCollatorConstructor(VM&, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ WriteBarrier<Structure> m_collatorStructure;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
+
+#endif // IntlCollatorConstructor_h
diff --git a/Source/JavaScriptCore/runtime/IntlCollatorPrototype.cpp b/Source/JavaScriptCore/runtime/IntlCollatorPrototype.cpp
new file mode 100644
index 000000000..1c2fea9f5
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlCollatorPrototype.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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 "IntlCollatorPrototype.h"
+
+#if ENABLE(INTL)
+
+#include "Error.h"
+#include "IntlCollator.h"
+#include "JSBoundFunction.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSObject.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL IntlCollatorPrototypeGetterCompare(ExecState*);
+static EncodedJSValue JSC_HOST_CALL IntlCollatorPrototypeFuncResolvedOptions(ExecState*);
+
+}
+
+#include "IntlCollatorPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo IntlCollatorPrototype::s_info = { "Object", &IntlCollator::s_info, &collatorPrototypeTable, CREATE_METHOD_TABLE(IntlCollatorPrototype) };
+
+/* Source for IntlCollatorPrototype.lut.h
+@begin collatorPrototypeTable
+ compare IntlCollatorPrototypeGetterCompare DontEnum|Accessor
+ resolvedOptions IntlCollatorPrototypeFuncResolvedOptions DontEnum|Function 0
+@end
+*/
+
+IntlCollatorPrototype* IntlCollatorPrototype::create(VM& vm, JSGlobalObject*, Structure* structure)
+{
+ IntlCollatorPrototype* object = new (NotNull, allocateCell<IntlCollatorPrototype>(vm.heap)) IntlCollatorPrototype(vm, structure);
+ object->finishCreation(vm);
+ return object;
+}
+
+Structure* IntlCollatorPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlCollatorPrototype::IntlCollatorPrototype(VM& vm, Structure* structure)
+ : IntlCollator(vm, structure)
+{
+}
+
+void IntlCollatorPrototype::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+}
+
+bool IntlCollatorPrototype::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<JSObject>(state, collatorPrototypeTable, jsCast<IntlCollatorPrototype*>(object), propertyName, slot);
+}
+
+static EncodedJSValue JSC_HOST_CALL IntlCollatorFuncCompare(ExecState* state)
+{
+ // 10.3.4 Collator Compare Functions (ECMA-402 2.0)
+ // 1. Let collator be the this value.
+ // 2. Assert: Type(collator) is Object and collator has an [[initializedCollator]] internal slot whose value is true.
+ IntlCollator* collator = jsCast<IntlCollator*>(state->thisValue());
+
+ // 3. If x is not provided, let x be undefined.
+ // 4. If y is not provided, let y be undefined.
+ // 5. Let X be ToString(x).
+ JSString* x = state->argument(0).toString(state);
+ // 6. ReturnIfAbrupt(X).
+ if (state->hadException())
+ return JSValue::encode(jsUndefined());
+
+ // 7. Let Y be ToString(y).
+ JSString* y = state->argument(1).toString(state);
+ // 8. ReturnIfAbrupt(Y).
+ if (state->hadException())
+ return JSValue::encode(jsUndefined());
+
+ // 9. Return CompareStrings(collator, X, Y).
+ return JSValue::encode(collator->compareStrings(*state, x->view(state).get(), y->view(state).get()));
+}
+
+EncodedJSValue JSC_HOST_CALL IntlCollatorPrototypeGetterCompare(ExecState* state)
+{
+ // 10.3.3 Intl.Collator.prototype.compare (ECMA-402 2.0)
+ // 1. Let collator be this Collator object.
+ IntlCollator* collator = jsDynamicCast<IntlCollator*>(state->thisValue());
+ if (!collator)
+ return JSValue::encode(throwTypeError(state, ASCIILiteral("Intl.Collator.prototype.compare called on value that's not an object initialized as a Collator")));
+
+ JSBoundFunction* boundCompare = collator->boundCompare();
+ // 2. If collator.[[boundCompare]] is undefined,
+ if (!boundCompare) {
+ VM& vm = state->vm();
+ JSGlobalObject* globalObject = collator->globalObject();
+ // a. Let F be a new built-in function object as defined in 11.3.4.
+ // b. The value of F’s length property is 2.
+ JSFunction* targetObject = JSFunction::create(vm, globalObject, 2, ASCIILiteral("compare"), IntlCollatorFuncCompare, NoIntrinsic);
+ JSArray* boundArgs = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), 0);
+ if (!boundArgs)
+ return JSValue::encode(throwOutOfMemoryError(state));
+
+ // c. Let bc be BoundFunctionCreate(F, «this value»).
+ boundCompare = JSBoundFunction::create(vm, globalObject, targetObject, collator, boundArgs, 2, ASCIILiteral("compare"));
+ // d. Set collator.[[boundCompare]] to bc.
+ collator->setBoundCompare(vm, boundCompare);
+ }
+ // 3. Return collator.[[boundCompare]].
+ return JSValue::encode(boundCompare);
+}
+
+EncodedJSValue JSC_HOST_CALL IntlCollatorPrototypeFuncResolvedOptions(ExecState* state)
+{
+ // 10.3.5 Intl.Collator.prototype.resolvedOptions() (ECMA-402 2.0)
+ IntlCollator* collator = jsDynamicCast<IntlCollator*>(state->thisValue());
+ if (!collator)
+ return JSValue::encode(throwTypeError(state, ASCIILiteral("Intl.Collator.prototype.resolvedOptions called on value that's not an object initialized as a Collator")));
+
+ return JSValue::encode(collator->resolvedOptions(*state));
+}
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
diff --git a/Source/JavaScriptCore/runtime/IntlCollatorPrototype.h b/Source/JavaScriptCore/runtime/IntlCollatorPrototype.h
new file mode 100644
index 000000000..f81642679
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlCollatorPrototype.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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.
+ */
+
+#ifndef IntlCollatorPrototype_h
+#define IntlCollatorPrototype_h
+
+#if ENABLE(INTL)
+
+#include "IntlCollator.h"
+#include "JSObject.h"
+
+namespace JSC {
+
+class IntlCollatorPrototype : public IntlCollator {
+public:
+ typedef IntlCollator Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static IntlCollatorPrototype* create(VM&, JSGlobalObject*, Structure*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+protected:
+ void finishCreation(VM&);
+
+private:
+ IntlCollatorPrototype(VM&, Structure*);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+};
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
+
+#endif // IntlCollatorPrototype_h
diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp
new file mode 100644
index 000000000..aa53c8533
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp
@@ -0,0 +1,917 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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 "IntlDateTimeFormat.h"
+
+#if ENABLE(INTL)
+
+#include "DateInstance.h"
+#include "Error.h"
+#include "IntlDateTimeFormatConstructor.h"
+#include "IntlObject.h"
+#include "JSBoundFunction.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "ObjectConstructor.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+#include <unicode/ucal.h>
+#include <unicode/udat.h>
+#include <unicode/udatpg.h>
+#include <unicode/uenum.h>
+
+namespace JSC {
+
+const ClassInfo IntlDateTimeFormat::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(IntlDateTimeFormat) };
+
+static const char* const relevantExtensionKeys[2] = { "ca", "nu" };
+static const size_t indexOfExtensionKeyCa = 0;
+static const size_t indexOfExtensionKeyNu = 1;
+
+IntlDateTimeFormat* IntlDateTimeFormat::create(VM& vm, IntlDateTimeFormatConstructor* constructor)
+{
+ IntlDateTimeFormat* format = new (NotNull, allocateCell<IntlDateTimeFormat>(vm.heap)) IntlDateTimeFormat(vm, constructor->dateTimeFormatStructure());
+ format->finishCreation(vm);
+ return format;
+}
+
+Structure* IntlDateTimeFormat::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlDateTimeFormat::IntlDateTimeFormat(VM& vm, Structure* structure)
+ : JSDestructibleObject(vm, structure)
+{
+}
+
+IntlDateTimeFormat::~IntlDateTimeFormat()
+{
+ if (m_dateFormat)
+ udat_close(m_dateFormat);
+}
+
+void IntlDateTimeFormat::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+}
+
+void IntlDateTimeFormat::destroy(JSCell* cell)
+{
+ static_cast<IntlDateTimeFormat*>(cell)->IntlDateTimeFormat::~IntlDateTimeFormat();
+}
+
+void IntlDateTimeFormat::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ IntlDateTimeFormat* thisObject = jsCast<IntlDateTimeFormat*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_boundFormat);
+}
+
+void IntlDateTimeFormat::setBoundFormat(VM& vm, JSBoundFunction* format)
+{
+ m_boundFormat.set(vm, this, format);
+}
+
+static String defaultTimeZone()
+{
+ // 6.4.3 DefaultTimeZone () (ECMA-402 2.0)
+ // The DefaultTimeZone abstract operation returns a String value representing the valid (6.4.1) and canonicalized (6.4.2) time zone name for the host environment’s current time zone.
+
+ UErrorCode status = U_ZERO_ERROR;
+ Vector<UChar, 32> buffer(32);
+ auto bufferLength = ucal_getDefaultTimeZone(buffer.data(), buffer.capacity(), &status);
+ if (status == U_BUFFER_OVERFLOW_ERROR) {
+ status = U_ZERO_ERROR;
+ buffer = Vector<UChar, 32>(bufferLength);
+ ucal_getDefaultTimeZone(buffer.data(), bufferLength, &status);
+ }
+ if (U_SUCCESS(status)) {
+ status = U_ZERO_ERROR;
+ UBool isSystemID = false;
+ Vector<UChar, 32> canonicalBuffer(32);
+ auto canonicalLength = ucal_getCanonicalTimeZoneID(buffer.data(), bufferLength, canonicalBuffer.data(), canonicalBuffer.capacity(), &isSystemID, &status);
+ if (status == U_BUFFER_OVERFLOW_ERROR) {
+ status = U_ZERO_ERROR;
+ canonicalBuffer = Vector<UChar, 32>(canonicalLength);
+ ucal_getCanonicalTimeZoneID(buffer.data(), bufferLength, canonicalBuffer.data(), canonicalLength, &isSystemID, &status);
+ }
+ if (U_SUCCESS(status))
+ return String(canonicalBuffer.data(), canonicalLength);
+ }
+
+ return ASCIILiteral("UTC");
+}
+
+static String canonicalizeTimeZoneName(const String& timeZoneName)
+{
+ // 6.4.1 IsValidTimeZoneName (timeZone)
+ // The abstract operation returns true if timeZone, converted to upper case as described in 6.1, is equal to one of the Zone or Link names of the IANA Time Zone Database, converted to upper case as described in 6.1. It returns false otherwise.
+ UErrorCode status = U_ZERO_ERROR;
+ UEnumeration* timeZones = ucal_openTimeZones(&status);
+ ASSERT(U_SUCCESS(status));
+
+ String canonical;
+ do {
+ status = U_ZERO_ERROR;
+ int32_t ianaTimeZoneLength;
+ // Time zone names are respresented as UChar[] in all related ICU apis.
+ const UChar* ianaTimeZone = uenum_unext(timeZones, &ianaTimeZoneLength, &status);
+ ASSERT(U_SUCCESS(status));
+
+ // End of enumeration.
+ if (!ianaTimeZone)
+ break;
+
+ StringView ianaTimeZoneView(ianaTimeZone, ianaTimeZoneLength);
+ if (!equalIgnoringASCIICase(timeZoneName, ianaTimeZoneView))
+ continue;
+
+ // Found a match, now canonicalize.
+ // 6.4.2 CanonicalizeTimeZoneName (timeZone) (ECMA-402 2.0)
+ // 1. Let ianaTimeZone be the Zone or Link name of the IANA Time Zone Database such that timeZone, converted to upper case as described in 6.1, is equal to ianaTimeZone, converted to upper case as described in 6.1.
+ // 2. If ianaTimeZone is a Link name, then let ianaTimeZone be the corresponding Zone name as specified in the “backward” file of the IANA Time Zone Database.
+
+ Vector<UChar, 32> buffer(ianaTimeZoneLength);
+ UBool isSystemID = false;
+ status = U_ZERO_ERROR;
+ auto canonicalLength = ucal_getCanonicalTimeZoneID(ianaTimeZone, ianaTimeZoneLength, buffer.data(), ianaTimeZoneLength, &isSystemID, &status);
+ if (status == U_BUFFER_OVERFLOW_ERROR) {
+ buffer = Vector<UChar, 32>(canonicalLength);
+ isSystemID = false;
+ status = U_ZERO_ERROR;
+ ucal_getCanonicalTimeZoneID(ianaTimeZone, ianaTimeZoneLength, buffer.data(), canonicalLength, &isSystemID, &status);
+ }
+ ASSERT(U_SUCCESS(status));
+ canonical = String(buffer.data(), canonicalLength);
+ } while (canonical.isNull());
+ uenum_close(timeZones);
+
+ // 3. If ianaTimeZone is "Etc/UTC" or "Etc/GMT", then return "UTC".
+ if (canonical == "Etc/UTC" || canonical == "Etc/GMT")
+ canonical = ASCIILiteral("UTC");
+
+ // 4. Return ianaTimeZone.
+ return canonical;
+}
+
+static Vector<String> localeData(const String& locale, size_t keyIndex)
+{
+ Vector<String> keyLocaleData;
+ switch (keyIndex) {
+ case indexOfExtensionKeyCa: {
+ UErrorCode status = U_ZERO_ERROR;
+ UEnumeration* calendars = ucal_getKeywordValuesForLocale("calendar", locale.utf8().data(), false, &status);
+ ASSERT(U_SUCCESS(status));
+
+ status = U_ZERO_ERROR;
+ int32_t nameLength;
+ while (const char* availableName = uenum_next(calendars, &nameLength, &status)) {
+ ASSERT(U_SUCCESS(status));
+ status = U_ZERO_ERROR;
+ String calendar = String(availableName, nameLength);
+ keyLocaleData.append(calendar);
+ // Ensure aliases used in language tag are allowed.
+ if (calendar == "gregorian")
+ keyLocaleData.append(ASCIILiteral("gregory"));
+ else if (calendar == "islamic-civil")
+ keyLocaleData.append(ASCIILiteral("islamicc"));
+ else if (calendar == "ethiopic-amete-alem")
+ keyLocaleData.append(ASCIILiteral("ethioaa"));
+ }
+ uenum_close(calendars);
+ break;
+ }
+ case indexOfExtensionKeyNu:
+ keyLocaleData = numberingSystemsForLocale(locale);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ return keyLocaleData;
+}
+
+static JSObject* toDateTimeOptionsAnyDate(ExecState& exec, JSValue originalOptions)
+{
+ // 12.1.1 ToDateTimeOptions abstract operation (ECMA-402 2.0)
+ VM& vm = exec.vm();
+
+ // 1. If options is undefined, then let options be null, else let options be ToObject(options).
+ // 2. ReturnIfAbrupt(options).
+ // 3. Let options be ObjectCreate(options).
+ JSObject* options;
+ if (originalOptions.isUndefined())
+ options = constructEmptyObject(&exec, exec.lexicalGlobalObject()->nullPrototypeObjectStructure());
+ else {
+ JSObject* originalToObject = originalOptions.toObject(&exec);
+ if (exec.hadException())
+ return nullptr;
+ options = constructEmptyObject(&exec, originalToObject);
+ }
+
+ // 4. Let needDefaults be true.
+ bool needDefaults = true;
+
+ // 5. If required is "date" or "any",
+ // Always "any".
+
+ // a. For each of the property names "weekday", "year", "month", "day":
+ // i. Let prop be the property name.
+ // ii. Let value be Get(options, prop).
+ // iii. ReturnIfAbrupt(value).
+ // iv. If value is not undefined, then let needDefaults be false.
+ JSValue weekday = options->get(&exec, vm.propertyNames->weekday);
+ if (exec.hadException())
+ return nullptr;
+ if (!weekday.isUndefined())
+ needDefaults = false;
+
+ JSValue year = options->get(&exec, vm.propertyNames->year);
+ if (exec.hadException())
+ return nullptr;
+ if (!year.isUndefined())
+ needDefaults = false;
+
+ JSValue month = options->get(&exec, vm.propertyNames->month);
+ if (exec.hadException())
+ return nullptr;
+ if (!month.isUndefined())
+ needDefaults = false;
+
+ JSValue day = options->get(&exec, vm.propertyNames->day);
+ if (exec.hadException())
+ return nullptr;
+ if (!day.isUndefined())
+ needDefaults = false;
+
+ // 6. If required is "time" or "any",
+ // Always "any".
+
+ // a. For each of the property names "hour", "minute", "second":
+ // i. Let prop be the property name.
+ // ii. Let value be Get(options, prop).
+ // iii. ReturnIfAbrupt(value).
+ // iv. If value is not undefined, then let needDefaults be false.
+ JSValue hour = options->get(&exec, vm.propertyNames->hour);
+ if (exec.hadException())
+ return nullptr;
+ if (!hour.isUndefined())
+ needDefaults = false;
+
+ JSValue minute = options->get(&exec, vm.propertyNames->minute);
+ if (exec.hadException())
+ return nullptr;
+ if (!minute.isUndefined())
+ needDefaults = false;
+
+ JSValue second = options->get(&exec, vm.propertyNames->second);
+ if (exec.hadException())
+ return nullptr;
+ if (!second.isUndefined())
+ needDefaults = false;
+
+ // 7. If needDefaults is true and defaults is either "date" or "all", then
+ // Defaults is always "date".
+ if (needDefaults) {
+ // a. For each of the property names "year", "month", "day":
+ // i. Let status be CreateDatePropertyOrThrow(options, prop, "numeric").
+ // ii. ReturnIfAbrupt(status).
+ options->putDirect(vm, vm.propertyNames->year, jsNontrivialString(&exec, ASCIILiteral("numeric")));
+ if (exec.hadException())
+ return nullptr;
+
+ options->putDirect(vm, vm.propertyNames->month, jsNontrivialString(&exec, ASCIILiteral("numeric")));
+ if (exec.hadException())
+ return nullptr;
+
+ options->putDirect(vm, vm.propertyNames->day, jsNontrivialString(&exec, ASCIILiteral("numeric")));
+ if (exec.hadException())
+ return nullptr;
+ }
+
+ // 8. If needDefaults is true and defaults is either "time" or "all", then
+ // Defaults is always "date". Ignore this branch.
+
+ // 9. Return options.
+ return options;
+}
+
+void IntlDateTimeFormat::setFormatsFromPattern(const StringView& pattern)
+{
+ // Get all symbols from the pattern, and set format fields accordingly.
+ // http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
+ unsigned length = pattern.length();
+ for (unsigned i = 0; i < length; ++i) {
+ UChar currentCharacter = pattern[i];
+ if (!isASCIIAlpha(currentCharacter))
+ continue;
+
+ unsigned count = 1;
+ while (i + 1 < length && pattern[i + 1] == currentCharacter) {
+ ++count;
+ ++i;
+ }
+
+ if (currentCharacter == 'h' || currentCharacter == 'K')
+ m_hour12 = true;
+ else if (currentCharacter == 'H' || currentCharacter == 'k')
+ m_hour12 = false;
+
+ switch (currentCharacter) {
+ case 'G':
+ if (count <= 3)
+ m_era = Era::Short;
+ else if (count == 4)
+ m_era = Era::Long;
+ else if (count == 5)
+ m_era = Era::Narrow;
+ break;
+ case 'y':
+ if (count == 1)
+ m_year = Year::Numeric;
+ else if (count == 2)
+ m_year = Year::TwoDigit;
+ break;
+ case 'M':
+ case 'L':
+ if (count == 1)
+ m_month = Month::Numeric;
+ else if (count == 2)
+ m_month = Month::TwoDigit;
+ else if (count == 3)
+ m_month = Month::Short;
+ else if (count == 4)
+ m_month = Month::Long;
+ else if (count == 5)
+ m_month = Month::Narrow;
+ break;
+ case 'E':
+ case 'e':
+ case 'c':
+ if (count <= 3)
+ m_weekday = Weekday::Short;
+ else if (count == 4)
+ m_weekday = Weekday::Long;
+ else if (count == 5)
+ m_weekday = Weekday::Narrow;
+ break;
+ case 'd':
+ if (count == 1)
+ m_day = Day::Numeric;
+ else if (count == 2)
+ m_day = Day::TwoDigit;
+ break;
+ case 'h':
+ case 'H':
+ case 'k':
+ case 'K':
+ if (count == 1)
+ m_hour = Hour::Numeric;
+ else if (count == 2)
+ m_hour = Hour::TwoDigit;
+ break;
+ case 'm':
+ if (count == 1)
+ m_minute = Minute::Numeric;
+ else if (count == 2)
+ m_minute = Minute::TwoDigit;
+ break;
+ case 's':
+ if (count == 1)
+ m_second = Second::Numeric;
+ else if (count == 2)
+ m_second = Second::TwoDigit;
+ break;
+ case 'z':
+ case 'v':
+ case 'V':
+ if (count == 1)
+ m_timeZoneName = TimeZoneName::Short;
+ else if (count == 4)
+ m_timeZoneName = TimeZoneName::Long;
+ break;
+ }
+ }
+}
+
+void IntlDateTimeFormat::initializeDateTimeFormat(ExecState& exec, JSValue locales, JSValue originalOptions)
+{
+ // 12.1.1 InitializeDateTimeFormat (dateTimeFormat, locales, options) (ECMA-402 2.0)
+ // 1. If dateTimeFormat.[[initializedIntlObject]] is true, throw a TypeError exception.
+ // 2. Set dateTimeFormat.[[initializedIntlObject]] to true.
+
+ // 3. Let requestedLocales be CanonicalizeLocaleList(locales).
+ Vector<String> requestedLocales = canonicalizeLocaleList(exec, locales);
+ // 4. ReturnIfAbrupt(requestedLocales),
+ if (exec.hadException())
+ return;
+
+ // 5. Let options be ToDateTimeOptions(options, "any", "date").
+ JSObject* options = toDateTimeOptionsAnyDate(exec, originalOptions);
+ // 6. ReturnIfAbrupt(options).
+ if (exec.hadException())
+ return;
+
+ // 7. Let opt be a new Record.
+ HashMap<String, String> localeOpt;
+
+ // 8. Let matcher be GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit").
+ VM& vm = exec.vm();
+ String localeMatcher = intlStringOption(exec, options, vm.propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit");
+ // 9. ReturnIfAbrupt(matcher).
+ if (exec.hadException())
+ return;
+ // 10. Set opt.[[localeMatcher]] to matcher.
+ localeOpt.set(vm.propertyNames->localeMatcher.string(), localeMatcher);
+
+ // 11. Let localeData be the value of %DateTimeFormat%.[[localeData]].
+ // 12. Let r be ResolveLocale( %DateTimeFormat%.[[availableLocales]], requestedLocales, opt, %DateTimeFormat%.[[relevantExtensionKeys]], localeData).
+ const HashSet<String> availableLocales = exec.lexicalGlobalObject()->intlDateTimeFormatAvailableLocales();
+ HashMap<String, String> resolved = resolveLocale(availableLocales, requestedLocales, localeOpt, relevantExtensionKeys, WTF_ARRAY_LENGTH(relevantExtensionKeys), localeData);
+
+ // 13. Set dateTimeFormat.[[locale]] to the value of r.[[locale]].
+ m_locale = resolved.get(vm.propertyNames->locale.string());
+ // 14. Set dateTimeFormat.[[calendar]] to the value of r.[[ca]].
+ m_calendar = resolved.get(ASCIILiteral("ca"));
+ // Switch to preferred aliases.
+ if (m_calendar == "gregory")
+ m_calendar = ASCIILiteral("gregorian");
+ else if (m_calendar == "islamicc")
+ m_calendar = ASCIILiteral("islamic-civil");
+ else if (m_calendar == "ethioaa")
+ m_calendar = ASCIILiteral("ethiopic-amete-alem");
+ // 15. Set dateTimeFormat.[[numberingSystem]] to the value of r.[[nu]].
+ m_numberingSystem = resolved.get(ASCIILiteral("nu"));
+ // 16. Let dataLocale be the value of r.[[dataLocale]].
+ String dataLocale = resolved.get(ASCIILiteral("dataLocale"));
+
+ // 17. Let tz be Get(options, "timeZone").
+ JSValue tzValue = options->get(&exec, vm.propertyNames->timeZone);
+ // 18. ReturnIfAbrupt(tz).
+ if (exec.hadException())
+ return;
+
+ // 19. If tz is not undefined, then
+ String tz;
+ if (!tzValue.isUndefined()) {
+ // a. Let tz be ToString(tz).
+ String originalTz = tzValue.toWTFString(&exec);
+ // b. ReturnIfAbrupt(tz).
+ if (exec.hadException())
+ return;
+ // c. If the result of IsValidTimeZoneName(tz) is false, then i. Throw a RangeError exception.
+ // d. Let tz be CanonicalizeTimeZoneName(tz).
+ tz = canonicalizeTimeZoneName(originalTz);
+ if (tz.isNull()) {
+ throwRangeError(&exec, String::format("invalid time zone: %s", originalTz.utf8().data()));
+ return;
+ }
+ } else {
+ // 20. Else,
+ // a. Let tz be DefaultTimeZone().
+ tz = defaultTimeZone();
+ }
+
+ // 21. Set dateTimeFormat.[[timeZone]] to tz.
+ m_timeZone = tz;
+
+ // 22. Let opt be a new Record.
+ // Rather than building a record, build the skeleton pattern.
+ StringBuilder skeletonBuilder;
+
+ // 23. For each row of Table 3, except the header row, do:
+ // a. Let prop be the name given in the Property column of the row.
+ // b. Let value be GetOption(options, prop, "string", «the strings given in the Values column of the row», undefined).
+ // c. ReturnIfAbrupt(value).
+ // d. Set opt.[[<prop>]] to value.
+ auto narrowShortLong = { "narrow", "short", "long" };
+ auto twoDigitNumeric = { "2-digit", "numeric" };
+ auto twoDigitNumericNarrowShortLong = { "2-digit", "numeric", "narrow", "short", "long" };
+ auto shortLong = { "short", "long" };
+
+ String weekday = intlStringOption(exec, options, vm.propertyNames->weekday, narrowShortLong, "weekday must be \"narrow\", \"short\", or \"long\"", nullptr);
+ if (exec.hadException())
+ return;
+ if (!weekday.isNull()) {
+ if (weekday == "narrow")
+ skeletonBuilder.appendLiteral("EEEEE");
+ else if (weekday == "short")
+ skeletonBuilder.appendLiteral("EEE");
+ else if (weekday == "long")
+ skeletonBuilder.appendLiteral("EEEE");
+ }
+
+ String era = intlStringOption(exec, options, vm.propertyNames->era, narrowShortLong, "era must be \"narrow\", \"short\", or \"long\"", nullptr);
+ if (exec.hadException())
+ return;
+ if (!era.isNull()) {
+ if (era == "narrow")
+ skeletonBuilder.appendLiteral("GGGGG");
+ else if (era == "short")
+ skeletonBuilder.appendLiteral("GGG");
+ else if (era == "long")
+ skeletonBuilder.appendLiteral("GGGG");
+ }
+
+ String year = intlStringOption(exec, options, vm.propertyNames->year, twoDigitNumeric, "year must be \"2-digit\" or \"numeric\"", nullptr);
+ if (exec.hadException())
+ return;
+ if (!year.isNull()) {
+ if (year == "2-digit")
+ skeletonBuilder.appendLiteral("yy");
+ else if (year == "numeric")
+ skeletonBuilder.append('y');
+ }
+
+ String month = intlStringOption(exec, options, vm.propertyNames->month, twoDigitNumericNarrowShortLong, "month must be \"2-digit\", \"numeric\", \"narrow\", \"short\", or \"long\"", nullptr);
+ if (exec.hadException())
+ return;
+ if (!month.isNull()) {
+ if (month == "2-digit")
+ skeletonBuilder.appendLiteral("MM");
+ else if (month == "numeric")
+ skeletonBuilder.append('M');
+ else if (month == "narrow")
+ skeletonBuilder.appendLiteral("MMMMM");
+ else if (month == "short")
+ skeletonBuilder.appendLiteral("MMM");
+ else if (month == "long")
+ skeletonBuilder.appendLiteral("MMMM");
+ }
+
+ String day = intlStringOption(exec, options, vm.propertyNames->day, twoDigitNumeric, "day must be \"2-digit\" or \"numeric\"", nullptr);
+ if (exec.hadException())
+ return;
+ if (!day.isNull()) {
+ if (day == "2-digit")
+ skeletonBuilder.appendLiteral("dd");
+ else if (day == "numeric")
+ skeletonBuilder.append('d');
+ }
+
+ String hour = intlStringOption(exec, options, vm.propertyNames->hour, twoDigitNumeric, "hour must be \"2-digit\" or \"numeric\"", nullptr);
+ if (exec.hadException())
+ return;
+
+ // We need hour12 to make the hour skeleton pattern decision, so do this early.
+ // 32. Let hr12 be GetOption(options, "hour12", "boolean", undefined, undefined).
+ bool isHour12Undefined = true;
+ bool hr12 = intlBooleanOption(exec, options, vm.propertyNames->hour12, isHour12Undefined);
+ // 33. ReturnIfAbrupt(hr12).
+ if (exec.hadException())
+ return;
+
+ if (!hour.isNull()) {
+ if (isHour12Undefined) {
+ if (hour == "2-digit")
+ skeletonBuilder.appendLiteral("jj");
+ else if (hour == "numeric")
+ skeletonBuilder.append('j');
+ } else if (hr12) {
+ if (hour == "2-digit")
+ skeletonBuilder.appendLiteral("hh");
+ else if (hour == "numeric")
+ skeletonBuilder.append('h');
+ } else {
+ if (hour == "2-digit")
+ skeletonBuilder.appendLiteral("HH");
+ else if (hour == "numeric")
+ skeletonBuilder.append('H');
+ }
+ }
+
+ String minute = intlStringOption(exec, options, vm.propertyNames->minute, twoDigitNumeric, "minute must be \"2-digit\" or \"numeric\"", nullptr);
+ if (exec.hadException())
+ return;
+ if (!minute.isNull()) {
+ if (minute == "2-digit")
+ skeletonBuilder.appendLiteral("mm");
+ else if (minute == "numeric")
+ skeletonBuilder.append('m');
+ }
+
+ String second = intlStringOption(exec, options, vm.propertyNames->second, twoDigitNumeric, "second must be \"2-digit\" or \"numeric\"", nullptr);
+ if (exec.hadException())
+ return;
+ if (!second.isNull()) {
+ if (second == "2-digit")
+ skeletonBuilder.appendLiteral("ss");
+ else if (second == "numeric")
+ skeletonBuilder.append('s');
+ }
+
+ String timeZoneName = intlStringOption(exec, options, vm.propertyNames->timeZoneName, shortLong, "timeZoneName must be \"short\" or \"long\"", nullptr);
+ if (exec.hadException())
+ return;
+ if (!timeZoneName.isNull()) {
+ if (timeZoneName == "short")
+ skeletonBuilder.append('z');
+ else if (timeZoneName == "long")
+ skeletonBuilder.appendLiteral("zzzz");
+ }
+
+ // 24. Let dataLocaleData be Get(localeData, dataLocale).
+ // 25. Let formats be Get(dataLocaleData, "formats").
+ // 26. Let matcher be GetOption(options, "formatMatcher", "string", «"basic", "best fit"», "best fit").
+ intlStringOption(exec, options, vm.propertyNames->formatMatcher, { "basic", "best fit" }, "formatMatcher must be either \"basic\" or \"best fit\"", "best fit");
+ // 27. ReturnIfAbrupt(matcher).
+ if (exec.hadException())
+ return;
+
+ // Always use ICU date format generator, rather than our own pattern list and matcher.
+ // Covers steps 28-36.
+ UErrorCode status = U_ZERO_ERROR;
+ UDateTimePatternGenerator* generator = udatpg_open(dataLocale.utf8().data(), &status);
+ if (U_FAILURE(status)) {
+ throwTypeError(&exec, ASCIILiteral("failed to initialize DateTimeFormat"));
+ return;
+ }
+
+ String skeleton = skeletonBuilder.toString();
+ StringView skeletonView(skeleton);
+ Vector<UChar, 32> patternBuffer(32);
+ status = U_ZERO_ERROR;
+ auto patternLength = udatpg_getBestPattern(generator, skeletonView.upconvertedCharacters(), skeletonView.length(), patternBuffer.data(), patternBuffer.capacity(), &status);
+ if (status == U_BUFFER_OVERFLOW_ERROR) {
+ status = U_ZERO_ERROR;
+ patternBuffer = Vector<UChar, 32>(patternLength);
+ udatpg_getBestPattern(generator, skeletonView.upconvertedCharacters(), skeletonView.length(), patternBuffer.data(), patternLength, &status);
+ }
+ udatpg_close(generator);
+ if (U_FAILURE(status)) {
+ throwTypeError(&exec, ASCIILiteral("failed to initialize DateTimeFormat"));
+ return;
+ }
+
+ StringView pattern(patternBuffer.data(), patternLength);
+ setFormatsFromPattern(pattern);
+
+ status = U_ZERO_ERROR;
+ StringView timeZoneView(m_timeZone);
+ m_dateFormat = udat_open(UDAT_IGNORE, UDAT_IGNORE, m_locale.utf8().data(), timeZoneView.upconvertedCharacters(), timeZoneView.length(), pattern.upconvertedCharacters(), pattern.length(), &status);
+ if (U_FAILURE(status)) {
+ throwTypeError(&exec, ASCIILiteral("failed to initialize DateTimeFormat"));
+ return;
+ }
+
+ // 37. Set dateTimeFormat.[[boundFormat]] to undefined.
+ // Already undefined.
+
+ // 38. Set dateTimeFormat.[[initializedDateTimeFormat]] to true.
+ m_initializedDateTimeFormat = true;
+
+ // 39. Return dateTimeFormat.
+ return;
+}
+
+const char* IntlDateTimeFormat::weekdayString(Weekday weekday)
+{
+ switch (weekday) {
+ case Weekday::Narrow:
+ return ASCIILiteral("narrow");
+ case Weekday::Short:
+ return ASCIILiteral("short");
+ case Weekday::Long:
+ return ASCIILiteral("long");
+ case Weekday::None:
+ ASSERT_NOT_REACHED();
+ return nullptr;
+ }
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+const char* IntlDateTimeFormat::eraString(Era era)
+{
+ switch (era) {
+ case Era::Narrow:
+ return "narrow";
+ case Era::Short:
+ return "short";
+ case Era::Long:
+ return "long";
+ case Era::None:
+ ASSERT_NOT_REACHED();
+ return nullptr;
+ }
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+const char* IntlDateTimeFormat::yearString(Year year)
+{
+ switch (year) {
+ case Year::TwoDigit:
+ return "2-digit";
+ case Year::Numeric:
+ return "numeric";
+ case Year::None:
+ ASSERT_NOT_REACHED();
+ return nullptr;
+ }
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+const char* IntlDateTimeFormat::monthString(Month month)
+{
+ switch (month) {
+ case Month::TwoDigit:
+ return "2-digit";
+ case Month::Numeric:
+ return "numeric";
+ case Month::Narrow:
+ return "narrow";
+ case Month::Short:
+ return "short";
+ case Month::Long:
+ return "long";
+ case Month::None:
+ ASSERT_NOT_REACHED();
+ return nullptr;
+ }
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+const char* IntlDateTimeFormat::dayString(Day day)
+{
+ switch (day) {
+ case Day::TwoDigit:
+ return "2-digit";
+ case Day::Numeric:
+ return "numeric";
+ case Day::None:
+ ASSERT_NOT_REACHED();
+ return nullptr;
+ }
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+const char* IntlDateTimeFormat::hourString(Hour hour)
+{
+ switch (hour) {
+ case Hour::TwoDigit:
+ return "2-digit";
+ case Hour::Numeric:
+ return "numeric";
+ case Hour::None:
+ ASSERT_NOT_REACHED();
+ return nullptr;
+ }
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+const char* IntlDateTimeFormat::minuteString(Minute minute)
+{
+ switch (minute) {
+ case Minute::TwoDigit:
+ return "2-digit";
+ case Minute::Numeric:
+ return "numeric";
+ case Minute::None:
+ ASSERT_NOT_REACHED();
+ return nullptr;
+ }
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+const char* IntlDateTimeFormat::secondString(Second second)
+{
+ switch (second) {
+ case Second::TwoDigit:
+ return "2-digit";
+ case Second::Numeric:
+ return "numeric";
+ case Second::None:
+ ASSERT_NOT_REACHED();
+ return nullptr;
+ }
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+const char* IntlDateTimeFormat::timeZoneNameString(TimeZoneName timeZoneName)
+{
+ switch (timeZoneName) {
+ case TimeZoneName::Short:
+ return "short";
+ case TimeZoneName::Long:
+ return "long";
+ case TimeZoneName::None:
+ ASSERT_NOT_REACHED();
+ return nullptr;
+ }
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+JSObject* IntlDateTimeFormat::resolvedOptions(ExecState& exec)
+{
+ // 12.3.5 Intl.DateTimeFormat.prototype.resolvedOptions() (ECMA-402 2.0)
+ // The function returns a new object whose properties and attributes are set as if constructed by an object literal assigning to each of the following properties the value of the corresponding internal slot of this DateTimeFormat object (see 12.4): locale, calendar, numberingSystem, timeZone, hour12, weekday, era, year, month, day, hour, minute, second, and timeZoneName. Properties whose corresponding internal slots are not present are not assigned.
+ // Note: In this version of the ECMAScript 2015 Internationalization API, the timeZone property will be the name of the default time zone if no timeZone property was provided in the options object provided to the Intl.DateTimeFormat constructor. The previous version left the timeZone property undefined in this case.
+ if (!m_initializedDateTimeFormat) {
+ initializeDateTimeFormat(exec, jsUndefined(), jsUndefined());
+ ASSERT(!exec.hadException());
+ }
+
+ VM& vm = exec.vm();
+ JSObject* options = constructEmptyObject(&exec);
+ options->putDirect(vm, vm.propertyNames->locale, jsNontrivialString(&exec, m_locale));
+ options->putDirect(vm, vm.propertyNames->calendar, jsNontrivialString(&exec, m_calendar));
+ options->putDirect(vm, vm.propertyNames->numberingSystem, jsNontrivialString(&exec, m_numberingSystem));
+ options->putDirect(vm, vm.propertyNames->timeZone, jsNontrivialString(&exec, m_timeZone));
+
+ if (m_weekday != Weekday::None)
+ options->putDirect(vm, vm.propertyNames->weekday, jsNontrivialString(&exec, ASCIILiteral(weekdayString(m_weekday))));
+
+ if (m_era != Era::None)
+ options->putDirect(vm, vm.propertyNames->era, jsNontrivialString(&exec, ASCIILiteral(eraString(m_era))));
+
+ if (m_year != Year::None)
+ options->putDirect(vm, vm.propertyNames->year, jsNontrivialString(&exec, ASCIILiteral(yearString(m_year))));
+
+ if (m_month != Month::None)
+ options->putDirect(vm, vm.propertyNames->month, jsNontrivialString(&exec, ASCIILiteral(monthString(m_month))));
+
+ if (m_day != Day::None)
+ options->putDirect(vm, vm.propertyNames->day, jsNontrivialString(&exec, ASCIILiteral(dayString(m_day))));
+
+ if (m_hour != Hour::None) {
+ options->putDirect(vm, vm.propertyNames->hour, jsNontrivialString(&exec, ASCIILiteral(hourString(m_hour))));
+ options->putDirect(vm, vm.propertyNames->hour12, jsBoolean(m_hour12));
+ }
+
+ if (m_minute != Minute::None)
+ options->putDirect(vm, vm.propertyNames->minute, jsNontrivialString(&exec, ASCIILiteral(minuteString(m_minute))));
+
+ if (m_second != Second::None)
+ options->putDirect(vm, vm.propertyNames->second, jsNontrivialString(&exec, ASCIILiteral(secondString(m_second))));
+
+ if (m_timeZoneName != TimeZoneName::None)
+ options->putDirect(vm, vm.propertyNames->timeZoneName, jsNontrivialString(&exec, ASCIILiteral(timeZoneNameString(m_timeZoneName))));
+
+ return options;
+}
+
+JSValue IntlDateTimeFormat::format(ExecState& exec, double value)
+{
+ // 12.3.4 FormatDateTime abstract operation (ECMA-402 2.0)
+ if (!m_initializedDateTimeFormat) {
+ initializeDateTimeFormat(exec, jsUndefined(), jsUndefined());
+ ASSERT(!exec.hadException());
+ }
+
+ // 1. If x is not a finite Number, then throw a RangeError exception.
+ if (!std::isfinite(value))
+ return throwRangeError(&exec, ASCIILiteral("date value is not finite in DateTimeFormat format()"));
+
+ // Delegate remaining steps to ICU.
+ UErrorCode status = U_ZERO_ERROR;
+ Vector<UChar, 32> result(32);
+ auto resultLength = udat_format(m_dateFormat, value, result.data(), result.capacity(), nullptr, &status);
+ if (status == U_BUFFER_OVERFLOW_ERROR) {
+ status = U_ZERO_ERROR;
+ result = Vector<UChar, 32>(resultLength);
+ udat_format(m_dateFormat, value, result.data(), resultLength, nullptr, &status);
+ }
+ if (U_FAILURE(status))
+ return throwTypeError(&exec, ASCIILiteral("failed to format date value"));
+
+ return jsString(&exec, String(result.data(), resultLength));
+}
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h
new file mode 100644
index 000000000..7dc57d075
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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.
+ */
+
+#ifndef IntlDateTimeFormat_h
+#define IntlDateTimeFormat_h
+
+#if ENABLE(INTL)
+
+#include "JSDestructibleObject.h"
+#include <unicode/udat.h>
+
+namespace JSC {
+
+class IntlDateTimeFormatConstructor;
+class JSBoundFunction;
+
+class IntlDateTimeFormat : public JSDestructibleObject {
+public:
+ typedef JSDestructibleObject Base;
+
+ static IntlDateTimeFormat* create(VM&, IntlDateTimeFormatConstructor*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+ void initializeDateTimeFormat(ExecState&, JSValue locales, JSValue options);
+ JSValue format(ExecState&, double value);
+ JSObject* resolvedOptions(ExecState&);
+
+ JSBoundFunction* boundFormat() const { return m_boundFormat.get(); }
+ void setBoundFormat(VM&, JSBoundFunction*);
+
+protected:
+ IntlDateTimeFormat(VM&, Structure*);
+ ~IntlDateTimeFormat();
+ void finishCreation(VM&);
+ static void destroy(JSCell*);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+private:
+ enum class Weekday { None, Narrow, Short, Long };
+ enum class Era { None, Narrow, Short, Long };
+ enum class Year { None, TwoDigit, Numeric };
+ enum class Month { None, TwoDigit, Numeric, Narrow, Short, Long };
+ enum class Day { None, TwoDigit, Numeric };
+ enum class Hour { None, TwoDigit, Numeric };
+ enum class Minute { None, TwoDigit, Numeric };
+ enum class Second { None, TwoDigit, Numeric };
+ enum class TimeZoneName { None, Short, Long };
+
+ static const char* weekdayString(Weekday);
+ static const char* eraString(Era);
+ static const char* yearString(Year);
+ static const char* monthString(Month);
+ static const char* dayString(Day);
+ static const char* hourString(Hour);
+ static const char* minuteString(Minute);
+ static const char* secondString(Second);
+ static const char* timeZoneNameString(TimeZoneName);
+
+ bool m_initializedDateTimeFormat { false };
+ void setFormatsFromPattern(const StringView&);
+ WriteBarrier<JSBoundFunction> m_boundFormat;
+ UDateFormat* m_dateFormat { nullptr };
+
+ String m_locale { ASCIILiteral("en") };
+ String m_calendar { ASCIILiteral("gregorian") };
+ String m_numberingSystem { ASCIILiteral("latn") };
+ String m_timeZone { ASCIILiteral("UTC") };
+ bool m_hour12 { true };
+ Weekday m_weekday { Weekday::None };
+ Era m_era { Era::None };
+ Year m_year { Year::None };
+ Month m_month { Month::None };
+ Day m_day { Day::None };
+ Hour m_hour { Hour::None };
+ Minute m_minute { Minute::None };
+ Second m_second { Second::None };
+ TimeZoneName m_timeZoneName { TimeZoneName::None };
+};
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
+
+#endif // IntlDateTimeFormat_h
diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp b/Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp
new file mode 100644
index 000000000..6a7c2e4af
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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 "IntlDateTimeFormatConstructor.h"
+
+#if ENABLE(INTL)
+
+#include "Error.h"
+#include "IntlDateTimeFormat.h"
+#include "IntlDateTimeFormatPrototype.h"
+#include "IntlObject.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "Lookup.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlDateTimeFormatConstructor);
+
+static EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatConstructorFuncSupportedLocalesOf(ExecState*);
+
+}
+
+#include "IntlDateTimeFormatConstructor.lut.h"
+
+namespace JSC {
+
+const ClassInfo IntlDateTimeFormatConstructor::s_info = { "Function", &InternalFunction::s_info, &dateTimeFormatConstructorTable, CREATE_METHOD_TABLE(IntlDateTimeFormatConstructor) };
+
+/* Source for IntlDateTimeFormatConstructor.lut.h
+@begin dateTimeFormatConstructorTable
+ supportedLocalesOf IntlDateTimeFormatConstructorFuncSupportedLocalesOf DontEnum|Function 1
+@end
+*/
+
+IntlDateTimeFormatConstructor* IntlDateTimeFormatConstructor::create(VM& vm, Structure* structure, IntlDateTimeFormatPrototype* dateTimeFormatPrototype, Structure* dateTimeFormatStructure)
+{
+ IntlDateTimeFormatConstructor* constructor = new (NotNull, allocateCell<IntlDateTimeFormatConstructor>(vm.heap)) IntlDateTimeFormatConstructor(vm, structure);
+ constructor->finishCreation(vm, dateTimeFormatPrototype, dateTimeFormatStructure);
+ return constructor;
+}
+
+Structure* IntlDateTimeFormatConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlDateTimeFormatConstructor::IntlDateTimeFormatConstructor(VM& vm, Structure* structure)
+ : InternalFunction(vm, structure)
+{
+}
+
+void IntlDateTimeFormatConstructor::finishCreation(VM& vm, IntlDateTimeFormatPrototype* dateTimeFormatPrototype, Structure* dateTimeFormatStructure)
+{
+ Base::finishCreation(vm, ASCIILiteral("DateTimeFormat"));
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, dateTimeFormatPrototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum | DontDelete);
+ m_dateTimeFormatStructure.set(vm, this, dateTimeFormatStructure);
+}
+
+static EncodedJSValue JSC_HOST_CALL constructIntlDateTimeFormat(ExecState* state)
+{
+ // 12.1.2 Intl.DateTimeFormat ([locales [, options]]) (ECMA-402 2.0)
+ // 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
+ JSValue newTarget = state->newTarget();
+ if (newTarget.isUndefined())
+ newTarget = state->callee();
+
+ // 2. Let dateTimeFormat be OrdinaryCreateFromConstructor(newTarget, %DateTimeFormatPrototype%).
+ VM& vm = state->vm();
+ IntlDateTimeFormat* dateTimeFormat = IntlDateTimeFormat::create(vm, jsCast<IntlDateTimeFormatConstructor*>(state->callee()));
+ if (dateTimeFormat && !jsDynamicCast<IntlDateTimeFormatConstructor*>(newTarget)) {
+ JSValue proto = asObject(newTarget)->getDirect(vm, vm.propertyNames->prototype);
+ asObject(dateTimeFormat)->setPrototypeWithCycleCheck(state, proto);
+ }
+
+ // 3. ReturnIfAbrupt(dateTimeFormat).
+ ASSERT(dateTimeFormat);
+
+ // 4. Return InitializeDateTimeFormat(dateTimeFormat, locales, options).
+ JSValue locales = state->argument(0);
+ JSValue options = state->argument(1);
+ dateTimeFormat->initializeDateTimeFormat(*state, locales, options);
+ return JSValue::encode(dateTimeFormat);
+}
+
+static EncodedJSValue JSC_HOST_CALL callIntlDateTimeFormat(ExecState* state)
+{
+ // 12.1.2 Intl.DateTimeFormat ([locales [, options]]) (ECMA-402 2.0)
+ // 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
+ // NewTarget is always undefined when called as a function.
+
+ // 2. Let dateTimeFormat be OrdinaryCreateFromConstructor(newTarget, %DateTimeFormatPrototype%).
+ VM& vm = state->vm();
+ IntlDateTimeFormat* dateTimeFormat = IntlDateTimeFormat::create(vm, jsCast<IntlDateTimeFormatConstructor*>(state->callee()));
+
+ // 3. ReturnIfAbrupt(dateTimeFormat).
+ ASSERT(dateTimeFormat);
+
+ // 4. Return InitializeDateTimeFormat(dateTimeFormat, locales, options).
+ JSValue locales = state->argument(0);
+ JSValue options = state->argument(1);
+ dateTimeFormat->initializeDateTimeFormat(*state, locales, options);
+ return JSValue::encode(dateTimeFormat);
+}
+
+ConstructType IntlDateTimeFormatConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructIntlDateTimeFormat;
+ return ConstructTypeHost;
+}
+
+CallType IntlDateTimeFormatConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callIntlDateTimeFormat;
+ return CallTypeHost;
+}
+
+bool IntlDateTimeFormatConstructor::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<InternalFunction>(state, dateTimeFormatConstructorTable, jsCast<IntlDateTimeFormatConstructor*>(object), propertyName, slot);
+}
+
+EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatConstructorFuncSupportedLocalesOf(ExecState* state)
+{
+ // 12.2.2 Intl.DateTimeFormat.supportedLocalesOf(locales [, options]) (ECMA-402 2.0)
+
+ // 1. Let availableLocales be %DateTimeFormat%.[[availableLocales]].
+ JSGlobalObject* globalObject = state->callee()->globalObject();
+ const HashSet<String> availableLocales = globalObject->intlDateTimeFormatAvailableLocales();
+
+ // 2. Let requestedLocales be CanonicalizeLocaleList(locales).
+ Vector<String> requestedLocales = canonicalizeLocaleList(*state, state->argument(0));
+ if (state->hadException())
+ return JSValue::encode(jsUndefined());
+
+ // 3. Return SupportedLocales(availableLocales, requestedLocales, options).
+ return JSValue::encode(supportedLocales(*state, availableLocales, requestedLocales, state->argument(1)));
+}
+
+void IntlDateTimeFormatConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ IntlDateTimeFormatConstructor* thisObject = jsCast<IntlDateTimeFormatConstructor*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_dateTimeFormatStructure);
+}
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.h b/Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.h
new file mode 100644
index 000000000..fd7339ed2
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormatConstructor.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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.
+ */
+
+#ifndef IntlDateTimeFormatConstructor_h
+#define IntlDateTimeFormatConstructor_h
+
+#if ENABLE(INTL)
+
+#include "InternalFunction.h"
+
+namespace JSC {
+
+class IntlDateTimeFormat;
+class IntlDateTimeFormatPrototype;
+
+class IntlDateTimeFormatConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static IntlDateTimeFormatConstructor* create(VM&, Structure*, IntlDateTimeFormatPrototype*, Structure*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+ Structure* dateTimeFormatStructure() const { return m_dateTimeFormatStructure.get(); }
+
+protected:
+ void finishCreation(VM&, IntlDateTimeFormatPrototype*, Structure*);
+
+private:
+ IntlDateTimeFormatConstructor(VM&, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ WriteBarrier<Structure> m_dateTimeFormatStructure;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
+
+#endif // IntlDateTimeFormatConstructor_h
diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp b/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp
new file mode 100644
index 000000000..ff48ec455
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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 "IntlDateTimeFormatPrototype.h"
+
+#if ENABLE(INTL)
+
+#include "DateConstructor.h"
+#include "Error.h"
+#include "IntlDateTimeFormat.h"
+#include "IntlObject.h"
+#include "JSBoundFunction.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSObject.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatPrototypeGetterFormat(ExecState*);
+static EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatPrototypeFuncResolvedOptions(ExecState*);
+
+}
+
+#include "IntlDateTimeFormatPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo IntlDateTimeFormatPrototype::s_info = { "Object", &IntlDateTimeFormat::s_info, &dateTimeFormatPrototypeTable, CREATE_METHOD_TABLE(IntlDateTimeFormatPrototype) };
+
+/* Source for IntlDateTimeFormatPrototype.lut.h
+@begin dateTimeFormatPrototypeTable
+ format IntlDateTimeFormatPrototypeGetterFormat DontEnum|Accessor
+ resolvedOptions IntlDateTimeFormatPrototypeFuncResolvedOptions DontEnum|Function 0
+@end
+*/
+
+IntlDateTimeFormatPrototype* IntlDateTimeFormatPrototype::create(VM& vm, JSGlobalObject*, Structure* structure)
+{
+ IntlDateTimeFormatPrototype* object = new (NotNull, allocateCell<IntlDateTimeFormatPrototype>(vm.heap)) IntlDateTimeFormatPrototype(vm, structure);
+ object->finishCreation(vm, structure);
+ return object;
+}
+
+Structure* IntlDateTimeFormatPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlDateTimeFormatPrototype::IntlDateTimeFormatPrototype(VM& vm, Structure* structure)
+ : IntlDateTimeFormat(vm, structure)
+{
+}
+
+void IntlDateTimeFormatPrototype::finishCreation(VM& vm, Structure*)
+{
+ Base::finishCreation(vm);
+}
+
+bool IntlDateTimeFormatPrototype::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<JSObject>(state, dateTimeFormatPrototypeTable, jsCast<IntlDateTimeFormatPrototype*>(object), propertyName, slot);
+}
+
+static EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatFuncFormatDateTime(ExecState* state)
+{
+ // 12.3.4 DateTime Format Functions (ECMA-402 2.0)
+ // 1. Let dtf be the this value.
+ // 2. Assert: Type(dtf) is Object and dtf has an [[initializedDateTimeFormat]] internal slot whose value is true.
+ IntlDateTimeFormat* format = jsCast<IntlDateTimeFormat*>(state->thisValue());
+
+ JSValue date = state->argument(0);
+ double value;
+
+ // 3. If date is not provided or is undefined, then
+ if (date.isUndefined()) {
+ // a. Let x be %Date_now%().
+ value = JSValue::decode(dateNow(state)).toNumber(state);
+ } else {
+ // 4. Else
+ // a. Let x be ToNumber(date).
+ value = date.toNumber(state);
+ // b. ReturnIfAbrupt(x).
+ if (state->hadException())
+ return JSValue::encode(jsUndefined());
+ }
+
+ // 5. Return FormatDateTime(dtf, x).
+ return JSValue::encode(format->format(*state, value));
+}
+
+EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatPrototypeGetterFormat(ExecState* state)
+{
+ // 12.3.3 Intl.DateTimeFormat.prototype.format (ECMA-402 2.0)
+ // 1. Let dtf be this DateTimeFormat object.
+ IntlDateTimeFormat* dtf = jsDynamicCast<IntlDateTimeFormat*>(state->thisValue());
+ // 2. ReturnIfAbrupt(dtf).
+ if (!dtf)
+ return JSValue::encode(throwTypeError(state, ASCIILiteral("Intl.DateTimeFormat.prototype.format called on value that's not an object initialized as a DateTimeFormat")));
+
+ JSBoundFunction* boundFormat = dtf->boundFormat();
+ // 3. If the [[boundFormat]] internal slot of this DateTimeFormat object is undefined,
+ if (!boundFormat) {
+ VM& vm = state->vm();
+ JSGlobalObject* globalObject = dtf->globalObject();
+ // a. Let F be a new built-in function object as defined in 12.3.4.
+ // b. The value of F’s length property is 1. (Note: F’s length property was 0 in ECMA-402 1.0)
+ JSFunction* targetObject = JSFunction::create(vm, globalObject, 1, ASCIILiteral("format"), IntlDateTimeFormatFuncFormatDateTime, NoIntrinsic);
+ JSArray* boundArgs = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), 0);
+ if (!boundArgs)
+ return JSValue::encode(throwOutOfMemoryError(state));
+
+ // c. Let bf be BoundFunctionCreate(F, «this value»).
+ boundFormat = JSBoundFunction::create(vm, globalObject, targetObject, dtf, boundArgs, 1, ASCIILiteral("format"));
+ // d. Set dtf.[[boundFormat]] to bf.
+ dtf->setBoundFormat(vm, boundFormat);
+ }
+ // 4. Return dtf.[[boundFormat]].
+ return JSValue::encode(boundFormat);
+}
+
+EncodedJSValue JSC_HOST_CALL IntlDateTimeFormatPrototypeFuncResolvedOptions(ExecState* state)
+{
+ // 12.3.5 Intl.DateTimeFormat.prototype.resolvedOptions() (ECMA-402 2.0)
+ IntlDateTimeFormat* dateTimeFormat = jsDynamicCast<IntlDateTimeFormat*>(state->thisValue());
+ if (!dateTimeFormat)
+ return JSValue::encode(throwTypeError(state, ASCIILiteral("Intl.DateTimeFormat.prototype.resolvedOptions called on value that's not an object initialized as a DateTimeFormat")));
+
+ return JSValue::encode(dateTimeFormat->resolvedOptions(*state));
+}
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.h b/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.h
new file mode 100644
index 000000000..a2fd5e34e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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.
+ */
+
+#ifndef IntlDateTimeFormatPrototype_h
+#define IntlDateTimeFormatPrototype_h
+
+#if ENABLE(INTL)
+
+#include "IntlDateTimeFormat.h"
+#include "JSObject.h"
+
+namespace JSC {
+
+class IntlDateTimeFormatPrototype : public IntlDateTimeFormat {
+public:
+ typedef IntlDateTimeFormat Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static IntlDateTimeFormatPrototype* create(VM&, JSGlobalObject*, Structure*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+protected:
+ void finishCreation(VM&, Structure*);
+
+private:
+ IntlDateTimeFormatPrototype(VM&, Structure*);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+};
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
+
+#endif // IntlDateTimeFormatPrototype_h
diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp b/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp
new file mode 100644
index 000000000..674f3d4b2
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ * Copyright (C) 2016 Sukolsak Sakshuwong (sukolsak@gmail.com)
+ *
+ * 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 "IntlNumberFormat.h"
+
+#if ENABLE(INTL)
+
+#include "Error.h"
+#include "IdentifierInlines.h"
+#include "IntlNumberFormatConstructor.h"
+#include "IntlObject.h"
+#include "JSBoundFunction.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "ObjectConstructor.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+const ClassInfo IntlNumberFormat::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(IntlNumberFormat) };
+
+static const char* const relevantExtensionKeys[1] = { "nu" };
+
+IntlNumberFormat* IntlNumberFormat::create(VM& vm, IntlNumberFormatConstructor* constructor)
+{
+ IntlNumberFormat* format = new (NotNull, allocateCell<IntlNumberFormat>(vm.heap)) IntlNumberFormat(vm, constructor->numberFormatStructure());
+ format->finishCreation(vm);
+ return format;
+}
+
+Structure* IntlNumberFormat::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlNumberFormat::IntlNumberFormat(VM& vm, Structure* structure)
+ : JSDestructibleObject(vm, structure)
+{
+}
+
+void IntlNumberFormat::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+}
+
+void IntlNumberFormat::destroy(JSCell* cell)
+{
+ static_cast<IntlNumberFormat*>(cell)->IntlNumberFormat::~IntlNumberFormat();
+}
+
+void IntlNumberFormat::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ IntlNumberFormat* thisObject = jsCast<IntlNumberFormat*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_boundFormat);
+}
+
+static Vector<String> localeData(const String& locale, size_t keyIndex)
+{
+ // 9.1 Internal slots of Service Constructors & 11.2.3 Internal slots (ECMA-402 2.0)
+ ASSERT_UNUSED(keyIndex, !keyIndex); // The index of the extension key "nu" in relevantExtensionKeys is 0.
+ return numberingSystemsForLocale(locale);
+}
+
+static inline unsigned computeCurrencySortKey(const String& currency)
+{
+ ASSERT(currency.length() == 3);
+ ASSERT(currency.isAllSpecialCharacters<isASCIIUpper>());
+ return (currency[0] << 16) + (currency[1] << 8) + currency[2];
+}
+
+static inline unsigned computeCurrencySortKey(const char* currency)
+{
+ ASSERT(strlen(currency) == 3);
+ ASSERT(isAllSpecialCharacters<isASCIIUpper>(currency, 3));
+ return (currency[0] << 16) + (currency[1] << 8) + currency[2];
+}
+
+static unsigned extractCurrencySortKey(std::pair<const char*, unsigned>* currencyMinorUnit)
+{
+ return computeCurrencySortKey(currencyMinorUnit->first);
+}
+
+static unsigned computeCurrencyDigits(const String& currency)
+{
+ // 11.1.1 The abstract operation CurrencyDigits (currency)
+ // "If the ISO 4217 currency and funds code list contains currency as an alphabetic code,
+ // then return the minor unit value corresponding to the currency from the list; else return 2.
+ std::pair<const char*, unsigned> currencyMinorUnits[] = {
+ { "BHD", 3 },
+ { "BIF", 0 },
+ { "BYR", 0 },
+ { "CLF", 4 },
+ { "CLP", 0 },
+ { "DJF", 0 },
+ { "GNF", 0 },
+ { "IQD", 3 },
+ { "ISK", 0 },
+ { "JOD", 3 },
+ { "JPY", 0 },
+ { "KMF", 0 },
+ { "KRW", 0 },
+ { "KWD", 3 },
+ { "LYD", 3 },
+ { "OMR", 3 },
+ { "PYG", 0 },
+ { "RWF", 0 },
+ { "TND", 3 },
+ { "UGX", 0 },
+ { "UYI", 0 },
+ { "VND", 0 },
+ { "VUV", 0 },
+ { "XAF", 0 },
+ { "XOF", 0 },
+ { "XPF", 0 }
+ };
+ auto* currencyMinorUnit = tryBinarySearch<std::pair<const char*, unsigned>>(currencyMinorUnits, WTF_ARRAY_LENGTH(currencyMinorUnits), computeCurrencySortKey(currency), extractCurrencySortKey);
+ if (currencyMinorUnit)
+ return currencyMinorUnit->second;
+ return 2;
+}
+
+void IntlNumberFormat::initializeNumberFormat(ExecState& state, JSValue locales, JSValue optionsValue)
+{
+ // 11.1.1 InitializeNumberFormat (numberFormat, locales, options) (ECMA-402 2.0)
+ VM& vm = state.vm();
+
+ // 1. If numberFormat has an [[initializedIntlObject]] internal slot with value true, throw a TypeError exception.
+ // 2. Set numberFormat.[[initializedIntlObject]] to true.
+
+ // 3. Let requestedLocales be CanonicalizeLocaleList(locales).
+ auto requestedLocales = canonicalizeLocaleList(state, locales);
+ // 4. ReturnIfAbrupt(requestedLocales).
+ if (state.hadException())
+ return;
+
+ // 5. If options is undefined, then
+ JSObject* options;
+ if (optionsValue.isUndefined()) {
+ // a. Let options be ObjectCreate(%ObjectPrototype%).
+ options = constructEmptyObject(&state);
+ } else { // 6. Else
+ // a. Let options be ToObject(options).
+ options = optionsValue.toObject(&state);
+ // b. ReturnIfAbrupt(options).
+ if (state.hadException())
+ return;
+ }
+
+ // 7. Let opt be a new Record.
+ HashMap<String, String> opt;
+
+ // 8. Let matcher be GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit").
+ String matcher = intlStringOption(state, options, state.vm().propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit");
+ // 9. ReturnIfAbrupt(matcher).
+ if (state.hadException())
+ return;
+ // 10. Set opt.[[localeMatcher]] to matcher.
+ opt.add(ASCIILiteral("localeMatcher"), matcher);
+
+ // 11. Let localeData be %NumberFormat%.[[localeData]].
+ // 12. Let r be ResolveLocale(%NumberFormat%.[[availableLocales]], requestedLocales, opt, %NumberFormat%.[[relevantExtensionKeys]], localeData).
+ auto& availableLocales = state.callee()->globalObject()->intlNumberFormatAvailableLocales();
+ auto result = resolveLocale(availableLocales, requestedLocales, opt, relevantExtensionKeys, WTF_ARRAY_LENGTH(relevantExtensionKeys), localeData);
+
+ // 13. Set numberFormat.[[locale]] to the value of r.[[locale]].
+ m_locale = result.get(ASCIILiteral("locale"));
+
+ // 14. Set numberFormat.[[numberingSystem]] to the value of r.[[nu]].
+ m_numberingSystem = result.get(ASCIILiteral("nu"));
+
+ // 15. Let dataLocale be r.[[dataLocale]].
+
+ // 16. Let s be GetOption(options, "style", "string", « "decimal", "percent", "currency"», "decimal").
+ String styleString = intlStringOption(state, options, Identifier::fromString(&vm, "style"), { "decimal", "percent", "currency" }, "style must be either \"decimal\", \"percent\", or \"currency\"", "decimal");
+ // 17. ReturnIfAbrupt(s).
+ if (state.hadException())
+ return;
+ // 18. Set numberFormat.[[style]] to s.
+ if (styleString == "decimal")
+ m_style = Style::Decimal;
+ else if (styleString == "percent")
+ m_style = Style::Percent;
+ else if (styleString == "currency")
+ m_style = Style::Currency;
+ else
+ ASSERT_NOT_REACHED();
+
+ // 19. Let c be GetOption(options, "currency", "string", undefined, undefined).
+ String currency = intlStringOption(state, options, Identifier::fromString(&vm, "currency"), { }, nullptr, nullptr);
+ // 20. ReturnIfAbrupt(c).
+ if (state.hadException())
+ return;
+ // 21. If c is not undefined, then
+ if (!currency.isNull()) {
+ // a. If the result of IsWellFormedCurrencyCode(c), is false, then throw a RangeError exception.
+ if (currency.length() != 3 || !currency.isAllSpecialCharacters<isASCIIAlpha>()) {
+ state.vm().throwException(&state, createRangeError(&state, ASCIILiteral("currency is not a well-formed currency code")));
+ return;
+ }
+ }
+
+ unsigned currencyDigits;
+ if (m_style == Style::Currency) {
+ // 22. If s is "currency" and c is undefined, throw a TypeError exception.
+ if (currency.isNull()) {
+ throwTypeError(&state, ASCIILiteral("currency must be a string"));
+ return;
+ }
+
+ // 23. If s is "currency", then
+ // a. Let c be converting c to upper case as specified in 6.1.
+ currency = currency.convertToASCIIUppercase();
+ // b. Set numberFormat.[[currency]] to c.
+ m_currency = currency;
+ // c. Let cDigits be CurrencyDigits(c)
+ currencyDigits = computeCurrencyDigits(currency);
+ }
+
+ // 24. Let cd be GetOption(options, "currencyDisplay", "string", «"code", "symbol", "name"», "symbol").
+ String currencyDisplayString = intlStringOption(state, options, Identifier::fromString(&vm, "currencyDisplay"), { "code", "symbol", "name" }, "currencyDisplay must be either \"code\", \"symbol\", or \"name\"", "symbol");
+ // 25. ReturnIfAbrupt(cd).
+ if (state.hadException())
+ return;
+ // 26. If s is "currency", set numberFormat.[[currencyDisplay]] to cd.
+ if (m_style == Style::Currency) {
+ if (currencyDisplayString == "code")
+ m_currencyDisplay = CurrencyDisplay::Code;
+ else if (currencyDisplayString == "symbol")
+ m_currencyDisplay = CurrencyDisplay::Symbol;
+ else if (currencyDisplayString == "name")
+ m_currencyDisplay = CurrencyDisplay::Name;
+ else
+ ASSERT_NOT_REACHED();
+ }
+
+ // 27. Let mnid be GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1).
+ // 28. ReturnIfAbrupt(mnid).
+ // 29. Set numberFormat.[[minimumIntegerDigits]] to mnid.
+ unsigned minimumIntegerDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "minimumIntegerDigits"), 1, 21, 1);
+ if (state.hadException())
+ return;
+ m_minimumIntegerDigits = minimumIntegerDigits;
+
+ // 30. If s is "currency", let mnfdDefault be cDigits; else let mnfdDefault be 0.
+ unsigned minimumFractionDigitsDefault = (m_style == Style::Currency) ? currencyDigits : 0;
+
+ // 31. Let mnfd be GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault).
+ // 32. ReturnIfAbrupt(mnfd).
+ // 33. Set numberFormat.[[minimumFractionDigits]] to mnfd.
+ unsigned minimumFractionDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "minimumFractionDigits"), 0, 20, minimumFractionDigitsDefault);
+ if (state.hadException())
+ return;
+ m_minimumFractionDigits = minimumFractionDigits;
+
+ // 34. If s is "currency", let mxfdDefault be max(mnfd, cDigits);
+ unsigned maximumFractionDigitsDefault;
+ if (m_style == Style::Currency)
+ maximumFractionDigitsDefault = std::max(minimumFractionDigits, currencyDigits);
+ else if (m_style == Style::Percent) // else if s is "percent", let mxfdDefault be max(mnfd, 0);
+ maximumFractionDigitsDefault = minimumFractionDigits;
+ else // else let mxfdDefault be max(mnfd, 3).
+ maximumFractionDigitsDefault = std::max(minimumFractionDigits, 3u);
+
+ // 35. Let mxfd be GetNumberOption(options, "maximumFractionDigits", mnfd, 20, mxfdDefault).
+ // 36. ReturnIfAbrupt(mxfd).
+ // 37. Set numberFormat.[[maximumFractionDigits]] to mxfd.
+ unsigned maximumFractionDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "maximumFractionDigits"), minimumFractionDigits, 20, maximumFractionDigitsDefault);
+ if (state.hadException())
+ return;
+ m_maximumFractionDigits = maximumFractionDigits;
+
+ // 38. Let mnsd be Get(options, "minimumSignificantDigits").
+ JSValue minimumSignificantDigitsValue = options->get(&state, Identifier::fromString(&vm, "minimumSignificantDigits"));
+ // 39. ReturnIfAbrupt(mnsd).
+ if (state.hadException())
+ return;
+
+ // 40. Let mxsd be Get(options, "maximumSignificantDigits").
+ JSValue maximumSignificantDigitsValue = options->get(&state, Identifier::fromString(&vm, "maximumSignificantDigits"));
+ // 41. ReturnIfAbrupt(mxsd).
+ if (state.hadException())
+ return;
+
+ // 42. If mnsd is not undefined or mxsd is not undefined, then
+ if (!minimumSignificantDigitsValue.isUndefined() || !maximumSignificantDigitsValue.isUndefined()) {
+ // a. Let mnsd be GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1).
+ unsigned minimumSignificantDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "minimumSignificantDigits"), 1, 21, 1);
+ // b. ReturnIfAbrupt(mnsd).
+ if (state.hadException())
+ return;
+ // c. Let mxsd be GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21).
+ unsigned maximumSignificantDigits = intlNumberOption(state, options, Identifier::fromString(&vm, "maximumSignificantDigits"), minimumSignificantDigits, 21, 21);
+ // d. ReturnIfAbrupt(mxsd).
+ if (state.hadException())
+ return;
+ // e. Set numberFormat.[[minimumSignificantDigits]] to mnsd.
+ m_minimumSignificantDigits = minimumSignificantDigits;
+ // f. Set numberFormat.[[maximumSignificantDigits]] to mxsd.
+ m_maximumSignificantDigits = maximumSignificantDigits;
+ }
+
+ // 43. Let g be GetOption(options, "useGrouping", "boolean", undefined, true).
+ bool usesFallback;
+ bool useGrouping = intlBooleanOption(state, options, Identifier::fromString(&vm, "useGrouping"), usesFallback);
+ if (usesFallback)
+ useGrouping = true;
+ // 44. ReturnIfAbrupt(g).
+ if (state.hadException())
+ return;
+ // 45. Set numberFormat.[[useGrouping]] to g.
+ m_useGrouping = useGrouping;
+
+ // FIXME: Implement Steps 46 - 51.
+ // 46. Let dataLocaleData be Get(localeData, dataLocale).
+ // 47. Let patterns be Get(dataLocaleData, "patterns").
+ // 48. Assert: patterns is an object (see 11.2.3).
+ // 49. Let stylePatterns be Get(patterns, s).
+ // 50. Set numberFormat.[[positivePattern]] to Get(stylePatterns, "positivePattern").
+ // 51. Set numberFormat.[[negativePattern]] to Get(stylePatterns, "negativePattern").
+
+ // 52. Set numberFormat.[[boundFormat]] to undefined.
+ // 53. Set numberFormat.[[initializedNumberFormat]] to true.
+ m_initializedNumberFormat = true;
+
+ // 54. Return numberFormat.
+}
+
+EncodedJSValue JSC_HOST_CALL IntlNumberFormatFuncFormatNumber(ExecState* state)
+{
+ // 11.3.4 Format Number Functions (ECMA-402 2.0)
+ // 1. Let nf be the this value.
+ IntlNumberFormat* format = jsDynamicCast<IntlNumberFormat*>(state->thisValue());
+ // 2. Assert: Type(nf) is Object and nf has an [[initializedNumberFormat]] internal slot whose value is true.
+ if (!format)
+ return JSValue::encode(throwTypeError(state));
+
+ // 3. If value is not provided, let value be undefined.
+ // 4. Let x be ToNumber(value).
+ double value = state->argument(0).toNumber(state);
+ // 5. ReturnIfAbrupt(x).
+ if (state->hadException())
+ return JSValue::encode(jsUndefined());
+
+ // 6. Return FormatNumber(nf, x).
+
+ // 11.3.4 FormatNumber abstract operation (ECMA-402 2.0)
+ // FIXME: Implement FormatNumber.
+
+ return JSValue::encode(jsNumber(value).toString(state));
+}
+
+const char* IntlNumberFormat::styleString(Style style)
+{
+ switch (style) {
+ case Style::Decimal:
+ return "decimal";
+ case Style::Percent:
+ return "percent";
+ case Style::Currency:
+ return "currency";
+ }
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+const char* IntlNumberFormat::currencyDisplayString(CurrencyDisplay currencyDisplay)
+{
+ switch (currencyDisplay) {
+ case CurrencyDisplay::Code:
+ return "code";
+ case CurrencyDisplay::Symbol:
+ return "symbol";
+ case CurrencyDisplay::Name:
+ return "name";
+ }
+ ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+JSObject* IntlNumberFormat::resolvedOptions(ExecState& state)
+{
+ // 11.3.5 Intl.NumberFormat.prototype.resolvedOptions() (ECMA-402 2.0)
+ // The function returns a new object whose properties and attributes are set as if
+ // constructed by an object literal assigning to each of the following properties the
+ // value of the corresponding internal slot of this NumberFormat object (see 11.4):
+ // locale, numberingSystem, style, currency, currencyDisplay, minimumIntegerDigits,
+ // minimumFractionDigits, maximumFractionDigits, minimumSignificantDigits,
+ // maximumSignificantDigits, and useGrouping. Properties whose corresponding internal
+ // slots are not present are not assigned.
+
+ if (!m_initializedNumberFormat) {
+ initializeNumberFormat(state, jsUndefined(), jsUndefined());
+ ASSERT(!state.hadException());
+ }
+
+ VM& vm = state.vm();
+ JSObject* options = constructEmptyObject(&state);
+ options->putDirect(vm, vm.propertyNames->locale, jsString(&state, m_locale));
+ options->putDirect(vm, Identifier::fromString(&vm, "numberingSystem"), jsString(&state, m_numberingSystem));
+ options->putDirect(vm, Identifier::fromString(&vm, "style"), jsNontrivialString(&state, ASCIILiteral(styleString(m_style))));
+ if (m_style == Style::Currency) {
+ options->putDirect(vm, Identifier::fromString(&vm, "currency"), jsNontrivialString(&state, m_currency));
+ options->putDirect(vm, Identifier::fromString(&vm, "currencyDisplay"), jsNontrivialString(&state, ASCIILiteral(currencyDisplayString(m_currencyDisplay))));
+ }
+ options->putDirect(vm, Identifier::fromString(&vm, "minimumIntegerDigits"), jsNumber(m_minimumIntegerDigits));
+ options->putDirect(vm, Identifier::fromString(&vm, "minimumFractionDigits"), jsNumber(m_minimumFractionDigits));
+ options->putDirect(vm, Identifier::fromString(&vm, "maximumFractionDigits"), jsNumber(m_maximumFractionDigits));
+ if (m_minimumSignificantDigits) {
+ ASSERT(m_maximumSignificantDigits);
+ options->putDirect(vm, Identifier::fromString(&vm, "minimumSignificantDigits"), jsNumber(m_minimumSignificantDigits));
+ options->putDirect(vm, Identifier::fromString(&vm, "maximumSignificantDigits"), jsNumber(m_maximumSignificantDigits));
+ }
+ options->putDirect(vm, Identifier::fromString(&vm, "useGrouping"), jsBoolean(m_useGrouping));
+ return options;
+}
+
+void IntlNumberFormat::setBoundFormat(VM& vm, JSBoundFunction* format)
+{
+ m_boundFormat.set(vm, this, format);
+}
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormat.h b/Source/JavaScriptCore/runtime/IntlNumberFormat.h
new file mode 100644
index 000000000..f90731023
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlNumberFormat.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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.
+ */
+
+#ifndef IntlNumberFormat_h
+#define IntlNumberFormat_h
+
+#if ENABLE(INTL)
+
+#include "JSDestructibleObject.h"
+
+namespace JSC {
+
+class IntlNumberFormatConstructor;
+class JSBoundFunction;
+
+class IntlNumberFormat : public JSDestructibleObject {
+public:
+ typedef JSDestructibleObject Base;
+
+ static IntlNumberFormat* create(VM&, IntlNumberFormatConstructor*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+ void initializeNumberFormat(ExecState&, JSValue locales, JSValue optionsValue);
+ JSObject* resolvedOptions(ExecState&);
+
+ JSBoundFunction* boundFormat() const { return m_boundFormat.get(); }
+ void setBoundFormat(VM&, JSBoundFunction*);
+
+protected:
+ IntlNumberFormat(VM&, Structure*);
+ void finishCreation(VM&);
+ static void destroy(JSCell*);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+private:
+ enum class Style { Decimal, Percent, Currency };
+ enum class CurrencyDisplay { Code, Symbol, Name };
+
+ const char* styleString(Style);
+ const char* currencyDisplayString(CurrencyDisplay);
+
+ String m_locale;
+ String m_numberingSystem;
+ Style m_style { Style::Decimal };
+ String m_currency;
+ CurrencyDisplay m_currencyDisplay;
+ unsigned m_minimumIntegerDigits { 1 };
+ unsigned m_minimumFractionDigits { 0 };
+ unsigned m_maximumFractionDigits { 3 };
+ unsigned m_minimumSignificantDigits { 0 };
+ unsigned m_maximumSignificantDigits { 0 };
+ WriteBarrier<JSBoundFunction> m_boundFormat;
+ bool m_useGrouping { true };
+ bool m_initializedNumberFormat { false };
+};
+
+EncodedJSValue JSC_HOST_CALL IntlNumberFormatFuncFormatNumber(ExecState*);
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
+
+#endif // IntlNumberFormat_h
diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.cpp b/Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.cpp
new file mode 100644
index 000000000..07fa654e3
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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 "IntlNumberFormatConstructor.h"
+
+#if ENABLE(INTL)
+
+#include "Error.h"
+#include "IntlNumberFormat.h"
+#include "IntlNumberFormatPrototype.h"
+#include "IntlObject.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "Lookup.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlNumberFormatConstructor);
+
+static EncodedJSValue JSC_HOST_CALL IntlNumberFormatConstructorFuncSupportedLocalesOf(ExecState*);
+
+}
+
+#include "IntlNumberFormatConstructor.lut.h"
+
+namespace JSC {
+
+const ClassInfo IntlNumberFormatConstructor::s_info = { "Function", &Base::s_info, &numberFormatConstructorTable, CREATE_METHOD_TABLE(IntlNumberFormatConstructor) };
+
+/* Source for IntlNumberFormatConstructor.lut.h
+@begin numberFormatConstructorTable
+ supportedLocalesOf IntlNumberFormatConstructorFuncSupportedLocalesOf DontEnum|Function 1
+@end
+*/
+
+IntlNumberFormatConstructor* IntlNumberFormatConstructor::create(VM& vm, Structure* structure, IntlNumberFormatPrototype* numberFormatPrototype, Structure* numberFormatStructure)
+{
+ IntlNumberFormatConstructor* constructor = new (NotNull, allocateCell<IntlNumberFormatConstructor>(vm.heap)) IntlNumberFormatConstructor(vm, structure);
+ constructor->finishCreation(vm, numberFormatPrototype, numberFormatStructure);
+ return constructor;
+}
+
+Structure* IntlNumberFormatConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlNumberFormatConstructor::IntlNumberFormatConstructor(VM& vm, Structure* structure)
+ : InternalFunction(vm, structure)
+{
+}
+
+void IntlNumberFormatConstructor::finishCreation(VM& vm, IntlNumberFormatPrototype* numberFormatPrototype, Structure* numberFormatStructure)
+{
+ Base::finishCreation(vm, ASCIILiteral("NumberFormat"));
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, numberFormatPrototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum | DontDelete);
+ m_numberFormatStructure.set(vm, this, numberFormatStructure);
+}
+
+static EncodedJSValue JSC_HOST_CALL constructIntlNumberFormat(ExecState* state)
+{
+ // 11.1.2 Intl.NumberFormat ([locales [, options]]) (ECMA-402 2.0)
+ // 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
+ JSValue newTarget = state->newTarget();
+ if (newTarget.isUndefined())
+ newTarget = state->callee();
+
+ // 2. Let numberFormat be OrdinaryCreateFromConstructor(newTarget, %NumberFormatPrototype%).
+ VM& vm = state->vm();
+ IntlNumberFormat* numberFormat = IntlNumberFormat::create(vm, jsCast<IntlNumberFormatConstructor*>(state->callee()));
+ if (numberFormat && !jsDynamicCast<IntlNumberFormatConstructor*>(newTarget)) {
+ JSValue proto = asObject(newTarget)->getDirect(vm, vm.propertyNames->prototype);
+ asObject(numberFormat)->setPrototypeWithCycleCheck(state, proto);
+ }
+
+ // 3. ReturnIfAbrupt(numberFormat).
+ ASSERT(numberFormat);
+
+ // 4. Return InitializeNumberFormat(numberFormat, locales, options).
+ JSValue locales = state->argument(0);
+ JSValue options = state->argument(1);
+ numberFormat->initializeNumberFormat(*state, locales, options);
+ return JSValue::encode(numberFormat);
+}
+
+static EncodedJSValue JSC_HOST_CALL callIntlNumberFormat(ExecState* state)
+{
+ // 11.1.2 Intl.NumberFormat ([locales [, options]]) (ECMA-402 2.0)
+ // 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
+ // NewTarget is always undefined when called as a function.
+
+ // 2. Let numberFormat be OrdinaryCreateFromConstructor(newTarget, %NumberFormatPrototype%).
+ VM& vm = state->vm();
+ IntlNumberFormat* numberFormat = IntlNumberFormat::create(vm, jsCast<IntlNumberFormatConstructor*>(state->callee()));
+
+ // 3. ReturnIfAbrupt(numberFormat).
+ ASSERT(numberFormat);
+
+ // 4. Return InitializeNumberFormat(numberFormat, locales, options).
+ JSValue locales = state->argument(0);
+ JSValue options = state->argument(1);
+ numberFormat->initializeNumberFormat(*state, locales, options);
+ return JSValue::encode(numberFormat);
+}
+
+ConstructType IntlNumberFormatConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructIntlNumberFormat;
+ return ConstructTypeHost;
+}
+
+CallType IntlNumberFormatConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callIntlNumberFormat;
+ return CallTypeHost;
+}
+
+bool IntlNumberFormatConstructor::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<InternalFunction>(state, numberFormatConstructorTable, jsCast<IntlNumberFormatConstructor*>(object), propertyName, slot);
+}
+
+EncodedJSValue JSC_HOST_CALL IntlNumberFormatConstructorFuncSupportedLocalesOf(ExecState* state)
+{
+ // 11.2.2 Intl.NumberFormat.supportedLocalesOf(locales [, options]) (ECMA-402 2.0)
+
+ // 1. Let availableLocales be %NumberFormat%.[[availableLocales]].
+ JSGlobalObject* globalObject = state->callee()->globalObject();
+ const HashSet<String> availableLocales = globalObject->intlNumberFormatAvailableLocales();
+
+ // 2. Let requestedLocales be CanonicalizeLocaleList(locales).
+ Vector<String> requestedLocales = canonicalizeLocaleList(*state, state->argument(0));
+ if (state->hadException())
+ return JSValue::encode(jsUndefined());
+
+ // 3. Return SupportedLocales(availableLocales, requestedLocales, options).
+ return JSValue::encode(supportedLocales(*state, availableLocales, requestedLocales, state->argument(1)));
+}
+
+void IntlNumberFormatConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ IntlNumberFormatConstructor* thisObject = jsCast<IntlNumberFormatConstructor*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_numberFormatStructure);
+}
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.h b/Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.h
new file mode 100644
index 000000000..3f7c26ab1
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlNumberFormatConstructor.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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.
+ */
+
+#ifndef IntlNumberFormatConstructor_h
+#define IntlNumberFormatConstructor_h
+
+#if ENABLE(INTL)
+
+#include "InternalFunction.h"
+
+namespace JSC {
+
+class IntlNumberFormat;
+class IntlNumberFormatPrototype;
+
+class IntlNumberFormatConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static IntlNumberFormatConstructor* create(VM&, Structure*, IntlNumberFormatPrototype*, Structure*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+ Structure* numberFormatStructure() const { return m_numberFormatStructure.get(); }
+
+protected:
+ void finishCreation(VM&, IntlNumberFormatPrototype*, Structure*);
+
+private:
+ IntlNumberFormatConstructor(VM&, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ WriteBarrier<Structure> m_numberFormatStructure;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
+
+#endif // IntlNumberFormatConstructor_h
diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp b/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp
new file mode 100644
index 000000000..02a7530c6
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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 "IntlNumberFormatPrototype.h"
+
+#if ENABLE(INTL)
+
+#include "Error.h"
+#include "IntlNumberFormat.h"
+#include "JSBoundFunction.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSObject.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL IntlNumberFormatPrototypeGetterFormat(ExecState*);
+static EncodedJSValue JSC_HOST_CALL IntlNumberFormatPrototypeFuncResolvedOptions(ExecState*);
+
+}
+
+#include "IntlNumberFormatPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo IntlNumberFormatPrototype::s_info = { "Object", &IntlNumberFormat::s_info, &numberFormatPrototypeTable, CREATE_METHOD_TABLE(IntlNumberFormatPrototype) };
+
+/* Source for IntlNumberFormatPrototype.lut.h
+@begin numberFormatPrototypeTable
+ format IntlNumberFormatPrototypeGetterFormat DontEnum|Accessor
+ resolvedOptions IntlNumberFormatPrototypeFuncResolvedOptions DontEnum|Function 0
+@end
+*/
+
+IntlNumberFormatPrototype* IntlNumberFormatPrototype::create(VM& vm, JSGlobalObject*, Structure* structure)
+{
+ IntlNumberFormatPrototype* object = new (NotNull, allocateCell<IntlNumberFormatPrototype>(vm.heap)) IntlNumberFormatPrototype(vm, structure);
+ object->finishCreation(vm, structure);
+ return object;
+}
+
+Structure* IntlNumberFormatPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+IntlNumberFormatPrototype::IntlNumberFormatPrototype(VM& vm, Structure* structure)
+ : IntlNumberFormat(vm, structure)
+{
+}
+
+void IntlNumberFormatPrototype::finishCreation(VM& vm, Structure*)
+{
+ Base::finishCreation(vm);
+}
+
+bool IntlNumberFormatPrototype::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<JSObject>(state, numberFormatPrototypeTable, jsCast<IntlNumberFormatPrototype*>(object), propertyName, slot);
+}
+
+EncodedJSValue JSC_HOST_CALL IntlNumberFormatPrototypeGetterFormat(ExecState* state)
+{
+ // 11.3.3 Intl.NumberFormat.prototype.format (ECMA-402 2.0)
+ // 1. Let nf be this NumberFormat object.
+ IntlNumberFormat* nf = jsDynamicCast<IntlNumberFormat*>(state->thisValue());
+ if (!nf)
+ return JSValue::encode(throwTypeError(state, ASCIILiteral("Intl.NumberFormat.prototype.format called on value that's not an object initialized as a NumberFormat")));
+
+ JSBoundFunction* boundFormat = nf->boundFormat();
+ // 2. If nf.[[boundFormat]] is undefined,
+ if (!boundFormat) {
+ VM& vm = state->vm();
+ JSGlobalObject* globalObject = nf->globalObject();
+ // a. Let F be a new built-in function object as defined in 11.3.4.
+ // b. The value of F’s length property is 1.
+ JSFunction* targetObject = JSFunction::create(vm, globalObject, 1, ASCIILiteral("format"), IntlNumberFormatFuncFormatNumber, NoIntrinsic);
+ JSArray* boundArgs = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), 0);
+ if (!boundArgs)
+ return JSValue::encode(throwOutOfMemoryError(state));
+
+ // c. Let bf be BoundFunctionCreate(F, «this value»).
+ boundFormat = JSBoundFunction::create(vm, globalObject, targetObject, nf, boundArgs, 1, ASCIILiteral("format"));
+ // d. Set nf.[[boundFormat]] to bf.
+ nf->setBoundFormat(vm, boundFormat);
+ }
+ // 3. Return nf.[[boundFormat]].
+ return JSValue::encode(boundFormat);
+}
+
+EncodedJSValue JSC_HOST_CALL IntlNumberFormatPrototypeFuncResolvedOptions(ExecState* state)
+{
+ // 11.3.5 Intl.NumberFormat.prototype.resolvedOptions() (ECMA-402 2.0)
+ IntlNumberFormat* numberFormat = jsDynamicCast<IntlNumberFormat*>(state->thisValue());
+ if (!numberFormat)
+ return JSValue::encode(throwTypeError(state, ASCIILiteral("Intl.NumberFormat.prototype.resolvedOptions called on value that's not an object initialized as a NumberFormat")));
+
+ return JSValue::encode(numberFormat->resolvedOptions(*state));
+}
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.h b/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.h
new file mode 100644
index 000000000..78bc051fd
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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.
+ */
+
+#ifndef IntlNumberFormatPrototype_h
+#define IntlNumberFormatPrototype_h
+
+#if ENABLE(INTL)
+
+#include "IntlNumberFormat.h"
+#include "JSObject.h"
+
+namespace JSC {
+
+class IntlNumberFormatPrototype : public IntlNumberFormat {
+public:
+ typedef IntlNumberFormat Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static IntlNumberFormatPrototype* create(VM&, JSGlobalObject*, Structure*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+protected:
+ void finishCreation(VM&, Structure*);
+
+private:
+ IntlNumberFormatPrototype(VM&, Structure*);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+};
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
+
+#endif // IntlNumberFormatPrototype_h
diff --git a/Source/JavaScriptCore/runtime/IntlObject.cpp b/Source/JavaScriptCore/runtime/IntlObject.cpp
new file mode 100644
index 000000000..395a0430c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlObject.cpp
@@ -0,0 +1,998 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ * Copyright (C) 2015 Sukolsak Sakshuwong (sukolsak@gmail.com)
+ *
+ * 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 "IntlObject.h"
+
+#if ENABLE(INTL)
+
+#include "Error.h"
+#include "FunctionPrototype.h"
+#include "IntlCollator.h"
+#include "IntlCollatorConstructor.h"
+#include "IntlCollatorPrototype.h"
+#include "IntlDateTimeFormat.h"
+#include "IntlDateTimeFormatConstructor.h"
+#include "IntlDateTimeFormatPrototype.h"
+#include "IntlNumberFormat.h"
+#include "IntlNumberFormatConstructor.h"
+#include "IntlNumberFormatPrototype.h"
+#include "JSCInlines.h"
+#include "JSCJSValueInlines.h"
+#include "Lookup.h"
+#include "ObjectPrototype.h"
+#include <unicode/uloc.h>
+#include <unicode/unumsys.h>
+#include <wtf/Assertions.h>
+#include <wtf/NeverDestroyed.h>
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IntlObject);
+
+}
+
+namespace JSC {
+
+struct MatcherResult {
+ String locale;
+ String extension;
+ size_t extensionIndex;
+};
+
+const ClassInfo IntlObject::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(IntlObject) };
+
+IntlObject::IntlObject(VM& vm, Structure* structure)
+ : JSNonFinalObject(vm, structure)
+{
+}
+
+IntlObject* IntlObject::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+{
+ IntlObject* object = new (NotNull, allocateCell<IntlObject>(vm.heap)) IntlObject(vm, structure);
+ object->finishCreation(vm, globalObject);
+ return object;
+}
+
+void IntlObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+
+ // Set up Collator.
+ IntlCollatorPrototype* collatorPrototype = IntlCollatorPrototype::create(vm, globalObject, IntlCollatorPrototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
+ Structure* collatorStructure = IntlCollator::createStructure(vm, globalObject, collatorPrototype);
+ IntlCollatorConstructor* collatorConstructor = IntlCollatorConstructor::create(vm, IntlCollatorConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), collatorPrototype, collatorStructure);
+
+ collatorPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, collatorConstructor, DontEnum);
+
+ // Set up NumberFormat.
+ IntlNumberFormatPrototype* numberFormatPrototype = IntlNumberFormatPrototype::create(vm, globalObject, IntlNumberFormatPrototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
+ Structure* numberFormatStructure = IntlNumberFormat::createStructure(vm, globalObject, numberFormatPrototype);
+ IntlNumberFormatConstructor* numberFormatConstructor = IntlNumberFormatConstructor::create(vm, IntlNumberFormatConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), numberFormatPrototype, numberFormatStructure);
+
+ numberFormatPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, numberFormatConstructor, DontEnum);
+
+ // Set up DateTimeFormat.
+ IntlDateTimeFormatPrototype* dateTimeFormatPrototype = IntlDateTimeFormatPrototype::create(vm, globalObject, IntlDateTimeFormatPrototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
+ Structure* dateTimeFormatStructure = IntlDateTimeFormat::createStructure(vm, globalObject, dateTimeFormatPrototype);
+ IntlDateTimeFormatConstructor* dateTimeFormatConstructor = IntlDateTimeFormatConstructor::create(vm, IntlDateTimeFormatConstructor::createStructure(vm, globalObject, globalObject->functionPrototype()), dateTimeFormatPrototype, dateTimeFormatStructure);
+
+ dateTimeFormatPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, dateTimeFormatConstructor, DontEnum);
+
+ // 8.1 Properties of the Intl Object (ECMA-402 2.0)
+ putDirectWithoutTransition(vm, vm.propertyNames->Collator, collatorConstructor, DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->NumberFormat, numberFormatConstructor, DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->DateTimeFormat, dateTimeFormatConstructor, DontEnum);
+}
+
+Structure* IntlObject::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+String defaultLocale()
+{
+ // 6.2.4 DefaultLocale ()
+ String locale = uloc_getDefault();
+ convertICULocaleToBCP47LanguageTag(locale);
+ return locale;
+}
+
+void convertICULocaleToBCP47LanguageTag(String& locale)
+{
+ locale.replace('_', '-');
+}
+
+bool intlBooleanOption(ExecState& state, JSValue options, PropertyName property, bool& usesFallback)
+{
+ // 9.2.9 GetOption (options, property, type, values, fallback)
+ // For type="boolean". values is always undefined.
+
+ // 1. Let opts be ToObject(options).
+ JSObject* opts = options.toObject(&state);
+
+ // 2. ReturnIfAbrupt(opts).
+ if (state.hadException())
+ return false;
+
+ // 3. Let value be Get(opts, property).
+ JSValue value = opts->get(&state, property);
+
+ // 4. ReturnIfAbrupt(value).
+ if (state.hadException())
+ return false;
+
+ // 5. If value is not undefined, then
+ if (!value.isUndefined()) {
+ // a. Assert: type is "boolean" or "string".
+ // Function dedicated to "boolean".
+
+ // b. If type is "boolean", then
+ // i. Let value be ToBoolean(value).
+ bool booleanValue = value.toBoolean(&state);
+
+ // e. Return value.
+ usesFallback = false;
+ return booleanValue;
+ }
+
+ // 6. Else return fallback.
+ // Because fallback can be undefined, we let the caller handle it instead.
+ usesFallback = true;
+ return false;
+}
+
+String intlStringOption(ExecState& state, JSValue options, PropertyName property, std::initializer_list<const char*> values, const char* notFound, const char* fallback)
+{
+ // 9.2.9 GetOption (options, property, type, values, fallback)
+ // For type="string".
+
+ // 1. Let opts be ToObject(options).
+ JSObject* opts = options.toObject(&state);
+
+ // 2. ReturnIfAbrupt(opts).
+ if (state.hadException())
+ return { };
+
+ // 3. Let value be Get(opts, property).
+ JSValue value = opts->get(&state, property);
+
+ // 4. ReturnIfAbrupt(value).
+ if (state.hadException())
+ return { };
+
+ // 5. If value is not undefined, then
+ if (!value.isUndefined()) {
+ // a. Assert: type is "boolean" or "string".
+ // Function dedicated to "string".
+
+ // c. If type is "string", then
+ // i. Let value be ToString(value).
+ String stringValue = value.toWTFString(&state);
+
+ // ii. ReturnIfAbrupt(value).
+ if (state.hadException())
+ return { };
+
+ // d. If values is not undefined, then
+ // i. If values does not contain an element equal to value, throw a RangeError exception.
+ if (values.size() && std::find(values.begin(), values.end(), stringValue) == values.end()) {
+ state.vm().throwException(&state, createRangeError(&state, notFound));
+ return { };
+ }
+
+ // e. Return value.
+ return stringValue;
+ }
+
+ // 6. Else return fallback.
+ return fallback;
+}
+
+unsigned intlNumberOption(ExecState& state, JSValue options, PropertyName property, unsigned minimum, unsigned maximum, unsigned fallback)
+{
+ // 9.2.9 GetNumberOption (options, property, minimum, maximum, fallback) (ECMA-402 2.0)
+ // 1. Let opts be ToObject(options).
+ JSObject* opts = options.toObject(&state);
+
+ // 2. ReturnIfAbrupt(opts).
+ if (state.hadException())
+ return 0;
+
+ // 3. Let value be Get(opts, property).
+ JSValue value = opts->get(&state, property);
+
+ // 4. ReturnIfAbrupt(value).
+ if (state.hadException())
+ return 0;
+
+ // 5. If value is not undefined, then
+ if (!value.isUndefined()) {
+ // a. Let value be ToNumber(value).
+ double doubleValue = value.toNumber(&state);
+ // b. ReturnIfAbrupt(value).
+ if (state.hadException())
+ return 0;
+ // 1. If value is NaN or less than minimum or greater than maximum, throw a RangeError exception.
+ if (!(doubleValue >= minimum && doubleValue <= maximum)) {
+ state.vm().throwException(&state, createRangeError(&state, *property.publicName() + " is out of range"));
+ return 0;
+ }
+
+ // c. Return floor(value).
+ return static_cast<unsigned>(doubleValue);
+ }
+
+ // 6. Else return fallback.
+ return fallback;
+}
+
+static String privateUseLangTag(const Vector<String>& parts, size_t startIndex)
+{
+ size_t numParts = parts.size();
+ size_t currentIndex = startIndex;
+
+ // Check for privateuse.
+ // privateuse = "x" 1*("-" (2*8alphanum))
+ StringBuilder privateuse;
+ while (currentIndex < numParts) {
+ const String& singleton = parts[currentIndex];
+ unsigned singletonLength = singleton.length();
+ bool isValid = (singletonLength == 1 && (singleton == "x" || singleton == "X"));
+ if (!isValid)
+ break;
+
+ if (currentIndex != startIndex)
+ privateuse.append('-');
+
+ ++currentIndex;
+ unsigned numExtParts = 0;
+ privateuse.append('x');
+ while (currentIndex < numParts) {
+ const String& extPart = parts[currentIndex];
+ unsigned extPartLength = extPart.length();
+
+ bool isValid = (extPartLength >= 2 && extPartLength <= 8 && extPart.isAllSpecialCharacters<isASCIIAlphanumeric>());
+ if (!isValid)
+ break;
+
+ ++currentIndex;
+ ++numExtParts;
+ privateuse.append('-');
+ privateuse.append(extPart.convertToASCIILowercase());
+ }
+
+ // Requires at least one production.
+ if (!numExtParts)
+ return String();
+ }
+
+ // Leftovers makes it invalid.
+ if (currentIndex < numParts)
+ return String();
+
+ return privateuse.toString();
+}
+
+static String canonicalLangTag(const Vector<String>& parts)
+{
+ ASSERT(!parts.isEmpty());
+
+ // Follows the grammar at https://www.rfc-editor.org/rfc/bcp/bcp47.txt
+ // langtag = language ["-" script] ["-" region] *("-" variant) *("-" extension) ["-" privateuse]
+
+ size_t numParts = parts.size();
+ // Check for language.
+ // language = 2*3ALPHA ["-" extlang] / 4ALPHA / 5*8ALPHA
+ size_t currentIndex = 0;
+ const String& language = parts[currentIndex];
+ unsigned languageLength = language.length();
+ bool canHaveExtlang = languageLength >= 2 && languageLength <= 3;
+ bool isValidLanguage = languageLength >= 2 && languageLength <= 8 && language.isAllSpecialCharacters<isASCIIAlpha>();
+ if (!isValidLanguage)
+ return String();
+
+ ++currentIndex;
+ StringBuilder canonical;
+ canonical.append(language.convertToASCIILowercase());
+
+ // Check for extlang.
+ // extlang = 3ALPHA *2("-" 3ALPHA)
+ if (canHaveExtlang) {
+ for (unsigned times = 0; times < 3 && currentIndex < numParts; ++times) {
+ const String& extlang = parts[currentIndex];
+ unsigned extlangLength = extlang.length();
+ if (extlangLength == 3 && extlang.isAllSpecialCharacters<isASCIIAlpha>()) {
+ ++currentIndex;
+ canonical.append('-');
+ canonical.append(extlang.convertToASCIILowercase());
+ } else
+ break;
+ }
+ }
+
+ // Check for script.
+ // script = 4ALPHA
+ if (currentIndex < numParts) {
+ const String& script = parts[currentIndex];
+ unsigned scriptLength = script.length();
+ if (scriptLength == 4 && script.isAllSpecialCharacters<isASCIIAlpha>()) {
+ ++currentIndex;
+ canonical.append('-');
+ canonical.append(toASCIIUpper(script[0]));
+ canonical.append(script.substring(1, 3).convertToASCIILowercase());
+ }
+ }
+
+ // Check for region.
+ // region = 2ALPHA / 3DIGIT
+ if (currentIndex < numParts) {
+ const String& region = parts[currentIndex];
+ unsigned regionLength = region.length();
+ bool isValidRegion = (
+ (regionLength == 2 && region.isAllSpecialCharacters<isASCIIAlpha>())
+ || (regionLength == 3 && region.isAllSpecialCharacters<isASCIIDigit>())
+ );
+ if (isValidRegion) {
+ ++currentIndex;
+ canonical.append('-');
+ canonical.append(region.convertToASCIIUppercase());
+ }
+ }
+
+ // Check for variant.
+ // variant = 5*8alphanum / (DIGIT 3alphanum)
+ HashSet<String> subtags;
+ while (currentIndex < numParts) {
+ const String& variant = parts[currentIndex];
+ unsigned variantLength = variant.length();
+ bool isValidVariant = (
+ (variantLength >= 5 && variantLength <= 8 && variant.isAllSpecialCharacters<isASCIIAlphanumeric>())
+ || (variantLength == 4 && isASCIIDigit(variant[0]) && variant.substring(1, 3).isAllSpecialCharacters<isASCIIAlphanumeric>())
+ );
+ if (!isValidVariant)
+ break;
+
+ // Cannot include duplicate subtags (case insensitive).
+ String lowerVariant = variant.convertToASCIILowercase();
+ if (!subtags.add(lowerVariant).isNewEntry)
+ return String();
+
+ ++currentIndex;
+
+ // Reordering variant subtags is not required in the spec.
+ canonical.append('-');
+ canonical.append(lowerVariant);
+ }
+
+ // Check for extension.
+ // extension = singleton 1*("-" (2*8alphanum))
+ // singleton = alphanum except x or X
+ subtags.clear();
+ Vector<String> extensions;
+ while (currentIndex < numParts) {
+ const String& possibleSingleton = parts[currentIndex];
+ unsigned singletonLength = possibleSingleton.length();
+ bool isValidSingleton = (singletonLength == 1 && possibleSingleton != "x" && possibleSingleton != "X" && isASCIIAlphanumeric(possibleSingleton[0]));
+ if (!isValidSingleton)
+ break;
+
+ // Cannot include duplicate singleton (case insensitive).
+ String singleton = possibleSingleton.convertToASCIILowercase();
+ if (!subtags.add(singleton).isNewEntry)
+ return String();
+
+ ++currentIndex;
+ int numExtParts = 0;
+ StringBuilder extension;
+ extension.append(singleton);
+ while (currentIndex < numParts) {
+ const String& extPart = parts[currentIndex];
+ unsigned extPartLength = extPart.length();
+
+ bool isValid = (extPartLength >= 2 && extPartLength <= 8 && extPart.isAllSpecialCharacters<isASCIIAlphanumeric>());
+ if (!isValid)
+ break;
+
+ ++currentIndex;
+ ++numExtParts;
+ extension.append('-');
+ extension.append(extPart.convertToASCIILowercase());
+ }
+
+ // Requires at least one production.
+ if (!numExtParts)
+ return String();
+
+ extensions.append(extension.toString());
+ }
+
+ // Add extensions to canonical sorted by singleton.
+ std::sort(
+ extensions.begin(),
+ extensions.end(),
+ [] (const String& a, const String& b) -> bool {
+ return a[0] < b[0];
+ }
+ );
+ size_t numExtenstions = extensions.size();
+ for (size_t i = 0; i < numExtenstions; ++i) {
+ canonical.append('-');
+ canonical.append(extensions[i]);
+ }
+
+ // Check for privateuse.
+ if (currentIndex < numParts) {
+ String privateuse = privateUseLangTag(parts, currentIndex);
+ if (privateuse.isNull())
+ return String();
+ canonical.append('-');
+ canonical.append(privateuse);
+ }
+
+ // FIXME: Replace subtags with their preferred values.
+
+ return canonical.toString();
+}
+
+static String grandfatheredLangTag(const String& locale)
+{
+ // grandfathered = irregular / regular
+ // FIXME: convert to a compile time hash table if this is causing performance issues.
+ HashMap<String, String> tagMap = {
+ // Irregular.
+ { ASCIILiteral("en-gb-oed"), ASCIILiteral("en-GB-oed") },
+ { ASCIILiteral("i-ami"), ASCIILiteral("ami") },
+ { ASCIILiteral("i-bnn"), ASCIILiteral("bnn") },
+ { ASCIILiteral("i-default"), ASCIILiteral("i-default") },
+ { ASCIILiteral("i-enochian"), ASCIILiteral("i-enochian") },
+ { ASCIILiteral("i-hak"), ASCIILiteral("hak") },
+ { ASCIILiteral("i-klingon"), ASCIILiteral("tlh") },
+ { ASCIILiteral("i-lux"), ASCIILiteral("lb") },
+ { ASCIILiteral("i-mingo"), ASCIILiteral("i-mingo") },
+ { ASCIILiteral("i-navajo"), ASCIILiteral("nv") },
+ { ASCIILiteral("i-pwn"), ASCIILiteral("pwn") },
+ { ASCIILiteral("i-tao"), ASCIILiteral("tao") },
+ { ASCIILiteral("i-tay"), ASCIILiteral("tay") },
+ { ASCIILiteral("i-tsu"), ASCIILiteral("tsu") },
+ { ASCIILiteral("sgn-be-fr"), ASCIILiteral("sfb") },
+ { ASCIILiteral("sgn-be-nl"), ASCIILiteral("vgt") },
+ { ASCIILiteral("sgn-ch-de"), ASCIILiteral("sgg") },
+ // Regular.
+ { ASCIILiteral("art-lojban"), ASCIILiteral("jbo") },
+ { ASCIILiteral("cel-gaulish"), ASCIILiteral("cel-gaulish") },
+ { ASCIILiteral("no-bok"), ASCIILiteral("nb") },
+ { ASCIILiteral("no-nyn"), ASCIILiteral("nn") },
+ { ASCIILiteral("zh-guoyu"), ASCIILiteral("cmn") },
+ { ASCIILiteral("zh-hakka"), ASCIILiteral("hak") },
+ { ASCIILiteral("zh-min"), ASCIILiteral("zh-min") },
+ { ASCIILiteral("zh-min-nan"), ASCIILiteral("nan") },
+ { ASCIILiteral("zh-xiang"), ASCIILiteral("hsn") }
+ };
+
+ return tagMap.get(locale.convertToASCIILowercase());
+}
+
+static String canonicalizeLanguageTag(const String& locale)
+{
+ // 6.2.2 IsStructurallyValidLanguageTag (locale)
+ // 6.2.3 CanonicalizeLanguageTag (locale)
+ // These are done one after another in CanonicalizeLocaleList, so they are combined here to reduce duplication.
+ // https://www.rfc-editor.org/rfc/bcp/bcp47.txt
+
+ // Language-Tag = langtag / privateuse / grandfathered
+ String grandfather = grandfatheredLangTag(locale);
+ if (!grandfather.isNull())
+ return grandfather;
+
+ // FIXME: Replace redundant tags [RFC4647].
+
+ Vector<String> parts;
+ locale.split('-', true, parts);
+ if (!parts.isEmpty()) {
+ String langtag = canonicalLangTag(parts);
+ if (!langtag.isNull())
+ return langtag;
+
+ String privateuse = privateUseLangTag(parts, 0);
+ if (!privateuse.isNull())
+ return privateuse;
+ }
+
+ return String();
+}
+
+Vector<String> canonicalizeLocaleList(ExecState& state, JSValue locales)
+{
+ // 9.2.1 CanonicalizeLocaleList (locales)
+ VM& vm = state.vm();
+ JSGlobalObject* globalObject = state.callee()->globalObject();
+ Vector<String> seen;
+
+ // 1. If locales is undefined, then a. Return a new empty List.
+ if (locales.isUndefined())
+ return seen;
+
+ // 2. Let seen be an empty List.
+ // Done before to also return in step 1, if needed.
+
+ // 3. If Type(locales) is String, then
+ JSObject* localesObject;
+ if (locales.isString()) {
+ // a. Let aLocales be CreateArrayFromList(«locales»).
+ JSArray* localesArray = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 1);
+ localesArray->initializeIndex(vm, 0, locales);
+ // 4. Let O be ToObject(aLocales).
+ localesObject = localesArray;
+ } else {
+ // 4. Let O be ToObject(aLocales).
+ localesObject = locales.toObject(&state);
+ }
+
+ // 5. ReturnIfAbrupt(O).
+ if (state.hadException())
+ return Vector<String>();
+
+ // 6. Let len be ToLength(Get(O, "length")).
+ JSValue lengthProperty = localesObject->get(&state, vm.propertyNames->length);
+ if (state.hadException())
+ return Vector<String>();
+
+ double length = lengthProperty.toLength(&state);
+ if (state.hadException())
+ return Vector<String>();
+
+ // Keep track of locales that have been added to the list.
+ HashSet<String> seenSet;
+
+ // 7. Let k be 0.
+ // 8. Repeat, while k < len
+ for (double k = 0; k < length; ++k) {
+ // a. Let Pk be ToString(k).
+ // Not needed because hasProperty and get take an int for numeric key.
+
+ // b. Let kPresent be HasProperty(O, Pk).
+ bool kPresent = localesObject->hasProperty(&state, k);
+
+ // c. ReturnIfAbrupt(kPresent).
+ if (state.hadException())
+ return Vector<String>();
+
+ // d. If kPresent is true, then
+ if (kPresent) {
+ // i. Let kValue be Get(O, Pk).
+ JSValue kValue = localesObject->get(&state, k);
+
+ // ii. ReturnIfAbrupt(kValue).
+ if (state.hadException())
+ return Vector<String>();
+
+ // iii. If Type(kValue) is not String or Object, throw a TypeError exception.
+ if (!kValue.isString() && !kValue.isObject()) {
+ throwTypeError(&state, ASCIILiteral("locale value must be a string or object"));
+ return Vector<String>();
+ }
+
+ // iv. Let tag be ToString(kValue).
+ JSString* tag = kValue.toString(&state);
+
+ // v. ReturnIfAbrupt(tag).
+ if (state.hadException())
+ return Vector<String>();
+
+ // vi. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception.
+ // vii. Let canonicalizedTag be CanonicalizeLanguageTag(tag).
+ String canonicalizedTag = canonicalizeLanguageTag(tag->value(&state));
+ if (canonicalizedTag.isNull()) {
+ state.vm().throwException(&state, createRangeError(&state, String::format("invalid language tag: %s", tag->value(&state).utf8().data())));
+ return Vector<String>();
+ }
+
+ // viii. If canonicalizedTag is not an element of seen, append canonicalizedTag as the last element of seen.
+ if (seenSet.add(canonicalizedTag).isNewEntry)
+ seen.append(canonicalizedTag);
+ }
+ // e. Increase k by 1.
+ }
+
+ return seen;
+}
+
+String bestAvailableLocale(const HashSet<String>& availableLocales, const String& locale)
+{
+ // 9.2.2 BestAvailableLocale (availableLocales, locale)
+ // 1. Let candidate be locale.
+ String candidate = locale;
+
+ // 2. Repeat
+ while (!candidate.isEmpty()) {
+ // a. If availableLocales contains an element equal to candidate, then return candidate.
+ if (availableLocales.contains(candidate))
+ return candidate;
+
+ // b. Let pos be the character index of the last occurrence of "-" (U+002D) within candidate. If that character does not occur, return undefined.
+ size_t pos = candidate.reverseFind('-');
+ if (pos == notFound)
+ return String();
+
+ // c. If pos ≥ 2 and the character "-" occurs at index pos-2 of candidate, then decrease pos by 2.
+ if (pos >= 2 && candidate[pos - 2] == '-')
+ pos -= 2;
+
+ // d. Let candidate be the substring of candidate from position 0, inclusive, to position pos, exclusive.
+ candidate = candidate.substring(0, pos);
+ }
+
+ return String();
+}
+
+String removeUnicodeLocaleExtension(const String& locale)
+{
+ Vector<String> parts;
+ locale.split('-', parts);
+ StringBuilder builder;
+ size_t partsSize = parts.size();
+ if (partsSize > 0)
+ builder.append(parts[0]);
+ for (size_t p = 1; p < partsSize; ++p) {
+ if (parts[p] == "u") {
+ // Skip the u- and anything that follows until another singleton.
+ // While the next part is part of the unicode extension, skip it.
+ while (p + 1 < partsSize && parts[p + 1].length() > 1)
+ ++p;
+ } else {
+ builder.append('-');
+ builder.append(parts[p]);
+ }
+ }
+ return builder.toString();
+}
+
+static MatcherResult lookupMatcher(const HashSet<String>& availableLocales, const Vector<String>& requestedLocales)
+{
+ // 9.2.3 LookupMatcher (availableLocales, requestedLocales) (ECMA-402 2.0)
+ String locale;
+ String noExtensionsLocale;
+ String availableLocale;
+ for (size_t i = 0; i < requestedLocales.size() && availableLocale.isNull(); ++i) {
+ locale = requestedLocales[i];
+ noExtensionsLocale = removeUnicodeLocaleExtension(locale);
+ availableLocale = bestAvailableLocale(availableLocales, noExtensionsLocale);
+ }
+
+ MatcherResult result;
+ if (!availableLocale.isNull()) {
+ result.locale = availableLocale;
+ if (locale != noExtensionsLocale) {
+ // i. Let extension be the String value consisting of the first substring of locale that is a Unicode locale extension sequence.
+ // ii. Let extensionIndex be the character position of the initial "-" extension sequence within locale.
+ size_t extensionIndex = locale.find("-u-");
+ RELEASE_ASSERT(extensionIndex != notFound);
+
+ size_t extensionLength = locale.length() - extensionIndex;
+ size_t end = extensionIndex + 3;
+ while (end < locale.length()) {
+ end = locale.find('-', end);
+ if (end == notFound)
+ break;
+ if (end + 2 < locale.length() && locale[end + 2] == '-') {
+ extensionLength = end - extensionIndex;
+ break;
+ }
+ end++;
+ }
+ result.extension = locale.substring(extensionIndex, extensionLength);
+ result.extensionIndex = extensionIndex;
+ }
+ } else
+ result.locale = defaultLocale();
+ return result;
+}
+
+static MatcherResult bestFitMatcher(const HashSet<String>& availableLocales, const Vector<String>& requestedLocales)
+{
+ // 9.2.4 BestFitMatcher (availableLocales, requestedLocales) (ECMA-402 2.0)
+ // FIXME: Implement something better than lookup.
+ return lookupMatcher(availableLocales, requestedLocales);
+}
+
+HashMap<String, String> resolveLocale(const HashSet<String>& availableLocales, const Vector<String>& requestedLocales, const HashMap<String, String>& options, const char* const relevantExtensionKeys[], size_t relevantExtensionKeyCount, Vector<String> (*localeData)(const String&, size_t))
+{
+ // 9.2.5 ResolveLocale (availableLocales, requestedLocales, options, relevantExtensionKeys, localeData) (ECMA-402 2.0)
+ // 1. Let matcher be the value of options.[[localeMatcher]].
+ const String& matcher = options.get(ASCIILiteral("localeMatcher"));
+
+ // 2. If matcher is "lookup", then
+ MatcherResult (*matcherOperation)(const HashSet<String>&, const Vector<String>&);
+ if (matcher == "lookup") {
+ // a. Let MatcherOperation be the abstract operation LookupMatcher.
+ matcherOperation = lookupMatcher;
+ } else { // 3. Else
+ // a. Let MatcherOperation be the abstract operation BestFitMatcher.
+ matcherOperation = bestFitMatcher;
+ }
+
+ // 4. Let r be MatcherOperation(availableLocales, requestedLocales).
+ MatcherResult matcherResult = matcherOperation(availableLocales, requestedLocales);
+
+ // 5. Let foundLocale be the value of r.[[locale]].
+ String foundLocale = matcherResult.locale;
+
+ // 6. If r has an [[extension]] field, then
+ Vector<String> extensionSubtags;
+ if (!matcherResult.extension.isNull()) {
+ // a. Let extension be the value of r.[[extension]].
+ // b. Let extensionIndex be the value of r.[[extensionIndex]].
+ // c. Let extensionSubtags be Call(%StringProto_split%, extension, «"-"») .
+ // d. Let extensionSubtagsLength be Get(CreateArrayFromList(extensionSubtags), "length").
+ matcherResult.extension.split('-', extensionSubtags);
+ }
+
+ // 7. Let result be a new Record.
+ HashMap<String, String> result;
+
+ // 8. Set result.[[dataLocale]] to foundLocale.
+ result.add(ASCIILiteral("dataLocale"), foundLocale);
+
+ // 9. Let supportedExtension be "-u".
+ String supportedExtension = ASCIILiteral("-u");
+
+ // 10. Let k be 0.
+ // 11. Let rExtensionKeys be ToObject(CreateArrayFromList(relevantExtensionKeys)).
+ // 12. ReturnIfAbrupt(rExtensionKeys).
+ // 13. Let len be ToLength(Get(rExtensionKeys, "length")).
+ // 14. Repeat while k < len
+ for (size_t keyIndex = 0; keyIndex < relevantExtensionKeyCount; ++keyIndex) {
+ // a. Let key be Get(rExtensionKeys, ToString(k)).
+ // b. ReturnIfAbrupt(key).
+ const char* key = relevantExtensionKeys[keyIndex];
+
+ // c. Let foundLocaleData be Get(localeData, foundLocale).
+ // d. ReturnIfAbrupt(foundLocaleData).
+ // e. Let keyLocaleData be ToObject(Get(foundLocaleData, key)).
+ // f. ReturnIfAbrupt(keyLocaleData).
+ Vector<String> keyLocaleData = localeData(foundLocale, keyIndex);
+
+ // g. Let value be ToString(Get(keyLocaleData, "0")).
+ // h. ReturnIfAbrupt(value).
+ ASSERT(!keyLocaleData.isEmpty());
+ String value = keyLocaleData[0];
+
+ // i. Let supportedExtensionAddition be "".
+ String supportedExtensionAddition;
+
+ // j. If extensionSubtags is not undefined, then
+ if (!extensionSubtags.isEmpty()) {
+ // i. Let keyPos be Call(%ArrayProto_indexOf%, extensionSubtags, «key») .
+ size_t keyPos = extensionSubtags.find(key);
+ // ii. If keyPos != -1, then
+ if (keyPos != notFound) {
+ // FIXME: https://github.com/tc39/ecma402/issues/59
+ // 1. If keyPos + 1 < extensionSubtagsLength and the length of the result of Get(extensionSubtags, ToString(keyPos +1)) is greater than 2, then
+ if (keyPos + 1 < extensionSubtags.size() && extensionSubtags[keyPos + 1].length() > 2) {
+ const String& requestedValue = extensionSubtags[keyPos + 1];
+ if (keyLocaleData.contains(requestedValue)) {
+ value = requestedValue;
+ supportedExtensionAddition = makeString('-', key, '-', value);
+ }
+ } else if (keyLocaleData.contains(static_cast<String>(ASCIILiteral("true")))) {
+ // 2. Else, if the result of Call(%StringProto_includes%, keyLocaleData, «"true"») is true, then
+ value = ASCIILiteral("true");
+ }
+ }
+ }
+
+ // k. If options has a field [[<key>]], then
+ HashMap<String, String>::const_iterator iterator = options.find(key);
+ if (iterator != options.end()) {
+ // i. Let optionsValue be the value of ToString(options.[[<key>]]).
+ // ii. ReturnIfAbrupt(optionsValue).
+ const String& optionsValue = iterator->value;
+ // iii. If the result of Call(%StringProto_includes%, keyLocaleData, «optionsValue») is true, then
+ if (!optionsValue.isNull() && keyLocaleData.contains(optionsValue)) {
+ // 1. If optionsValue is not equal to value, then
+ if (optionsValue != value) {
+ value = optionsValue;
+ supportedExtensionAddition = String();
+ }
+ }
+ }
+
+ // l. Set result.[[<key>]] to value.
+ result.add(key, value);
+
+ // m. Append supportedExtensionAddition to supportedExtension.
+ supportedExtension.append(supportedExtensionAddition);
+
+ // n. Increase k by 1.
+ }
+
+ // 15. If the number of elements in supportedExtension is greater than 2, then
+ if (supportedExtension.length() > 2) {
+ // a. Let preExtension be the substring of foundLocale from position 0, inclusive, to position extensionIndex, exclusive.
+ // b. Let postExtension be the substring of foundLocale from position extensionIndex to the end of the string.
+ // c. Let foundLocale be the concatenation of preExtension, supportedExtension, and postExtension.
+ String preExtension = foundLocale.substring(0, matcherResult.extensionIndex);
+ String postExtension = foundLocale.substring(matcherResult.extensionIndex);
+ foundLocale = preExtension + supportedExtension + postExtension;
+ }
+
+ // 16. Set result.[[locale]] to foundLocale.
+ result.add(ASCIILiteral("locale"), foundLocale);
+
+ // 17. Return result.
+ return result;
+}
+
+static JSArray* lookupSupportedLocales(ExecState& state, const HashSet<String>& availableLocales, const Vector<String>& requestedLocales)
+{
+ // 9.2.6 LookupSupportedLocales (availableLocales, requestedLocales)
+
+ // 1. Let rLocales be CreateArrayFromList(requestedLocales).
+ // Already an array.
+
+ // 2. Let len be ToLength(Get(rLocales, "length")).
+ size_t len = requestedLocales.size();
+
+ // 3. Let subset be an empty List.
+ VM& vm = state.vm();
+ JSGlobalObject* globalObject = state.callee()->globalObject();
+ JSArray* subset = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), 0);
+ if (!subset) {
+ throwOutOfMemoryError(&state);
+ return nullptr;
+ }
+
+ // 4. Let k be 0.
+ // 5. Repeat while k < len
+ for (size_t k = 0; k < len; ++k) {
+ // a. Let Pk be ToString(k).
+ // b. Let locale be Get(rLocales, Pk).
+ // c. ReturnIfAbrupt(locale).
+ const String& locale = requestedLocales[k];
+
+ // d. Let noExtensionsLocale be the String value that is locale with all Unicode locale extension sequences removed.
+ String noExtensionsLocale = removeUnicodeLocaleExtension(locale);
+
+ // e. Let availableLocale be BestAvailableLocale(availableLocales, noExtensionsLocale).
+ String availableLocale = bestAvailableLocale(availableLocales, noExtensionsLocale);
+
+ // f. If availableLocale is not undefined, then append locale to the end of subset.
+ if (!availableLocale.isNull())
+ subset->push(&state, jsString(&state, locale));
+
+ // g. Increment k by 1.
+ }
+
+ // 6. Return subset.
+ return subset;
+}
+
+static JSArray* bestFitSupportedLocales(ExecState& state, const HashSet<String>& availableLocales, const Vector<String>& requestedLocales)
+{
+ // 9.2.7 BestFitSupportedLocales (availableLocales, requestedLocales)
+ // FIXME: Implement something better than lookup.
+ return lookupSupportedLocales(state, availableLocales, requestedLocales);
+}
+
+JSValue supportedLocales(ExecState& state, const HashSet<String>& availableLocales, const Vector<String>& requestedLocales, JSValue options)
+{
+ // 9.2.8 SupportedLocales (availableLocales, requestedLocales, options)
+ VM& vm = state.vm();
+ String matcher;
+
+ // 1. If options is not undefined, then
+ if (!options.isUndefined()) {
+ // a. Let matcher be GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit").
+ matcher = intlStringOption(state, options, vm.propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit");
+ // b. ReturnIfAbrupt(matcher).
+ if (state.hadException())
+ return jsUndefined();
+ } else {
+ // 2. Else, let matcher be "best fit".
+ matcher = ASCIILiteral("best fit");
+ }
+
+ JSArray* supportedLocales;
+ // 3. If matcher is "best fit",
+ if (matcher == "best fit") {
+ // a. Let MatcherOperation be the abstract operation BestFitSupportedLocales.
+ // 5. Let supportedLocales be MatcherOperation(availableLocales, requestedLocales).
+ supportedLocales = bestFitSupportedLocales(state, availableLocales, requestedLocales);
+ } else {
+ // 4. Else
+ // a. Let MatcherOperation be the abstract operation LookupSupportedLocales.
+ // 5. Let supportedLocales be MatcherOperation(availableLocales, requestedLocales).
+ supportedLocales = lookupSupportedLocales(state, availableLocales, requestedLocales);
+ }
+
+ if (state.hadException())
+ return jsUndefined();
+
+ // 6. Let subset be CreateArrayFromList(supportedLocales).
+ // Already an array.
+
+ // 7. Let keys be subset.[[OwnPropertyKeys]]().
+ PropertyNameArray keys(&state, PropertyNameMode::Strings);
+ supportedLocales->getOwnPropertyNames(supportedLocales, &state, keys, EnumerationMode());
+
+ PropertyDescriptor desc;
+ desc.setConfigurable(false);
+ desc.setWritable(false);
+
+ // 8. Repeat for each element P of keys in List order,
+ size_t len = keys.size();
+ for (size_t i = 0; i < len; ++i) {
+ // a. Let desc be PropertyDescriptor { [[Configurable]]: false, [[Writable]]: false }.
+ // Created above for reuse.
+
+ // b. Let status be DefinePropertyOrThrow(subset, P, desc).
+ supportedLocales->defineOwnProperty(supportedLocales, &state, keys[i], desc, true);
+
+ // c. Assert: status is not abrupt completion.
+ if (state.hadException())
+ return jsUndefined();
+ }
+
+ // 9. Return subset.
+ return supportedLocales;
+}
+
+Vector<String> numberingSystemsForLocale(const String& locale)
+{
+ static NeverDestroyed<Vector<String>> cachedNumberingSystems;
+ Vector<String>& availableNumberingSystems = cachedNumberingSystems.get();
+ if (availableNumberingSystems.isEmpty()) {
+ UErrorCode status(U_ZERO_ERROR);
+ UEnumeration* numberingSystemNames = unumsys_openAvailableNames(&status);
+ ASSERT(U_SUCCESS(status));
+ status = U_ZERO_ERROR;
+
+ int32_t resultLength;
+ // Numbering system names are always ASCII, so use char[].
+ while (const char* result = uenum_next(numberingSystemNames, &resultLength, &status)) {
+ ASSERT(U_SUCCESS(status));
+ status = U_ZERO_ERROR;
+ availableNumberingSystems.append(String(result, resultLength));
+ }
+ uenum_close(numberingSystemNames);
+ }
+
+ UErrorCode status(U_ZERO_ERROR);
+ UNumberingSystem* defaultSystem = unumsys_open(locale.utf8().data(), &status);
+ ASSERT(U_SUCCESS(status));
+ String defaultSystemName(unumsys_getName(defaultSystem));
+ unumsys_close(defaultSystem);
+
+ Vector<String> numberingSystems({ defaultSystemName });
+ numberingSystems.appendVector(availableNumberingSystems);
+ return numberingSystems;
+}
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
diff --git a/Source/JavaScriptCore/runtime/IntlObject.h b/Source/JavaScriptCore/runtime/IntlObject.h
new file mode 100644
index 000000000..52c781116
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IntlObject.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 Andy VanWagoner (thetalecrafter@gmail.com)
+ *
+ * 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.
+ */
+
+#ifndef IntlObject_h
+#define IntlObject_h
+
+#if ENABLE(INTL)
+
+#include "JSCJSValueInlines.h"
+#include "JSObject.h"
+
+namespace JSC {
+
+class IntlCollatorConstructor;
+class IntlCollatorPrototype;
+class IntlDateTimeFormatConstructor;
+class IntlDateTimeFormatPrototype;
+class IntlNumberFormatConstructor;
+class IntlNumberFormatPrototype;
+
+class IntlObject : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static IntlObject* create(VM&, JSGlobalObject*, Structure*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+protected:
+ void finishCreation(VM&, JSGlobalObject*);
+
+private:
+ IntlObject(VM&, Structure*);
+};
+
+String defaultLocale();
+void convertICULocaleToBCP47LanguageTag(String& locale);
+bool intlBooleanOption(ExecState&, JSValue options, PropertyName, bool& usesFallback);
+String intlStringOption(ExecState&, JSValue options, PropertyName, std::initializer_list<const char*> values, const char* notFound, const char* fallback);
+unsigned intlNumberOption(ExecState&, JSValue options, PropertyName, unsigned minimum, unsigned maximum, unsigned fallback);
+Vector<String> canonicalizeLocaleList(ExecState&, JSValue locales);
+HashMap<String, String> resolveLocale(const HashSet<String>& availableLocales, const Vector<String>& requestedLocales, const HashMap<String, String>& options, const char* const relevantExtensionKeys[], size_t relevantExtensionKeyCount, Vector<String> (*localeData)(const String&, size_t));
+JSValue supportedLocales(ExecState&, const HashSet<String>& availableLocales, const Vector<String>& requestedLocales, JSValue options);
+String removeUnicodeLocaleExtension(const String& locale);
+String bestAvailableLocale(const HashSet<String>& availableLocales, const String& requestedLocale);
+Vector<String> numberingSystemsForLocale(const String& locale);
+
+} // namespace JSC
+
+#endif // ENABLE(INTL)
+
+#endif // IntlObject_h
diff --git a/Source/JavaScriptCore/runtime/Intrinsic.h b/Source/JavaScriptCore/runtime/Intrinsic.h
index 1f741da1e..218d2efd6 100644
--- a/Source/JavaScriptCore/runtime/Intrinsic.h
+++ b/Source/JavaScriptCore/runtime/Intrinsic.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 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
@@ -29,12 +29,14 @@
namespace JSC {
enum Intrinsic {
+ // Call intrinsics.
NoIntrinsic,
AbsIntrinsic,
MinIntrinsic,
MaxIntrinsic,
SqrtIntrinsic,
SinIntrinsic,
+ Clz32Intrinsic,
CosIntrinsic,
ArrayPushIntrinsic,
ArrayPopIntrinsic,
@@ -50,10 +52,24 @@ enum Intrinsic {
RegExpExecIntrinsic,
RegExpTestIntrinsic,
StringPrototypeValueOfIntrinsic,
+ StringPrototypeReplaceIntrinsic,
IMulIntrinsic,
- ArrayIteratorNextValueIntrinsic,
- ArrayIteratorNextKeyIntrinsic,
- ArrayIteratorNextGenericIntrinsic
+ RandomIntrinsic,
+ FRoundIntrinsic,
+
+ // Getter intrinsics.
+ TypedArrayLengthIntrinsic,
+ TypedArrayByteLengthIntrinsic,
+ TypedArrayByteOffsetIntrinsic,
+
+ // Debugging intrinsics. These are meant to be used as testing hacks within
+ // jsc.cpp and should never be exposed to users.
+ DFGTrueIntrinsic,
+ OSRExitIntrinsic,
+ IsFinalTierIntrinsic,
+ SetInt32HeapPredictionIntrinsic,
+ CheckInt32Intrinsic,
+ FiatInt52Intrinsic,
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/IterationStatus.h b/Source/JavaScriptCore/runtime/IterationStatus.h
new file mode 100644
index 000000000..fb8b5fb75
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IterationStatus.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#ifndef IterationStatus_h
+#define IterationStatus_h
+
+namespace JSC {
+
+enum class IterationStatus {
+ Continue,
+ Done
+};
+
+} // namespace JSC
+
+#endif // IterationStatus_h
diff --git a/Source/JavaScriptCore/runtime/IteratorOperations.cpp b/Source/JavaScriptCore/runtime/IteratorOperations.cpp
new file mode 100644
index 000000000..7dcd07b6f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IteratorOperations.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 "IteratorOperations.h"
+
+#include "Error.h"
+#include "JSCInlines.h"
+#include "ObjectConstructor.h"
+
+using namespace WTF;
+
+namespace JSC {
+
+JSValue iteratorNext(ExecState* exec, JSValue iterator, JSValue value)
+{
+ JSValue nextFunction = iterator.get(exec, exec->vm().propertyNames->next);
+ if (exec->hadException())
+ return jsUndefined();
+
+ CallData nextFunctionCallData;
+ CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData);
+ if (nextFunctionCallType == CallTypeNone)
+ return throwTypeError(exec);
+
+ MarkedArgumentBuffer nextFunctionArguments;
+ if (!value.isEmpty())
+ nextFunctionArguments.append(value);
+ JSValue result = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments);
+ if (exec->hadException())
+ return jsUndefined();
+
+ if (!result.isObject())
+ return throwTypeError(exec, ASCIILiteral("Iterator result interface is not an object."));
+
+ return result;
+}
+
+JSValue iteratorNext(ExecState* exec, JSValue iterator)
+{
+ return iteratorNext(exec, iterator, JSValue());
+}
+
+JSValue iteratorValue(ExecState* exec, JSValue iterResult)
+{
+ return iterResult.get(exec, exec->vm().propertyNames->value);
+}
+
+bool iteratorComplete(ExecState* exec, JSValue iterResult)
+{
+ JSValue done = iterResult.get(exec, exec->vm().propertyNames->done);
+ return done.toBoolean(exec);
+}
+
+JSValue iteratorStep(ExecState* exec, JSValue iterator)
+{
+ JSValue result = iteratorNext(exec, iterator);
+ if (exec->hadException())
+ return jsUndefined();
+ bool done = iteratorComplete(exec, result);
+ if (exec->hadException())
+ return jsUndefined();
+ if (done)
+ return jsBoolean(false);
+ return result;
+}
+
+void iteratorClose(ExecState* exec, JSValue iterator)
+{
+ Exception* exception = nullptr;
+ if (exec->hadException()) {
+ exception = exec->exception();
+ exec->clearException();
+ }
+ JSValue returnFunction = iterator.get(exec, exec->vm().propertyNames->returnKeyword);
+ if (exec->hadException())
+ return;
+
+ if (returnFunction.isUndefined()) {
+ if (exception)
+ exec->vm().throwException(exec, exception);
+ return;
+ }
+
+ CallData returnFunctionCallData;
+ CallType returnFunctionCallType = getCallData(returnFunction, returnFunctionCallData);
+ if (returnFunctionCallType == CallTypeNone) {
+ if (exception)
+ exec->vm().throwException(exec, exception);
+ else
+ throwTypeError(exec);
+ return;
+ }
+
+ MarkedArgumentBuffer returnFunctionArguments;
+ JSValue innerResult = call(exec, returnFunction, returnFunctionCallType, returnFunctionCallData, iterator, returnFunctionArguments);
+
+ if (exception) {
+ exec->vm().throwException(exec, exception);
+ return;
+ }
+
+ if (exec->hadException())
+ return;
+
+ if (!innerResult.isObject()) {
+ throwTypeError(exec, ASCIILiteral("Iterator result interface is not an object."));
+ return;
+ }
+}
+
+static const PropertyOffset donePropertyOffset = 0;
+static const PropertyOffset valuePropertyOffset = 1;
+
+Structure* createIteratorResultObjectStructure(VM& vm, JSGlobalObject& globalObject)
+{
+ Structure* iteratorResultStructure = vm.prototypeMap.emptyObjectStructureForPrototype(globalObject.objectPrototype(), JSFinalObject::defaultInlineCapacity());
+ PropertyOffset offset;
+ iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames->done, 0, offset);
+ RELEASE_ASSERT(offset == donePropertyOffset);
+ iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames->value, 0, offset);
+ RELEASE_ASSERT(offset == valuePropertyOffset);
+ return iteratorResultStructure;
+}
+
+JSObject* createIteratorResultObject(ExecState* exec, JSValue value, bool done)
+{
+ JSObject* resultObject = constructEmptyObject(exec, exec->lexicalGlobalObject()->iteratorResultObjectStructure());
+ resultObject->putDirect(exec->vm(), donePropertyOffset, jsBoolean(done));
+ resultObject->putDirect(exec->vm(), valuePropertyOffset, value);
+ return resultObject;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/IteratorOperations.h b/Source/JavaScriptCore/runtime/IteratorOperations.h
new file mode 100644
index 000000000..faee46ae2
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/IteratorOperations.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 IteratorOperations_h
+#define IteratorOperations_h
+
+#include "JSCJSValue.h"
+#include "JSObject.h"
+
+namespace JSC {
+
+JSValue iteratorNext(ExecState*, JSValue iterator, JSValue);
+JSValue iteratorNext(ExecState*, JSValue iterator);
+JSValue iteratorValue(ExecState*, JSValue iterator);
+bool iteratorComplete(ExecState*, JSValue iterator);
+JSValue iteratorStep(ExecState*, JSValue iterator);
+void iteratorClose(ExecState*, JSValue iterator);
+JS_EXPORT_PRIVATE JSObject* createIteratorResultObject(ExecState*, JSValue, bool done);
+
+Structure* createIteratorResultObjectStructure(VM&, JSGlobalObject&);
+
+}
+
+#endif // !defined(IteratorOperations_h)
diff --git a/Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.cpp b/Source/JavaScriptCore/runtime/IteratorPrototype.cpp
index afb59790c..aa950693f 100644
--- a/Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/IteratorPrototype.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple, Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -20,26 +20,31 @@
* 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 "ArgumentsIteratorConstructor.h"
+#include "IteratorPrototype.h"
-#include "ArgumentsIteratorPrototype.h"
-#include "JSArgumentsIterator.h"
+#include "JSCBuiltins.h"
#include "JSCJSValueInlines.h"
#include "JSCellInlines.h"
#include "JSGlobalObject.h"
+#include "ObjectConstructor.h"
+#include "StructureInlines.h"
namespace JSC {
-const ClassInfo ArgumentsIteratorConstructor::s_info = { "ArgumentsIterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ArgumentsIteratorConstructor) };
+const ClassInfo IteratorPrototype::s_info = { "Iterator", &Base::s_info, nullptr, CREATE_METHOD_TABLE(IteratorPrototype) };
-void ArgumentsIteratorConstructor::finishCreation(VM& vm, ArgumentsIteratorPrototype* prototype)
+void IteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
{
Base::finishCreation(vm);
- putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly);
-}
+ ASSERT(inherits(info()));
+ vm.prototypeMap.addPrototype(this);
+ JSFunction* iteratorPrototypeFunction = JSFunction::createBuiltinFunction(vm, iteratorPrototypeSymbolIteratorGetterCodeGenerator(vm), globalObject, "[Symbol.iterator]");
+ putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, iteratorPrototypeFunction, DontEnum);
}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/MapIteratorConstructor.h b/Source/JavaScriptCore/runtime/IteratorPrototype.h
index 45ba5b7ff..c15971dab 100644
--- a/Source/JavaScriptCore/runtime/MapIteratorConstructor.h
+++ b/Source/JavaScriptCore/runtime/IteratorPrototype.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple, Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -20,27 +20,26 @@
* 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.
*/
-#ifndef MapIteratorConstructor_h
-#define MapIteratorConstructor_h
+#ifndef IteratorPrototype_h
+#define IteratorPrototype_h
#include "JSObject.h"
namespace JSC {
-class MapIteratorPrototype;
-
-class MapIteratorConstructor : public JSNonFinalObject {
+class IteratorPrototype : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags;
- static MapIteratorConstructor* create(VM& vm, Structure* structure, MapIteratorPrototype* prototype)
+ static IteratorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
{
- MapIteratorConstructor* constructor = new (NotNull, allocateCell<MapIteratorConstructor>(vm.heap)) MapIteratorConstructor(vm, structure);
- constructor->finishCreation(vm, prototype);
- return constructor;
+ IteratorPrototype* prototype = new (NotNull, allocateCell<IteratorPrototype>(vm.heap)) IteratorPrototype(vm, structure);
+ prototype->finishCreation(vm, globalObject);
+ return prototype;
}
DECLARE_INFO;
@@ -51,13 +50,13 @@ public:
}
private:
- MapIteratorConstructor(VM& vm, Structure* structure)
+ IteratorPrototype(VM& vm, Structure* structure)
: Base(vm, structure)
{
}
- void finishCreation(VM&, MapIteratorPrototype*);
+ void finishCreation(VM&, JSGlobalObject*);
};
}
-#endif // !defined(MapConstructor_h)
+#endif // !defined(IteratorPrototype_h)
diff --git a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.cpp b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.cpp
index 80c762620..6e5b53618 100644
--- a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.cpp
+++ b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.cpp
@@ -29,6 +29,6 @@ namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSAPIValueWrapper);
-const ClassInfo JSAPIValueWrapper::s_info = { "API Wrapper", 0, 0, 0, CREATE_METHOD_TABLE(JSAPIValueWrapper) };
+const ClassInfo JSAPIValueWrapper::s_info = { "API Wrapper", 0, 0, CREATE_METHOD_TABLE(JSAPIValueWrapper) };
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h
index e1f2cd804..66e61c70d 100644
--- a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h
+++ b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h
@@ -30,50 +30,51 @@
namespace JSC {
- class JSAPIValueWrapper : public JSCell {
- friend JSValue jsAPIValueWrapper(ExecState*, JSValue);
- public:
- typedef JSCell Base;
+class JSAPIValueWrapper : public JSCell {
+ friend JSValue jsAPIValueWrapper(ExecState*, JSValue);
+public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
- JSValue value() const { return m_value.get(); }
+ JSValue value() const { return m_value.get(); }
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(APIValueWrapperType, OverridesVisitChildren | OverridesGetPropertyNames), info());
- }
-
- DECLARE_EXPORT_INFO;
-
- static JSAPIValueWrapper* create(ExecState* exec, JSValue value)
- {
- VM& vm = exec->vm();
- JSAPIValueWrapper* wrapper = new (NotNull, allocateCell<JSAPIValueWrapper>(vm.heap)) JSAPIValueWrapper(exec);
- wrapper->finishCreation(vm, value);
- return wrapper;
- }
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(APIValueWrapperType, OverridesGetPropertyNames), info());
+ }
- protected:
- void finishCreation(VM& vm, JSValue value)
- {
- Base::finishCreation(vm);
- m_value.set(vm, this, value);
- ASSERT(!value.isCell());
- }
+ DECLARE_EXPORT_INFO;
- private:
- JSAPIValueWrapper(ExecState* exec)
- : JSCell(exec->vm(), exec->vm().apiWrapperStructure.get())
- {
- }
+ static JSAPIValueWrapper* create(ExecState* exec, JSValue value)
+ {
+ VM& vm = exec->vm();
+ JSAPIValueWrapper* wrapper = new (NotNull, allocateCell<JSAPIValueWrapper>(vm.heap)) JSAPIValueWrapper(exec);
+ wrapper->finishCreation(vm, value);
+ return wrapper;
+ }
- WriteBarrier<Unknown> m_value;
- };
+protected:
+ void finishCreation(VM& vm, JSValue value)
+ {
+ Base::finishCreation(vm);
+ m_value.set(vm, this, value);
+ ASSERT(!value.isCell());
+ }
- inline JSValue jsAPIValueWrapper(ExecState* exec, JSValue value)
+private:
+ JSAPIValueWrapper(ExecState* exec)
+ : JSCell(exec->vm(), exec->vm().apiWrapperStructure.get())
{
- return JSAPIValueWrapper::create(exec, value);
}
+ WriteBarrier<Unknown> m_value;
+};
+
+inline JSValue jsAPIValueWrapper(ExecState* exec, JSValue value)
+{
+ return JSAPIValueWrapper::create(exec, value);
+}
+
} // namespace JSC
#endif // JSAPIValueWrapper_h
diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp
deleted file mode 100644
index 72ed1c712..000000000
--- a/Source/JavaScriptCore/runtime/JSActivation.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2008, 2009 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.
- * 3. Neither the name of Apple Computer, 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "JSActivation.h"
-
-#include "Arguments.h"
-#include "Interpreter.h"
-#include "JSFunction.h"
-#include "Operations.h"
-
-using namespace std;
-
-namespace JSC {
-
-const ClassInfo JSActivation::s_info = { "JSActivation", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSActivation) };
-
-void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor)
-{
- JSActivation* thisObject = jsCast<JSActivation*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
- Base::visitChildren(thisObject, visitor);
-
- // No need to mark our registers if they're still in the JSStack.
- if (!thisObject->isTornOff())
- return;
-
- for (int i = 0; i < thisObject->symbolTable()->captureCount(); ++i)
- visitor.append(&thisObject->storage()[i]);
-}
-
-inline bool JSActivation::symbolTableGet(PropertyName propertyName, PropertySlot& slot)
-{
- SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName());
- if (entry.isNull())
- return false;
-
- // Defend against the inspector asking for a var after it has been optimized out.
- if (isTornOff() && !isValid(entry))
- return false;
-
- slot.setValue(this, DontEnum, registerAt(entry.getIndex()).get());
- return true;
-}
-
-inline bool JSActivation::symbolTableGet(PropertyName propertyName, PropertyDescriptor& descriptor)
-{
- SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName());
- if (entry.isNull())
- return false;
-
- // Defend against the inspector asking for a var after it has been optimized out.
- if (isTornOff() && !isValid(entry))
- return false;
-
- descriptor.setDescriptor(registerAt(entry.getIndex()).get(), entry.getAttributes());
- return true;
-}
-
-inline bool JSActivation::symbolTablePut(ExecState* exec, PropertyName propertyName, JSValue value, bool shouldThrow)
-{
- VM& vm = exec->vm();
- ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
-
- SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName());
- if (entry.isNull())
- return false;
- if (entry.isReadOnly()) {
- if (shouldThrow)
- throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
- return true;
- }
-
- // Defend against the inspector asking for a var after it has been optimized out.
- if (isTornOff() && !isValid(entry))
- return false;
-
- registerAt(entry.getIndex()).set(vm, this, value);
- return true;
-}
-
-void JSActivation::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
-{
- JSActivation* thisObject = jsCast<JSActivation*>(object);
-
- CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(thisObject->m_registers));
- if (mode == IncludeDontEnumProperties && !thisObject->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval()))
- propertyNames.add(exec->propertyNames().arguments);
-
- {
- ConcurrentJITLocker locker(thisObject->symbolTable()->m_lock);
- SymbolTable::Map::iterator end = thisObject->symbolTable()->end(locker);
- for (SymbolTable::Map::iterator it = thisObject->symbolTable()->begin(locker); it != end; ++it) {
- if (it->value.getAttributes() & DontEnum && mode != IncludeDontEnumProperties)
- continue;
- if (!thisObject->isValid(it->value))
- continue;
- propertyNames.add(Identifier(exec, it->key.get()));
- }
- }
- // Skip the JSVariableObject implementation of getOwnNonIndexPropertyNames
- JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
-}
-
-inline bool JSActivation::symbolTablePutWithAttributes(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
-{
- ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
-
- WriteBarrierBase<Unknown>* reg;
- {
- ConcurrentJITLocker locker(symbolTable()->m_lock);
- SymbolTable::Map::iterator iter = symbolTable()->find(locker, propertyName.publicName());
- if (iter == symbolTable()->end(locker))
- return false;
- SymbolTableEntry& entry = iter->value;
- ASSERT(!entry.isNull());
- if (!isValid(entry))
- return false;
-
- entry.setAttributes(attributes);
- reg = &registerAt(entry.getIndex());
- }
- reg->set(vm, this, value);
- return true;
-}
-
-bool JSActivation::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
-{
- JSActivation* thisObject = jsCast<JSActivation*>(object);
-
- if (propertyName == exec->propertyNames().arguments) {
- // Defend against the inspector asking for the arguments object after it has been optimized out.
- CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(thisObject->m_registers));
- if (!thisObject->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval())) {
- slot.setCustom(thisObject, DontEnum, argumentsGetter);
- return true;
- }
- }
-
- if (thisObject->symbolTableGet(propertyName, slot))
- return true;
-
- unsigned attributes;
- if (JSValue value = thisObject->getDirect(exec->vm(), propertyName, attributes)) {
- slot.setValue(thisObject, attributes, value);
- return true;
- }
-
- // We don't call through to JSObject because there's no way to give an
- // activation object getter properties or a prototype.
- ASSERT(!thisObject->hasGetterSetterProperties());
- ASSERT(thisObject->prototype().isNull());
- return false;
-}
-
-void JSActivation::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
-{
- JSActivation* thisObject = jsCast<JSActivation*>(cell);
- ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
-
- if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode()))
- return;
-
- // We don't call through to JSObject because __proto__ and getter/setter
- // properties are non-standard extensions that other implementations do not
- // expose in the activation object.
- ASSERT(!thisObject->hasGetterSetterProperties());
- thisObject->putOwnDataProperty(exec->vm(), propertyName, value, slot);
-}
-
-bool JSActivation::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
-{
- if (propertyName == exec->propertyNames().arguments)
- return false;
-
- return Base::deleteProperty(cell, exec, propertyName);
-}
-
-JSValue JSActivation::toThis(JSCell*, ExecState* exec, ECMAMode ecmaMode)
-{
- if (ecmaMode == StrictMode)
- return jsUndefined();
- return exec->globalThisValue();
-}
-
-EncodedJSValue JSActivation::argumentsGetter(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
-{
- JSActivation* activation = jsCast<JSActivation*>(JSValue::decode(slotBase));
- CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(activation->m_registers));
- ASSERT(!activation->isTornOff() && (callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval()));
- if (activation->isTornOff() || !(callFrame->codeBlock()->usesArguments() || callFrame->codeBlock()->usesEval()))
- return JSValue::encode(jsUndefined());
-
- VirtualRegister argumentsRegister = callFrame->codeBlock()->argumentsRegister();
- if (JSValue arguments = callFrame->uncheckedR(argumentsRegister.offset()).jsValue())
- return JSValue::encode(arguments);
- int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister).offset();
-
- JSValue arguments = JSValue(Arguments::create(callFrame->vm(), callFrame));
- callFrame->uncheckedR(argumentsRegister.offset()) = arguments;
- callFrame->uncheckedR(realArgumentsRegister) = arguments;
-
- ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(Arguments::info()));
- return JSValue::encode(callFrame->uncheckedR(realArgumentsRegister).jsValue());
-}
-
-} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSActivation.h b/Source/JavaScriptCore/runtime/JSActivation.h
deleted file mode 100644
index 67eafeeeb..000000000
--- a/Source/JavaScriptCore/runtime/JSActivation.h
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2008, 2009, 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.
- * 3. Neither the name of Apple Computer, 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
- */
-
-#ifndef JSActivation_h
-#define JSActivation_h
-
-#include "CodeBlock.h"
-#include "CopiedSpaceInlines.h"
-#include "JSVariableObject.h"
-#include "Nodes.h"
-#include "SymbolTable.h"
-
-namespace JSC {
-
-class Register;
-
-class JSActivation : public JSVariableObject {
-private:
- JSActivation(VM&, CallFrame*, Register*, SymbolTable*);
-
-public:
- typedef JSVariableObject Base;
-
- static JSActivation* create(VM& vm, CallFrame* callFrame, Register* registers, CodeBlock* codeBlock)
- {
- SymbolTable* symbolTable = codeBlock->symbolTable();
- ASSERT(codeBlock->codeType() == FunctionCode);
- JSActivation* activation = new (
- NotNull,
- allocateCell<JSActivation>(
- vm.heap,
- allocationSize(symbolTable)
- )
- ) JSActivation(vm, callFrame, registers, symbolTable);
- activation->finishCreation(vm);
- return activation;
- }
-
- static JSActivation* create(VM& vm, CallFrame* callFrame, CodeBlock* codeBlock)
- {
- return create(vm, callFrame, callFrame->registers(), codeBlock);
- }
-
- static void visitChildren(JSCell*, SlotVisitor&);
-
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
-
- static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
-
- static bool deleteProperty(JSCell*, ExecState*, PropertyName);
-
- static JSValue toThis(JSCell*, ExecState*, ECMAMode);
-
- void tearOff(VM&);
-
- DECLARE_INFO;
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(ActivationObjectType, StructureFlags), info()); }
-
- WriteBarrierBase<Unknown>& registerAt(int) const;
- bool isValidIndex(int) const;
- bool isValid(const SymbolTableEntry&) const;
- bool isTornOff();
- int registersOffset();
- static int registersOffset(SymbolTable*);
-
-protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags;
-
-private:
- bool symbolTableGet(PropertyName, PropertySlot&);
- bool symbolTableGet(PropertyName, PropertyDescriptor&);
- bool symbolTableGet(PropertyName, PropertySlot&, bool& slotIsWriteable);
- bool symbolTablePut(ExecState*, PropertyName, JSValue, bool shouldThrow);
- bool symbolTablePutWithAttributes(VM&, PropertyName, JSValue, unsigned attributes);
-
- static EncodedJSValue argumentsGetter(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-
- static size_t allocationSize(SymbolTable*);
- static size_t storageOffset();
-
- WriteBarrier<Unknown>* storage(); // captureCount() number of registers.
-};
-
-extern int activationCount;
-extern int allTheThingsCount;
-
-inline JSActivation::JSActivation(VM& vm, CallFrame* callFrame, Register* registers, SymbolTable* symbolTable)
- : Base(
- vm,
- callFrame->lexicalGlobalObject()->activationStructure(),
- registers,
- callFrame->scope(),
- symbolTable)
-{
- WriteBarrier<Unknown>* storage = this->storage();
- size_t captureCount = symbolTable->captureCount();
- for (size_t i = 0; i < captureCount; ++i)
- new (NotNull, &storage[i]) WriteBarrier<Unknown>;
-}
-
-JSActivation* asActivation(JSValue);
-
-inline JSActivation* asActivation(JSValue value)
-{
- ASSERT(asObject(value)->inherits(JSActivation::info()));
- return jsCast<JSActivation*>(asObject(value));
-}
-
-ALWAYS_INLINE JSActivation* Register::activation() const
-{
- return asActivation(jsValue());
-}
-
-inline int JSActivation::registersOffset(SymbolTable* symbolTable)
-{
- return storageOffset() + ((symbolTable->captureCount() - symbolTable->captureStart() - 1) * sizeof(WriteBarrier<Unknown>));
-}
-
-inline void JSActivation::tearOff(VM& vm)
-{
- ASSERT(!isTornOff());
-
- WriteBarrierBase<Unknown>* dst = reinterpret_cast_ptr<WriteBarrierBase<Unknown>*>(
- reinterpret_cast<char*>(this) + registersOffset(symbolTable()));
- WriteBarrierBase<Unknown>* src = m_registers;
-
- int captureEnd = symbolTable()->captureEnd();
- for (int i = symbolTable()->captureStart(); i > captureEnd; --i)
- dst[i].set(vm, this, src[i].get());
-
- m_registers = dst;
- ASSERT(isTornOff());
-}
-
-inline bool JSActivation::isTornOff()
-{
- return m_registers == reinterpret_cast_ptr<WriteBarrierBase<Unknown>*>(
- reinterpret_cast<char*>(this) + registersOffset(symbolTable()));
-}
-
-inline size_t JSActivation::storageOffset()
-{
- return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSActivation));
-}
-
-inline WriteBarrier<Unknown>* JSActivation::storage()
-{
- return reinterpret_cast_ptr<WriteBarrier<Unknown>*>(
- reinterpret_cast<char*>(this) + storageOffset());
-}
-
-inline size_t JSActivation::allocationSize(SymbolTable* symbolTable)
-{
- size_t objectSizeInBytes = WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSActivation));
- size_t storageSizeInBytes = symbolTable->captureCount() * sizeof(WriteBarrier<Unknown>);
- return objectSizeInBytes + storageSizeInBytes;
-}
-
-inline bool JSActivation::isValidIndex(int index) const
-{
- if (index > symbolTable()->captureStart())
- return false;
- if (index <= symbolTable()->captureEnd())
- return false;
- return true;
-}
-
-inline bool JSActivation::isValid(const SymbolTableEntry& entry) const
-{
- return isValidIndex(entry.getIndex());
-}
-
-inline WriteBarrierBase<Unknown>& JSActivation::registerAt(int index) const
-{
- ASSERT(isValidIndex(index));
- return Base::registerAt(index);
-}
-
-} // namespace JSC
-
-#endif // JSActivation_h
diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp
index 9007b5f7d..afdbe0de7 100644
--- a/Source/JavaScriptCore/runtime/JSArray.cpp
+++ b/Source/JavaScriptCore/runtime/JSArray.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2007, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2007, 2008, 2009, 2012, 2013, 2015 Apple Inc. All rights reserved.
* Copyright (C) 2003 Peter Kelly (pmk@post.com)
* Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
*
@@ -26,18 +26,16 @@
#include "ArrayPrototype.h"
#include "ButterflyInlines.h"
#include "CachedCall.h"
+#include "CodeBlock.h"
#include "CopiedSpace.h"
-#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "Executable.h"
#include "GetterSetter.h"
#include "IndexingHeaderInlines.h"
+#include "JSCInlines.h"
#include "PropertyNameArray.h"
#include "Reject.h"
-#include <wtf/AVLTree.h>
#include <wtf/Assertions.h>
-#include <wtf/OwnPtr.h>
-#include <Operations.h>
using namespace std;
using namespace WTF;
@@ -46,7 +44,7 @@ namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSArray);
-const ClassInfo JSArray::s_info = {"Array", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSArray)};
+const ClassInfo JSArray::s_info = {"Array", &JSNonFinalObject::s_info, 0, CREATE_METHOD_TABLE(JSArray)};
Butterfly* createArrayButterflyInDictionaryIndexingMode(
VM& vm, JSCell* intendedOwner, unsigned initialLength)
@@ -109,11 +107,12 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName
unsigned newLen = descriptor.value().toUInt32(exec);
// d. If newLen is not equal to ToNumber( Desc.[[Value]]), throw a RangeError exception.
if (newLen != descriptor.value().toNumber(exec)) {
- exec->vm().throwException(exec, createRangeError(exec, "Invalid array length"));
+ exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Invalid array length")));
return false;
}
// Based on SameValue check in 8.12.9, this is always okay.
+ // FIXME: Nothing prevents this from being called on a RuntimeArray, and the length function will always return 0 in that case.
if (newLen == array->length()) {
if (descriptor.writablePresent())
array->setLengthWritable(exec, descriptor.writable());
@@ -160,9 +159,10 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName
// 4. Else if P is an array index (15.4), then
// a. Let index be ToUint32(P).
- unsigned index = propertyName.asIndex();
- if (index != PropertyName::NotAnIndex) {
+ if (Optional<uint32_t> optionalIndex = parseIndex(propertyName)) {
// b. Reject if index >= oldLen and oldLenDesc.[[Writable]] is false.
+ uint32_t index = optionalIndex.value();
+ // FIXME: Nothing prevents this from being called on a RuntimeArray, and the length function will always return 0 in that case.
if (index >= array->length() && !array->isLengthWritable())
return reject(exec, throwException, "Attempting to define numeric property on array with non-writable length property.");
// c. Let succeeded be the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing P, Desc, and false as arguments.
@@ -228,7 +228,7 @@ void JSArray::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, Pro
{
JSArray* thisObject = jsCast<JSArray*>(object);
- if (mode == IncludeDontEnumProperties)
+ if (mode.includeDontEnumProperties())
propertyNames.add(exec->propertyNames().length);
JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
@@ -239,8 +239,8 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count)
{
ArrayStorage* storage = ensureArrayStorage(vm);
Butterfly* butterfly = storage->butterfly();
- unsigned propertyCapacity = structure()->outOfLineCapacity();
- unsigned propertySize = structure()->outOfLineSize();
+ unsigned propertyCapacity = structure(vm)->outOfLineCapacity();
+ unsigned propertySize = structure(vm)->outOfLineSize();
// If not, we should have handled this on the fast path.
ASSERT(!addToFront || count > storage->m_indexBias);
@@ -274,7 +274,7 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count)
unsigned newStorageCapacity;
// If the current storage array is sufficiently large (but not too large!) then just keep using it.
if (currentCapacity > desiredCapacity && isDenseEnoughForVector(currentCapacity, requiredVectorLength)) {
- newAllocBase = butterfly->base(structure());
+ newAllocBase = butterfly->base(structure(vm));
newStorageCapacity = currentCapacity;
} else {
size_t newSize = Butterfly::totalSize(0, propertyCapacity, true, ArrayStorage::sizeFor(desiredCapacity));
@@ -298,7 +298,7 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count)
// Atomic decay, + the post-capacity cannot be greater than what is available.
postCapacity = min((storage->vectorLength() - length) >> 1, newStorageCapacity - requiredVectorLength);
// If we're moving contents within the same allocation, the post-capacity is being reduced.
- ASSERT(newAllocBase != butterfly->base(structure()) || postCapacity < storage->vectorLength() - length);
+ ASSERT(newAllocBase != butterfly->base(structure(vm)) || postCapacity < storage->vectorLength() - length);
}
unsigned newVectorLength = requiredVectorLength + postCapacity;
@@ -310,7 +310,7 @@ bool JSArray::unshiftCountSlowCase(VM& vm, bool addToFront, unsigned count)
ASSERT(count + usedVectorLength <= newVectorLength);
memmove(newButterfly->arrayStorage()->m_vector + count, storage->m_vector, sizeof(JSValue) * usedVectorLength);
memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0));
- } else if ((newAllocBase != butterfly->base(structure())) || (newIndexBias != storage->m_indexBias)) {
+ } else if ((newAllocBase != butterfly->base(structure(vm))) || (newIndexBias != storage->m_indexBias)) {
memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0));
memmove(newButterfly->arrayStorage()->m_vector, storage->m_vector, sizeof(JSValue) * usedVectorLength);
@@ -379,7 +379,7 @@ bool JSArray::setLengthWithArrayStorage(ExecState* exec, unsigned newLength, boo
unsigned usedVectorLength = min(length, storage->vectorLength());
for (unsigned i = newLength; i < usedVectorLength; ++i) {
WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
- bool hadValue = valueSlot;
+ bool hadValue = !!valueSlot;
valueSlot.clear();
storage->m_numValuesInVector -= hadValue;
}
@@ -392,7 +392,8 @@ bool JSArray::setLengthWithArrayStorage(ExecState* exec, unsigned newLength, boo
bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException)
{
- switch (structure()->indexingType()) {
+ Butterfly* butterfly = m_butterfly.get(this);
+ switch (indexingType()) {
case ArrayClass:
if (!newLength)
return true;
@@ -407,8 +408,8 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
case ArrayWithUndecided:
case ArrayWithInt32:
case ArrayWithDouble:
- case ArrayWithContiguous:
- if (newLength == m_butterfly->publicLength())
+ case ArrayWithContiguous: {
+ if (newLength == butterfly->publicLength())
return true;
if (newLength >= MAX_ARRAY_INDEX // This case ensures that we can do fast push.
|| (newLength >= MIN_SPARSE_ARRAY_INDEX
@@ -417,19 +418,28 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
exec, newLength, throwException,
ensureArrayStorage(exec->vm()));
}
- if (newLength > m_butterfly->publicLength()) {
+ if (newLength > butterfly->publicLength()) {
ensureLength(exec->vm(), newLength);
return true;
}
- if (structure()->indexingType() == ArrayWithDouble) {
- for (unsigned i = m_butterfly->publicLength(); i-- > newLength;)
- m_butterfly->contiguousDouble()[i] = QNaN;
+
+ unsigned lengthToClear = butterfly->publicLength() - newLength;
+ unsigned costToAllocateNewButterfly = 64; // a heuristic.
+ if (lengthToClear > newLength && lengthToClear > costToAllocateNewButterfly) {
+ reallocateAndShrinkButterfly(exec->vm(), newLength);
+ return true;
+ }
+
+ if (indexingType() == ArrayWithDouble) {
+ for (unsigned i = butterfly->publicLength(); i-- > newLength;)
+ butterfly->contiguousDouble()[i] = PNaN;
} else {
- for (unsigned i = m_butterfly->publicLength(); i-- > newLength;)
- m_butterfly->contiguous()[i].clear();
+ for (unsigned i = butterfly->publicLength(); i-- > newLength;)
+ butterfly->contiguous()[i].clear();
}
- m_butterfly->setPublicLength(newLength);
+ butterfly->setPublicLength(newLength);
return true;
+ }
case ArrayWithArrayStorage:
case ArrayWithSlowPutArrayStorage:
@@ -443,51 +453,53 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
JSValue JSArray::pop(ExecState* exec)
{
- switch (structure()->indexingType()) {
+ Butterfly* butterfly = m_butterfly.get(this);
+
+ switch (indexingType()) {
case ArrayClass:
return jsUndefined();
case ArrayWithUndecided:
- if (!m_butterfly->publicLength())
+ if (!butterfly->publicLength())
return jsUndefined();
// We have nothing but holes. So, drop down to the slow version.
break;
case ArrayWithInt32:
case ArrayWithContiguous: {
- unsigned length = m_butterfly->publicLength();
+ unsigned length = butterfly->publicLength();
if (!length--)
return jsUndefined();
- RELEASE_ASSERT(length < m_butterfly->vectorLength());
- JSValue value = m_butterfly->contiguous()[length].get();
+ RELEASE_ASSERT(length < butterfly->vectorLength());
+ JSValue value = butterfly->contiguous()[length].get();
if (value) {
- m_butterfly->contiguous()[length].clear();
- m_butterfly->setPublicLength(length);
+ butterfly->contiguous()[length].clear();
+ butterfly->setPublicLength(length);
return value;
}
break;
}
case ArrayWithDouble: {
- unsigned length = m_butterfly->publicLength();
+ unsigned length = butterfly->publicLength();
if (!length--)
return jsUndefined();
- RELEASE_ASSERT(length < m_butterfly->vectorLength());
- double value = m_butterfly->contiguousDouble()[length];
+ RELEASE_ASSERT(length < butterfly->vectorLength());
+ double value = butterfly->contiguousDouble()[length];
if (value == value) {
- m_butterfly->contiguousDouble()[length] = QNaN;
- m_butterfly->setPublicLength(length);
+ butterfly->contiguousDouble()[length] = PNaN;
+ butterfly->setPublicLength(length);
return JSValue(JSValue::EncodeAsDouble, value);
}
break;
}
case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
- ArrayStorage* storage = m_butterfly->arrayStorage();
+ ArrayStorage* storage = butterfly->arrayStorage();
unsigned length = storage->length();
if (!length) {
@@ -524,7 +536,7 @@ JSValue JSArray::pop(ExecState* exec)
return jsUndefined();
// Call the [[Delete]] internal method of O with arguments indx and true.
if (!deletePropertyByIndex(this, exec, index)) {
- throwTypeError(exec, "Unable to delete property.");
+ throwTypeError(exec, ASCIILiteral("Unable to delete property."));
return jsUndefined();
}
// Call the [[Put]] internal method of O with arguments "length", indx, and true.
@@ -538,7 +550,9 @@ JSValue JSArray::pop(ExecState* exec)
// - pushing to an array of length 2^32-1 stores the property, but throws a range error.
void JSArray::push(ExecState* exec, JSValue value)
{
- switch (structure()->indexingType()) {
+ Butterfly* butterfly = m_butterfly.get(this);
+
+ switch (indexingType()) {
case ArrayClass: {
createInitialUndecided(exec->vm(), 0);
FALLTHROUGH;
@@ -557,18 +571,18 @@ void JSArray::push(ExecState* exec, JSValue value)
return;
}
- unsigned length = m_butterfly->publicLength();
- ASSERT(length <= m_butterfly->vectorLength());
- if (length < m_butterfly->vectorLength()) {
- m_butterfly->contiguousInt32()[length].setWithoutWriteBarrier(value);
- m_butterfly->setPublicLength(length + 1);
+ unsigned length = butterfly->publicLength();
+ ASSERT(length <= butterfly->vectorLength());
+ if (length < butterfly->vectorLength()) {
+ butterfly->contiguousInt32()[length].setWithoutWriteBarrier(value);
+ butterfly->setPublicLength(length + 1);
return;
}
if (length > MAX_ARRAY_INDEX) {
- methodTable()->putByIndex(this, exec, length, value, true);
+ methodTable(exec->vm())->putByIndex(this, exec, length, value, true);
if (!exec->hadException())
- exec->vm().throwException(exec, createRangeError(exec, "Invalid array length"));
+ exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Invalid array length")));
return;
}
@@ -577,18 +591,18 @@ void JSArray::push(ExecState* exec, JSValue value)
}
case ArrayWithContiguous: {
- unsigned length = m_butterfly->publicLength();
- ASSERT(length <= m_butterfly->vectorLength());
- if (length < m_butterfly->vectorLength()) {
- m_butterfly->contiguous()[length].set(exec->vm(), this, value);
- m_butterfly->setPublicLength(length + 1);
+ unsigned length = butterfly->publicLength();
+ ASSERT(length <= butterfly->vectorLength());
+ if (length < butterfly->vectorLength()) {
+ butterfly->contiguous()[length].set(exec->vm(), this, value);
+ butterfly->setPublicLength(length + 1);
return;
}
if (length > MAX_ARRAY_INDEX) {
- methodTable()->putByIndex(this, exec, length, value, true);
+ methodTable(exec->vm())->putByIndex(this, exec, length, value, true);
if (!exec->hadException())
- exec->vm().throwException(exec, createRangeError(exec, "Invalid array length"));
+ exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Invalid array length")));
return;
}
@@ -609,18 +623,18 @@ void JSArray::push(ExecState* exec, JSValue value)
return;
}
- unsigned length = m_butterfly->publicLength();
- ASSERT(length <= m_butterfly->vectorLength());
- if (length < m_butterfly->vectorLength()) {
- m_butterfly->contiguousDouble()[length] = valueAsDouble;
- m_butterfly->setPublicLength(length + 1);
+ unsigned length = butterfly->publicLength();
+ ASSERT(length <= butterfly->vectorLength());
+ if (length < butterfly->vectorLength()) {
+ butterfly->contiguousDouble()[length] = valueAsDouble;
+ butterfly->setPublicLength(length + 1);
return;
}
if (length > MAX_ARRAY_INDEX) {
- methodTable()->putByIndex(this, exec, length, value, true);
+ methodTable(exec->vm())->putByIndex(this, exec, length, value, true);
if (!exec->hadException())
- exec->vm().throwException(exec, createRangeError(exec, "Invalid array length"));
+ exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Invalid array length")));
return;
}
@@ -639,7 +653,7 @@ void JSArray::push(ExecState* exec, JSValue value)
}
case ArrayWithArrayStorage: {
- ArrayStorage* storage = m_butterfly->arrayStorage();
+ ArrayStorage* storage = butterfly->arrayStorage();
// Fast case - push within vector, always update m_length & m_numValuesInVector.
unsigned length = storage->length();
@@ -652,10 +666,10 @@ void JSArray::push(ExecState* exec, JSValue value)
// Pushing to an array of invalid length (2^31-1) stores the property, but throws a range error.
if (storage->length() > MAX_ARRAY_INDEX) {
- methodTable()->putByIndex(this, exec, storage->length(), value, true);
+ methodTable(exec->vm())->putByIndex(this, exec, storage->length(), value, true);
// Per ES5.1 15.4.4.7 step 6 & 15.4.5.1 step 3.d.
if (!exec->hadException())
- exec->vm().throwException(exec, createRangeError(exec, "Invalid array length"));
+ exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Invalid array length")));
return;
}
@@ -669,15 +683,80 @@ void JSArray::push(ExecState* exec, JSValue value)
}
}
-bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage* storage)
+JSArray* JSArray::fastSlice(ExecState& exec, unsigned startIndex, unsigned count)
+{
+ auto arrayType = indexingType();
+ switch (arrayType) {
+ case ArrayWithDouble:
+ case ArrayWithInt32:
+ case ArrayWithContiguous: {
+ VM& vm = exec.vm();
+ if (count >= MIN_SPARSE_ARRAY_INDEX || structure(vm)->holesMustForwardToPrototype(vm))
+ return nullptr;
+
+ Structure* resultStructure = exec.lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(arrayType);
+ JSArray* resultArray = JSArray::tryCreateUninitialized(vm, resultStructure, count);
+ if (!resultArray)
+ return nullptr;
+
+ auto& resultButterfly = *resultArray->butterfly();
+ if (arrayType == ArrayWithDouble)
+ memcpy(resultButterfly.contiguousDouble().data(), m_butterfly.get(this)->contiguousDouble().data() + startIndex, sizeof(JSValue) * count);
+ else
+ memcpy(resultButterfly.contiguous().data(), m_butterfly.get(this)->contiguous().data() + startIndex, sizeof(JSValue) * count);
+ resultButterfly.setPublicLength(count);
+
+ return resultArray;
+ }
+ default:
+ return nullptr;
+ }
+}
+
+EncodedJSValue JSArray::fastConcatWith(ExecState& exec, JSArray& otherArray)
+{
+ auto newArrayType = indexingType();
+
+ VM& vm = exec.vm();
+ ASSERT(newArrayType == fastConcatType(vm, *this, otherArray));
+
+ unsigned thisArraySize = m_butterfly.get(this)->publicLength();
+ unsigned otherArraySize = otherArray.m_butterfly.get(this)->publicLength();
+ ASSERT(thisArraySize + otherArraySize < MIN_SPARSE_ARRAY_INDEX);
+
+ Structure* resultStructure = exec.lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(newArrayType);
+ JSArray* resultArray = JSArray::tryCreateUninitialized(vm, resultStructure, thisArraySize + otherArraySize);
+ if (!resultArray)
+ return JSValue::encode(throwOutOfMemoryError(&exec));
+
+ auto& resultButterfly = *resultArray->butterfly();
+ auto& otherButterfly = *otherArray.butterfly();
+ if (newArrayType == ArrayWithDouble) {
+ auto buffer = resultButterfly.contiguousDouble().data();
+ memcpy(buffer, m_butterfly.get(this)->contiguousDouble().data(), sizeof(JSValue) * thisArraySize);
+ memcpy(buffer + thisArraySize, otherButterfly.contiguousDouble().data(), sizeof(JSValue) * otherArraySize);
+ } else {
+ auto buffer = resultButterfly.contiguous().data();
+ memcpy(buffer, m_butterfly.get(this)->contiguous().data(), sizeof(JSValue) * thisArraySize);
+ memcpy(buffer + thisArraySize, otherButterfly.contiguous().data(), sizeof(JSValue) * otherArraySize);
+ }
+
+ resultButterfly.setPublicLength(thisArraySize + otherArraySize);
+ return JSValue::encode(resultArray);
+}
+
+bool JSArray::shiftCountWithArrayStorage(VM& vm, unsigned startIndex, unsigned count, ArrayStorage* storage)
{
unsigned oldLength = storage->length();
RELEASE_ASSERT(count <= oldLength);
// If the array contains holes or is otherwise in an abnormal state,
// use the generic algorithm in ArrayPrototype.
- if (oldLength != storage->m_numValuesInVector || inSparseIndexingMode() || shouldUseSlowPut(structure()->indexingType()))
+ if ((storage->hasHoles() && this->structure(vm)->holesMustForwardToPrototype(vm))
+ || hasSparseMap()
+ || shouldUseSlowPut(indexingType())) {
return false;
+ }
if (!oldLength)
return true;
@@ -711,16 +790,29 @@ bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, Ar
// after the shift region, so we move the elements before to the right.
if (numElementsBeforeShiftRegion) {
RELEASE_ASSERT(count + startIndex <= vectorLength);
- memmove(
- storage->m_vector + count,
- storage->m_vector,
- sizeof(JSValue) * startIndex);
+ if (storage->hasHoles()) {
+ for (unsigned i = startIndex; i-- > 0;) {
+ unsigned destinationIndex = count + i;
+ JSValue source = storage->m_vector[i].get();
+ JSValue dest = storage->m_vector[destinationIndex].get();
+ // Any time we overwrite a hole we know we overcounted the number of values we removed
+ // when we subtracted count from m_numValuesInVector above.
+ if (!dest && destinationIndex >= firstIndexAfterShiftRegion)
+ storage->m_numValuesInVector++;
+ storage->m_vector[count + i].setWithoutWriteBarrier(source);
+ }
+ } else {
+ memmove(storage->m_vector + count,
+ storage->m_vector,
+ sizeof(JSValue) * startIndex);
+ }
}
// Adjust the Butterfly and the index bias. We only need to do this here because we're changing
// the start of the Butterfly, which needs to point at the first indexed property in the used
// portion of the vector.
- m_butterfly.setWithoutWriteBarrier(m_butterfly->shift(structure(), count));
- storage = m_butterfly->arrayStorage();
+ Butterfly* butterfly = m_butterfly.get(this)->shift(structure(), count);
+ m_butterfly.setWithoutBarrier(butterfly);
+ storage = butterfly->arrayStorage();
storage->m_indexBias += count;
// Since we're consuming part of the vector by moving its beginning to the left,
@@ -729,10 +821,22 @@ bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, Ar
} else {
// The number of elements before the shift region is greater than or equal to the number
// of elements after the shift region, so we move the elements after the shift region to the left.
- memmove(
- storage->m_vector + startIndex,
- storage->m_vector + firstIndexAfterShiftRegion,
- sizeof(JSValue) * numElementsAfterShiftRegion);
+ if (storage->hasHoles()) {
+ for (unsigned i = 0; i < numElementsAfterShiftRegion; ++i) {
+ unsigned destinationIndex = startIndex + i;
+ JSValue source = storage->m_vector[firstIndexAfterShiftRegion + i].get();
+ JSValue dest = storage->m_vector[destinationIndex].get();
+ // Any time we overwrite a hole we know we overcounted the number of values we removed
+ // when we subtracted count from m_numValuesInVector above.
+ if (!dest && destinationIndex < firstIndexAfterShiftRegion)
+ storage->m_numValuesInVector++;
+ storage->m_vector[startIndex + i].setWithoutWriteBarrier(source);
+ }
+ } else {
+ memmove(storage->m_vector + startIndex,
+ storage->m_vector + firstIndexAfterShiftRegion,
+ sizeof(JSValue) * numElementsAfterShiftRegion);
+ }
// Clear the slots of the elements we just moved.
unsigned startOfEmptyVectorTail = usedVectorLength - count;
for (unsigned i = startOfEmptyVectorTail; i < usedVectorLength; ++i)
@@ -746,11 +850,14 @@ bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, Ar
return true;
}
-bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex, unsigned count)
+bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned& startIndex, unsigned count)
{
+ VM& vm = exec->vm();
RELEASE_ASSERT(count > 0);
+
+ Butterfly* butterfly = m_butterfly.get(this);
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ArrayClass:
return true;
@@ -760,78 +867,79 @@ bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex
case ArrayWithInt32:
case ArrayWithContiguous: {
- unsigned oldLength = m_butterfly->publicLength();
+ unsigned oldLength = butterfly->publicLength();
RELEASE_ASSERT(count <= oldLength);
// We may have to walk the entire array to do the shift. We're willing to do
// so only if it's not horribly slow.
if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
- return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
+ return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm));
// Storing to a hole is fine since we're still having a good time. But reading from a hole
// is totally not fine, since we might have to read from the proto chain.
// We have to check for holes before we start moving things around so that we don't get halfway
// through shifting and then realize we should have been in ArrayStorage mode.
unsigned end = oldLength - count;
- for (unsigned i = startIndex; i < end; ++i) {
- JSValue v = m_butterfly->contiguous()[i + count].get();
- if (UNLIKELY(!v))
- return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
+ if (this->structure(vm)->holesMustForwardToPrototype(vm)) {
+ for (unsigned i = startIndex; i < end; ++i) {
+ JSValue v = butterfly->contiguous()[i + count].get();
+ if (UNLIKELY(!v)) {
+ startIndex = i;
+ return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm));
+ }
+ butterfly->contiguous()[i].setWithoutWriteBarrier(v);
+ }
+ } else {
+ memmove(butterfly->contiguous().data() + startIndex,
+ butterfly->contiguous().data() + startIndex + count,
+ sizeof(JSValue) * (end - startIndex));
}
- for (unsigned i = startIndex; i < end; ++i) {
- JSValue v = m_butterfly->contiguous()[i + count].get();
- ASSERT(v);
- // No need for a barrier since we're just moving data around in the same vector.
- // This is in line with our standing assumption that we won't have a deletion
- // barrier.
- m_butterfly->contiguous()[i].setWithoutWriteBarrier(v);
- }
for (unsigned i = end; i < oldLength; ++i)
- m_butterfly->contiguous()[i].clear();
+ butterfly->contiguous()[i].clear();
- m_butterfly->setPublicLength(oldLength - count);
+ butterfly->setPublicLength(oldLength - count);
return true;
}
case ArrayWithDouble: {
- unsigned oldLength = m_butterfly->publicLength();
+ unsigned oldLength = butterfly->publicLength();
RELEASE_ASSERT(count <= oldLength);
// We may have to walk the entire array to do the shift. We're willing to do
// so only if it's not horribly slow.
if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX)
- return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
+ return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm));
// Storing to a hole is fine since we're still having a good time. But reading from a hole
// is totally not fine, since we might have to read from the proto chain.
// We have to check for holes before we start moving things around so that we don't get halfway
// through shifting and then realize we should have been in ArrayStorage mode.
unsigned end = oldLength - count;
- for (unsigned i = startIndex; i < end; ++i) {
- double v = m_butterfly->contiguousDouble()[i + count];
- if (UNLIKELY(v != v))
- return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
- }
-
- for (unsigned i = startIndex; i < end; ++i) {
- double v = m_butterfly->contiguousDouble()[i + count];
- ASSERT(v == v);
- // No need for a barrier since we're just moving data around in the same vector.
- // This is in line with our standing assumption that we won't have a deletion
- // barrier.
- m_butterfly->contiguousDouble()[i] = v;
+ if (this->structure(vm)->holesMustForwardToPrototype(vm)) {
+ for (unsigned i = startIndex; i < end; ++i) {
+ double v = butterfly->contiguousDouble()[i + count];
+ if (UNLIKELY(v != v)) {
+ startIndex = i;
+ return shiftCountWithArrayStorage(vm, startIndex, count, ensureArrayStorage(vm));
+ }
+ butterfly->contiguousDouble()[i] = v;
+ }
+ } else {
+ memmove(butterfly->contiguousDouble().data() + startIndex,
+ butterfly->contiguousDouble().data() + startIndex + count,
+ sizeof(JSValue) * (end - startIndex));
}
for (unsigned i = end; i < oldLength; ++i)
- m_butterfly->contiguousDouble()[i] = QNaN;
+ butterfly->contiguousDouble()[i] = PNaN;
- m_butterfly->setPublicLength(oldLength - count);
+ butterfly->setPublicLength(oldLength - count);
return true;
}
case ArrayWithArrayStorage:
case ArrayWithSlowPutArrayStorage:
- return shiftCountWithArrayStorage(startIndex, count, arrayStorage());
+ return shiftCountWithArrayStorage(vm, startIndex, count, arrayStorage());
default:
CRASH();
@@ -848,7 +956,7 @@ bool JSArray::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex,
// If the array contains holes or is otherwise in an abnormal state,
// use the generic algorithm in ArrayPrototype.
- if (length != storage->m_numValuesInVector || storage->inSparseMode() || shouldUseSlowPut(structure()->indexingType()))
+ if (storage->hasHoles() || storage->inSparseMode() || shouldUseSlowPut(indexingType()))
return false;
bool moveFront = !startIndex || startIndex < length / 2;
@@ -886,7 +994,9 @@ bool JSArray::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex,
bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex, unsigned count)
{
- switch (structure()->indexingType()) {
+ Butterfly* butterfly = m_butterfly.get(this);
+
+ switch (indexingType()) {
case ArrayClass:
case ArrayWithUndecided:
// We could handle this. But it shouldn't ever come up, so we won't.
@@ -894,7 +1004,7 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
case ArrayWithInt32:
case ArrayWithContiguous: {
- unsigned oldLength = m_butterfly->publicLength();
+ unsigned oldLength = butterfly->publicLength();
// We may have to walk the entire array to do the unshift. We're willing to do so
// only if it's not horribly slow.
@@ -902,19 +1012,20 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
ensureLength(exec->vm(), oldLength + count);
+ butterfly = m_butterfly.get(this);
// We have to check for holes before we start moving things around so that we don't get halfway
// through shifting and then realize we should have been in ArrayStorage mode.
for (unsigned i = oldLength; i-- > startIndex;) {
- JSValue v = m_butterfly->contiguous()[i].get();
+ JSValue v = butterfly->contiguous()[i].get();
if (UNLIKELY(!v))
return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
}
for (unsigned i = oldLength; i-- > startIndex;) {
- JSValue v = m_butterfly->contiguous()[i].get();
+ JSValue v = butterfly->contiguous()[i].get();
ASSERT(v);
- m_butterfly->contiguous()[i + count].setWithoutWriteBarrier(v);
+ butterfly->contiguous()[i + count].setWithoutWriteBarrier(v);
}
// NOTE: we're leaving being garbage in the part of the array that we shifted out
@@ -926,7 +1037,7 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
}
case ArrayWithDouble: {
- unsigned oldLength = m_butterfly->publicLength();
+ unsigned oldLength = butterfly->publicLength();
// We may have to walk the entire array to do the unshift. We're willing to do so
// only if it's not horribly slow.
@@ -934,19 +1045,20 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
ensureLength(exec->vm(), oldLength + count);
+ butterfly = m_butterfly.get(this);
// We have to check for holes before we start moving things around so that we don't get halfway
// through shifting and then realize we should have been in ArrayStorage mode.
for (unsigned i = oldLength; i-- > startIndex;) {
- double v = m_butterfly->contiguousDouble()[i];
+ double v = butterfly->contiguousDouble()[i];
if (UNLIKELY(v != v))
return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
}
for (unsigned i = oldLength; i-- > startIndex;) {
- double v = m_butterfly->contiguousDouble()[i];
+ double v = butterfly->contiguousDouble()[i];
ASSERT(v == v);
- m_butterfly->contiguousDouble()[i + count] = v;
+ butterfly->contiguousDouble()[i + count] = v;
}
// NOTE: we're leaving being garbage in the part of the array that we shifted out
@@ -967,526 +1079,15 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
}
}
-static int compareNumbersForQSortWithInt32(const void* a, const void* b)
-{
- int32_t ia = static_cast<const JSValue*>(a)->asInt32();
- int32_t ib = static_cast<const JSValue*>(b)->asInt32();
- return ia - ib;
-}
-
-static int compareNumbersForQSortWithDouble(const void* a, const void* b)
-{
- double da = *static_cast<const double*>(a);
- double db = *static_cast<const double*>(b);
- return (da > db) - (da < db);
-}
-
-static int compareNumbersForQSort(const void* a, const void* b)
-{
- double da = static_cast<const JSValue*>(a)->asNumber();
- double db = static_cast<const JSValue*>(b)->asNumber();
- return (da > db) - (da < db);
-}
-
-static int compareByStringPairForQSort(const void* a, const void* b)
-{
- const ValueStringPair* va = static_cast<const ValueStringPair*>(a);
- const ValueStringPair* vb = static_cast<const ValueStringPair*>(b);
- return codePointCompare(va->second, vb->second);
-}
-
-template<IndexingType indexingType>
-void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
-{
- ASSERT(indexingType == ArrayWithInt32 || indexingType == ArrayWithDouble || indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage);
-
- unsigned lengthNotIncludingUndefined;
- unsigned newRelevantLength;
- compactForSorting<indexingType>(
- lengthNotIncludingUndefined,
- newRelevantLength);
-
- ContiguousJSValues data = indexingData<indexingType>();
-
- if (indexingType == ArrayWithArrayStorage && arrayStorage()->m_sparseMap.get()) {
- throwOutOfMemoryError(exec);
- return;
- }
-
- if (!lengthNotIncludingUndefined)
- return;
-
- bool allValuesAreNumbers = true;
- switch (indexingType) {
- case ArrayWithInt32:
- case ArrayWithDouble:
- break;
-
- default:
- for (size_t i = 0; i < newRelevantLength; ++i) {
- if (!data[i].isNumber()) {
- allValuesAreNumbers = false;
- break;
- }
- }
- break;
- }
-
- if (!allValuesAreNumbers)
- return sort(exec, compareFunction, callType, callData);
-
- // For numeric comparison, which is fast, qsort is faster than mergesort. We
- // also don't require mergesort's stability, since there's no user visible
- // side-effect from swapping the order of equal primitive values.
- int (*compare)(const void*, const void*);
- switch (indexingType) {
- case ArrayWithInt32:
- compare = compareNumbersForQSortWithInt32;
- break;
-
- case ArrayWithDouble:
- compare = compareNumbersForQSortWithDouble;
- ASSERT(sizeof(WriteBarrier<Unknown>) == sizeof(double));
- break;
-
- default:
- compare = compareNumbersForQSort;
- break;
- }
- ASSERT(data.length() >= newRelevantLength);
- qsort(data.data(), newRelevantLength, sizeof(WriteBarrier<Unknown>), compare);
- return;
-}
-
-void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
-{
- ASSERT(!inSparseIndexingMode());
-
- switch (structure()->indexingType()) {
- case ArrayClass:
- return;
-
- case ArrayWithInt32:
- sortNumericVector<ArrayWithInt32>(exec, compareFunction, callType, callData);
- break;
-
- case ArrayWithDouble:
- sortNumericVector<ArrayWithDouble>(exec, compareFunction, callType, callData);
- break;
-
- case ArrayWithContiguous:
- sortNumericVector<ArrayWithContiguous>(exec, compareFunction, callType, callData);
- return;
-
- case ArrayWithArrayStorage:
- sortNumericVector<ArrayWithArrayStorage>(exec, compareFunction, callType, callData);
- return;
-
- default:
- CRASH();
- return;
- }
-}
-
-template <IndexingType> struct ContiguousTypeAccessor {
- typedef WriteBarrier<Unknown> Type;
- static JSValue getAsValue(ContiguousData<Type> data, size_t i) { return data[i].get(); }
- static void setWithValue(VM& vm, JSArray* thisValue, ContiguousData<Type> data, size_t i, JSValue value)
- {
- data[i].set(vm, thisValue, value);
- }
- static void replaceDataReference(ContiguousData<Type>* outData, ContiguousJSValues inData)
- {
- *outData = inData;
- }
-};
-
-template <> struct ContiguousTypeAccessor<ArrayWithDouble> {
- typedef double Type;
- static JSValue getAsValue(ContiguousData<Type> data, size_t i) { ASSERT(data[i] == data[i]); return JSValue(JSValue::EncodeAsDouble, data[i]); }
- static void setWithValue(VM&, JSArray*, ContiguousData<Type> data, size_t i, JSValue value)
- {
- data[i] = value.asNumber();
- }
- static NO_RETURN_DUE_TO_CRASH void replaceDataReference(ContiguousData<Type>*, ContiguousJSValues)
- {
- RELEASE_ASSERT_WITH_MESSAGE(0, "Inconsistent indexing types during compact array sort.");
- }
-};
-
-
-template<IndexingType indexingType, typename StorageType>
-void JSArray::sortCompactedVector(ExecState* exec, ContiguousData<StorageType> data, unsigned relevantLength)
-{
- if (!relevantLength)
- return;
-
- VM& vm = exec->vm();
-
- // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that.
- // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary
- // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return
- // random or otherwise changing results, effectively making compare function inconsistent.
-
- Vector<ValueStringPair, 0, UnsafeVectorOverflow> values(relevantLength);
- if (!values.begin()) {
- throwOutOfMemoryError(exec);
- return;
- }
-
- Heap::heap(this)->pushTempSortVector(&values);
-
- bool isSortingPrimitiveValues = true;
-
- for (size_t i = 0; i < relevantLength; i++) {
- JSValue value = ContiguousTypeAccessor<indexingType>::getAsValue(data, i);
- ASSERT(indexingType != ArrayWithInt32 || value.isInt32());
- ASSERT(!value.isUndefined());
- values[i].first = value;
- if (indexingType != ArrayWithDouble && indexingType != ArrayWithInt32)
- isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive();
- }
-
- // FIXME: The following loop continues to call toString on subsequent values even after
- // a toString call raises an exception.
-
- for (size_t i = 0; i < relevantLength; i++)
- values[i].second = values[i].first.toWTFStringInline(exec);
-
- if (exec->hadException()) {
- Heap::heap(this)->popTempSortVector(&values);
- return;
- }
-
- // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather
- // than O(N log N).
-
-#if HAVE(MERGESORT)
- if (isSortingPrimitiveValues)
- qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
- else
- mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
-#else
- // FIXME: The qsort library function is likely to not be a stable sort.
- // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort.
- qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
-#endif
-
- // If the toString function changed the length of the array or vector storage,
- // increase the length to handle the orignal number of actual values.
- switch (indexingType) {
- case ArrayWithInt32:
- case ArrayWithDouble:
- case ArrayWithContiguous:
- ensureLength(vm, relevantLength);
- break;
-
- case ArrayWithArrayStorage:
- if (arrayStorage()->vectorLength() < relevantLength) {
- increaseVectorLength(exec->vm(), relevantLength);
- ContiguousTypeAccessor<indexingType>::replaceDataReference(&data, arrayStorage()->vector());
- }
- if (arrayStorage()->length() < relevantLength)
- arrayStorage()->setLength(relevantLength);
- break;
-
- default:
- CRASH();
- }
-
- for (size_t i = 0; i < relevantLength; i++)
- ContiguousTypeAccessor<indexingType>::setWithValue(vm, this, data, i, values[i].first);
-
- Heap::heap(this)->popTempSortVector(&values);
-}
-
-void JSArray::sort(ExecState* exec)
-{
- ASSERT(!inSparseIndexingMode());
-
- switch (structure()->indexingType()) {
- case ArrayClass:
- case ArrayWithUndecided:
- return;
-
- case ArrayWithInt32: {
- unsigned lengthNotIncludingUndefined;
- unsigned newRelevantLength;
- compactForSorting<ArrayWithInt32>(
- lengthNotIncludingUndefined, newRelevantLength);
-
- sortCompactedVector<ArrayWithInt32>(
- exec, m_butterfly->contiguousInt32(), lengthNotIncludingUndefined);
- return;
- }
-
- case ArrayWithDouble: {
- unsigned lengthNotIncludingUndefined;
- unsigned newRelevantLength;
- compactForSorting<ArrayWithDouble>(
- lengthNotIncludingUndefined, newRelevantLength);
-
- sortCompactedVector<ArrayWithDouble>(
- exec, m_butterfly->contiguousDouble(), lengthNotIncludingUndefined);
- return;
- }
-
- case ArrayWithContiguous: {
- unsigned lengthNotIncludingUndefined;
- unsigned newRelevantLength;
- compactForSorting<ArrayWithContiguous>(
- lengthNotIncludingUndefined, newRelevantLength);
-
- sortCompactedVector<ArrayWithContiguous>(
- exec, m_butterfly->contiguous(), lengthNotIncludingUndefined);
- return;
- }
-
- case ArrayWithArrayStorage: {
- unsigned lengthNotIncludingUndefined;
- unsigned newRelevantLength;
- compactForSorting<ArrayWithArrayStorage>(
- lengthNotIncludingUndefined, newRelevantLength);
- ArrayStorage* storage = m_butterfly->arrayStorage();
- ASSERT(!storage->m_sparseMap);
-
- sortCompactedVector<ArrayWithArrayStorage>(exec, storage->vector(), lengthNotIncludingUndefined);
- return;
- }
-
- default:
- RELEASE_ASSERT_NOT_REACHED();
- }
-}
-
-struct AVLTreeNodeForArrayCompare {
- JSValue value;
-
- // Child pointers. The high bit of gt is robbed and used as the
- // balance factor sign. The high bit of lt is robbed and used as
- // the magnitude of the balance factor.
- int32_t gt;
- int32_t lt;
-};
-
-struct AVLTreeAbstractorForArrayCompare {
- typedef int32_t handle; // Handle is an index into m_nodes vector.
- typedef JSValue key;
- typedef int32_t size;
-
- Vector<AVLTreeNodeForArrayCompare, 0, UnsafeVectorOverflow> m_nodes;
- ExecState* m_exec;
- JSValue m_compareFunction;
- CallType m_compareCallType;
- const CallData* m_compareCallData;
- OwnPtr<CachedCall> m_cachedCall;
-
- handle get_less(handle h) { return m_nodes[h].lt & 0x7FFFFFFF; }
- void set_less(handle h, handle lh) { m_nodes[h].lt &= 0x80000000; m_nodes[h].lt |= lh; }
- handle get_greater(handle h) { return m_nodes[h].gt & 0x7FFFFFFF; }
- void set_greater(handle h, handle gh) { m_nodes[h].gt &= 0x80000000; m_nodes[h].gt |= gh; }
-
- int get_balance_factor(handle h)
- {
- if (m_nodes[h].gt & 0x80000000)
- return -1;
- return static_cast<unsigned>(m_nodes[h].lt) >> 31;
- }
-
- void set_balance_factor(handle h, int bf)
- {
- if (bf == 0) {
- m_nodes[h].lt &= 0x7FFFFFFF;
- m_nodes[h].gt &= 0x7FFFFFFF;
- } else {
- m_nodes[h].lt |= 0x80000000;
- if (bf < 0)
- m_nodes[h].gt |= 0x80000000;
- else
- m_nodes[h].gt &= 0x7FFFFFFF;
- }
- }
-
- int compare_key_key(key va, key vb)
- {
- ASSERT(!va.isUndefined());
- ASSERT(!vb.isUndefined());
-
- if (m_exec->hadException())
- return 1;
-
- double compareResult;
- if (m_cachedCall) {
- m_cachedCall->setThis(jsUndefined());
- m_cachedCall->setArgument(0, va);
- m_cachedCall->setArgument(1, vb);
- compareResult = m_cachedCall->call().toNumber(m_exec);
- } else {
- MarkedArgumentBuffer arguments;
- arguments.append(va);
- arguments.append(vb);
- compareResult = call(m_exec, m_compareFunction, m_compareCallType, *m_compareCallData, jsUndefined(), arguments).toNumber(m_exec);
- }
- return (compareResult < 0) ? -1 : 1; // Not passing equality through, because we need to store all values, even if equivalent.
- }
-
- int compare_key_node(key k, handle h) { return compare_key_key(k, m_nodes[h].value); }
- int compare_node_node(handle h1, handle h2) { return compare_key_key(m_nodes[h1].value, m_nodes[h2].value); }
-
- static handle null() { return 0x7FFFFFFF; }
-};
-
-template<IndexingType indexingType>
-void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
-{
- ASSERT(!inSparseIndexingMode());
- ASSERT(indexingType == structure()->indexingType());
-
- // FIXME: This ignores exceptions raised in the compare function or in toNumber.
-
- // The maximum tree depth is compiled in - but the caller is clearly up to no good
- // if a larger array is passed.
- ASSERT(m_butterfly->publicLength() <= static_cast<unsigned>(std::numeric_limits<int>::max()));
- if (m_butterfly->publicLength() > static_cast<unsigned>(std::numeric_limits<int>::max()))
- return;
-
- unsigned usedVectorLength = relevantLength<indexingType>();
- unsigned nodeCount = usedVectorLength;
-
- if (!nodeCount)
- return;
-
- AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items
- tree.abstractor().m_exec = exec;
- tree.abstractor().m_compareFunction = compareFunction;
- tree.abstractor().m_compareCallType = callType;
- tree.abstractor().m_compareCallData = &callData;
- tree.abstractor().m_nodes.grow(nodeCount);
-
- if (callType == CallTypeJS)
- tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, jsCast<JSFunction*>(compareFunction), 2));
-
- if (!tree.abstractor().m_nodes.begin()) {
- throwOutOfMemoryError(exec);
- return;
- }
-
- // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified
- // right out from under us while we're building the tree here.
-
- unsigned numDefined = 0;
- unsigned numUndefined = 0;
-
- // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree.
- for (; numDefined < usedVectorLength; ++numDefined) {
- if (numDefined >= m_butterfly->vectorLength())
- break;
- JSValue v = getHolyIndexQuickly(numDefined);
- if (!v || v.isUndefined())
- break;
- tree.abstractor().m_nodes[numDefined].value = v;
- tree.insert(numDefined);
- }
- for (unsigned i = numDefined; i < usedVectorLength; ++i) {
- if (i >= m_butterfly->vectorLength())
- break;
- JSValue v = getHolyIndexQuickly(i);
- if (v) {
- if (v.isUndefined())
- ++numUndefined;
- else {
- tree.abstractor().m_nodes[numDefined].value = v;
- tree.insert(numDefined);
- ++numDefined;
- }
- }
- }
-
- unsigned newUsedVectorLength = numDefined + numUndefined;
-
- // The array size may have changed. Figure out the new bounds.
- unsigned newestUsedVectorLength = currentRelevantLength();
-
- unsigned elementsToExtractThreshold = min(min(newestUsedVectorLength, numDefined), static_cast<unsigned>(tree.abstractor().m_nodes.size()));
- unsigned undefinedElementsThreshold = min(newestUsedVectorLength, newUsedVectorLength);
- unsigned clearElementsThreshold = min(newestUsedVectorLength, usedVectorLength);
-
- // Copy the values back into m_storage.
- AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter;
- iter.start_iter_least(tree);
- VM& vm = exec->vm();
- for (unsigned i = 0; i < elementsToExtractThreshold; ++i) {
- ASSERT(i < butterfly()->vectorLength());
- if (structure()->indexingType() == ArrayWithDouble)
- butterfly()->contiguousDouble()[i] = tree.abstractor().m_nodes[*iter].value.asNumber();
- else
- currentIndexingData()[i].set(vm, this, tree.abstractor().m_nodes[*iter].value);
- ++iter;
- }
- // Put undefined values back in.
- switch (structure()->indexingType()) {
- case ArrayWithInt32:
- case ArrayWithDouble:
- ASSERT(elementsToExtractThreshold == undefinedElementsThreshold);
- break;
-
- default:
- for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i) {
- ASSERT(i < butterfly()->vectorLength());
- currentIndexingData()[i].setUndefined();
- }
- }
-
- // Ensure that unused values in the vector are zeroed out.
- for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i) {
- ASSERT(i < butterfly()->vectorLength());
- if (structure()->indexingType() == ArrayWithDouble)
- butterfly()->contiguousDouble()[i] = QNaN;
- else
- currentIndexingData()[i].clear();
- }
-
- if (hasArrayStorage(structure()->indexingType()))
- arrayStorage()->m_numValuesInVector = newUsedVectorLength;
-}
-
-void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
-{
- ASSERT(!inSparseIndexingMode());
-
- switch (structure()->indexingType()) {
- case ArrayClass:
- case ArrayWithUndecided:
- return;
-
- case ArrayWithInt32:
- sortVector<ArrayWithInt32>(exec, compareFunction, callType, callData);
- return;
-
- case ArrayWithDouble:
- sortVector<ArrayWithDouble>(exec, compareFunction, callType, callData);
- return;
-
- case ArrayWithContiguous:
- sortVector<ArrayWithContiguous>(exec, compareFunction, callType, callData);
- return;
-
- case ArrayWithArrayStorage:
- sortVector<ArrayWithArrayStorage>(exec, compareFunction, callType, callData);
- return;
-
- default:
- RELEASE_ASSERT_NOT_REACHED();
- }
-}
-
void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
{
unsigned i = 0;
unsigned vectorEnd;
WriteBarrier<Unknown>* vector;
+
+ Butterfly* butterfly = m_butterfly.get(this);
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ArrayClass:
return;
@@ -1498,16 +1099,16 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
case ArrayWithInt32:
case ArrayWithContiguous: {
- vectorEnd = m_butterfly->publicLength();
- vector = m_butterfly->contiguous().data();
+ vectorEnd = butterfly->publicLength();
+ vector = butterfly->contiguous().data();
break;
}
case ArrayWithDouble: {
vector = 0;
vectorEnd = 0;
- for (; i < m_butterfly->publicLength(); ++i) {
- double v = butterfly()->contiguousDouble()[i];
+ for (; i < butterfly->publicLength(); ++i) {
+ double v = butterfly->contiguousDouble()[i];
if (v != v)
break;
args.append(JSValue(JSValue::EncodeAsDouble, v));
@@ -1516,7 +1117,7 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
}
case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
- ArrayStorage* storage = m_butterfly->arrayStorage();
+ ArrayStorage* storage = butterfly->arrayStorage();
vector = storage->m_vector;
vectorEnd = min(storage->length(), storage->vectorLength());
@@ -1525,9 +1126,11 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
default:
CRASH();
+#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
vector = 0;
vectorEnd = 0;
break;
+#endif
}
for (; i < vectorEnd; ++i) {
@@ -1536,19 +1139,25 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
break;
args.append(v.get());
}
-
+
+ // FIXME: What prevents this from being called with a RuntimeArray? The length function will always return 0 in that case.
for (; i < length(); ++i)
args.append(get(exec, i));
}
-void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length)
+void JSArray::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length)
{
- unsigned i = 0;
+ unsigned i = offset;
WriteBarrier<Unknown>* vector;
unsigned vectorEnd;
-
+ length += offset; // We like to think of the length as being our length, rather than the output length.
+
+ // FIXME: What prevents this from being called with a RuntimeArray? The length function will always return 0 in that case.
ASSERT(length == this->length());
- switch (structure()->indexingType()) {
+
+ Butterfly* butterfly = m_butterfly.get(this);
+
+ switch (indexingType()) {
case ArrayClass:
return;
@@ -1560,26 +1169,26 @@ void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t le
case ArrayWithInt32:
case ArrayWithContiguous: {
- vector = m_butterfly->contiguous().data();
- vectorEnd = m_butterfly->publicLength();
+ vector = butterfly->contiguous().data();
+ vectorEnd = butterfly->publicLength();
break;
}
case ArrayWithDouble: {
vector = 0;
vectorEnd = 0;
- for (; i < m_butterfly->publicLength(); ++i) {
- ASSERT(i < butterfly()->vectorLength());
- double v = m_butterfly->contiguousDouble()[i];
+ for (; i < butterfly->publicLength(); ++i) {
+ ASSERT(i < butterfly->vectorLength());
+ double v = butterfly->contiguousDouble()[i];
if (v != v)
break;
- callFrame->setArgument(i, JSValue(JSValue::EncodeAsDouble, v));
+ exec->r(firstElementDest + i - offset) = JSValue(JSValue::EncodeAsDouble, v);
}
break;
}
case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: {
- ArrayStorage* storage = m_butterfly->arrayStorage();
+ ArrayStorage* storage = butterfly->arrayStorage();
vector = storage->m_vector;
vectorEnd = min(length, storage->vectorLength());
break;
@@ -1587,111 +1196,25 @@ void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t le
default:
CRASH();
+#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
vector = 0;
vectorEnd = 0;
break;
+#endif
}
for (; i < vectorEnd; ++i) {
WriteBarrier<Unknown>& v = vector[i];
if (!v)
break;
- callFrame->setArgument(i, v.get());
+ exec->r(firstElementDest + i - offset) = v.get();
}
- for (; i < length; ++i)
- callFrame->setArgument(i, get(exec, i));
-}
-
-template<IndexingType indexingType>
-void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLength)
-{
- ASSERT(!inSparseIndexingMode());
- ASSERT(indexingType == structure()->indexingType());
-
- unsigned myRelevantLength = relevantLength<indexingType>();
-
- numDefined = 0;
- unsigned numUndefined = 0;
-
- for (; numDefined < myRelevantLength; ++numDefined) {
- ASSERT(numDefined < m_butterfly->vectorLength());
- if (indexingType == ArrayWithInt32) {
- JSValue v = m_butterfly->contiguousInt32()[numDefined].get();
- if (!v)
- break;
- ASSERT(v.isInt32());
- continue;
- }
- if (indexingType == ArrayWithDouble) {
- double v = m_butterfly->contiguousDouble()[numDefined];
- if (v != v)
- break;
- continue;
- }
- JSValue v = indexingData<indexingType>()[numDefined].get();
- if (!v || v.isUndefined())
- break;
- }
-
- for (unsigned i = numDefined; i < myRelevantLength; ++i) {
- ASSERT(i < m_butterfly->vectorLength());
- if (indexingType == ArrayWithInt32) {
- JSValue v = m_butterfly->contiguousInt32()[i].get();
- if (!v)
- continue;
- ASSERT(v.isInt32());
- ASSERT(numDefined < m_butterfly->vectorLength());
- m_butterfly->contiguousInt32()[numDefined++].setWithoutWriteBarrier(v);
- continue;
- }
- if (indexingType == ArrayWithDouble) {
- double v = m_butterfly->contiguousDouble()[i];
- if (v != v)
- continue;
- ASSERT(numDefined < m_butterfly->vectorLength());
- m_butterfly->contiguousDouble()[numDefined++] = v;
- continue;
- }
- JSValue v = indexingData<indexingType>()[i].get();
- if (v) {
- if (v.isUndefined())
- ++numUndefined;
- else {
- ASSERT(numDefined < m_butterfly->vectorLength());
- indexingData<indexingType>()[numDefined++].setWithoutWriteBarrier(v);
- }
- }
- }
-
- newRelevantLength = numDefined + numUndefined;
-
- if (hasArrayStorage(indexingType))
- RELEASE_ASSERT(!arrayStorage()->m_sparseMap);
-
- switch (indexingType) {
- case ArrayWithInt32:
- case ArrayWithDouble:
- RELEASE_ASSERT(numDefined == newRelevantLength);
- break;
-
- default:
- for (unsigned i = numDefined; i < newRelevantLength; ++i) {
- ASSERT(i < m_butterfly->vectorLength());
- indexingData<indexingType>()[i].setUndefined();
- }
- break;
- }
- for (unsigned i = newRelevantLength; i < myRelevantLength; ++i) {
- ASSERT(i < m_butterfly->vectorLength());
- if (indexingType == ArrayWithDouble)
- m_butterfly->contiguousDouble()[i] = QNaN;
- else
- indexingData<indexingType>()[i].clear();
+ for (; i < length; ++i) {
+ exec->r(firstElementDest + i - offset) = get(exec, i);
+ if (UNLIKELY(exec->vm().exception()))
+ return;
}
-
- if (hasArrayStorage(indexingType))
- arrayStorage()->m_numValuesInVector = newRelevantLength;
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h
index fe30d9f96..3dd0797b0 100644
--- a/Source/JavaScriptCore/runtime/JSArray.h
+++ b/Source/JavaScriptCore/runtime/JSArray.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, 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
@@ -37,6 +37,7 @@ class JSArray : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames;
static size_t allocationSize(size_t inlineCapacity)
{
@@ -52,6 +53,7 @@ protected:
public:
static JSArray* create(VM&, Structure*, unsigned initialLength = 0);
+ static JSArray* createWithButterfly(VM&, Structure*, Butterfly*);
// tryCreateUninitialized is used for fast construction of arrays whose size and
// contents are known at time of creation. Clients of this interface must:
@@ -61,20 +63,34 @@ public:
JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool throwException);
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
DECLARE_EXPORT_INFO;
-
+
+ // OK if we know this is a JSArray, but not if it could be an object of a derived class; for RuntimeArray this always returns 0.
unsigned length() const { return getArrayLength(); }
- // OK to use on new arrays, but not if it might be a RegExpMatchArray.
- bool setLength(ExecState*, unsigned, bool throwException = false);
- void sort(ExecState*);
- void sort(ExecState*, JSValue compareFunction, CallType, const CallData&);
- void sortNumeric(ExecState*, JSValue compareFunction, CallType, const CallData&);
+ // OK to use on new arrays, but not if it might be a RegExpMatchArray or RuntimeArray.
+ JS_EXPORT_PRIVATE bool setLength(ExecState*, unsigned, bool throwException = false);
+
+ JS_EXPORT_PRIVATE void push(ExecState*, JSValue);
+ JS_EXPORT_PRIVATE JSValue pop(ExecState*);
- void push(ExecState*, JSValue);
- JSValue pop(ExecState*);
+ JSArray* fastSlice(ExecState&, unsigned startIndex, unsigned count);
+
+ static IndexingType fastConcatType(VM& vm, JSArray& firstArray, JSArray& secondArray)
+ {
+ IndexingType type = firstArray.indexingType();
+ if (type != secondArray.indexingType())
+ return NonArray;
+ if (type != ArrayWithDouble && type != ArrayWithInt32 && type != ArrayWithContiguous)
+ return NonArray;
+ if (firstArray.structure(vm)->holesMustForwardToPrototype(vm)
+ || secondArray.structure(vm)->holesMustForwardToPrototype(vm))
+ return NonArray;
+ return type;
+ }
+ EncodedJSValue fastConcatWith(ExecState&, JSArray&);
enum ShiftCountMode {
// This form of shift hints that we're doing queueing. With this assumption in hand,
@@ -89,14 +105,14 @@ public:
bool shiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count)
{
- return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
+ return shiftCountWithArrayStorage(exec->vm(), startIndex, count, ensureArrayStorage(exec->vm()));
}
- bool shiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count)
+ bool shiftCountForSplice(ExecState* exec, unsigned& startIndex, unsigned count)
{
return shiftCountWithAnyIndexingType(exec, startIndex, count);
}
template<ShiftCountMode shiftCountMode>
- bool shiftCount(ExecState* exec, unsigned startIndex, unsigned count)
+ bool shiftCount(ExecState* exec, unsigned& startIndex, unsigned count)
{
switch (shiftCountMode) {
case ShiftCountForShift:
@@ -131,8 +147,8 @@ public:
}
}
- void fillArgList(ExecState*, MarkedArgumentBuffer&);
- void copyToArguments(ExecState*, CallFrame*, uint32_t length);
+ JS_EXPORT_PRIVATE void fillArgList(ExecState*, MarkedArgumentBuffer&);
+ JS_EXPORT_PRIVATE void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length);
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType)
{
@@ -140,7 +156,6 @@ public:
}
protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags;
static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
static bool deleteProperty(JSCell*, ExecState*, PropertyName);
@@ -156,27 +171,15 @@ private:
return !map || !map->lengthIsReadOnly();
}
- bool shiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count);
- bool shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage*);
+ bool shiftCountWithAnyIndexingType(ExecState*, unsigned& startIndex, unsigned count);
+ JS_EXPORT_PRIVATE bool shiftCountWithArrayStorage(VM&, unsigned startIndex, unsigned count, ArrayStorage*);
bool unshiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count);
bool unshiftCountWithArrayStorage(ExecState*, unsigned startIndex, unsigned count, ArrayStorage*);
bool unshiftCountSlowCase(VM&, bool, unsigned);
- template<IndexingType indexingType>
- void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&);
-
- template<IndexingType indexingType, typename StorageType>
- void sortCompactedVector(ExecState*, ContiguousData<StorageType>, unsigned relevantLength);
-
- template<IndexingType indexingType>
- void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&);
-
bool setLengthWithArrayStorage(ExecState*, unsigned newLength, bool throwException, ArrayStorage*);
void setLengthWritable(ExecState*, bool writable);
-
- template<IndexingType indexingType>
- void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength);
};
inline Butterfly* createContiguousArrayButterfly(VM& vm, JSCell* intendedOwner, unsigned length, unsigned& vectorLength)
@@ -208,7 +211,7 @@ Butterfly* createArrayButterflyInDictionaryIndexingMode(
inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLength)
{
Butterfly* butterfly;
- if (LIKELY(!hasArrayStorage(structure->indexingType()))) {
+ if (LIKELY(!hasAnyArrayStorage(structure->indexingType()))) {
ASSERT(
hasUndecided(structure->indexingType())
|| hasInt32(structure->indexingType())
@@ -216,10 +219,10 @@ inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLe
|| hasContiguous(structure->indexingType()));
unsigned vectorLength;
butterfly = createContiguousArrayButterfly(vm, 0, initialLength, vectorLength);
- ASSERT(initialLength < MIN_SPARSE_ARRAY_INDEX);
+ ASSERT(initialLength < MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH);
if (hasDouble(structure->indexingType())) {
for (unsigned i = 0; i < vectorLength; ++i)
- butterfly->contiguousDouble()[i] = QNaN;
+ butterfly->contiguousDouble()[i] = PNaN;
}
} else {
ASSERT(
@@ -227,9 +230,8 @@ inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLe
|| structure->indexingType() == ArrayWithArrayStorage);
butterfly = createArrayButterfly(vm, 0, initialLength);
}
- JSArray* array = new (NotNull, allocateCell<JSArray>(vm.heap)) JSArray(vm, structure, butterfly);
- array->finishCreation(vm);
- return array;
+
+ return createWithButterfly(vm, structure, butterfly);
}
inline JSArray* JSArray::tryCreateUninitialized(VM& vm, Structure* structure, unsigned initialLength)
@@ -237,9 +239,11 @@ inline JSArray* JSArray::tryCreateUninitialized(VM& vm, Structure* structure, un
unsigned vectorLength = std::max(BASE_VECTOR_LEN, initialLength);
if (vectorLength > MAX_STORAGE_VECTOR_LENGTH)
return 0;
-
+
+ unsigned outOfLineStorage = structure->outOfLineCapacity();
+
Butterfly* butterfly;
- if (LIKELY(!hasArrayStorage(structure->indexingType()))) {
+ if (LIKELY(!hasAnyArrayStorage(structure->indexingType()))) {
ASSERT(
hasUndecided(structure->indexingType())
|| hasInt32(structure->indexingType())
@@ -247,27 +251,32 @@ inline JSArray* JSArray::tryCreateUninitialized(VM& vm, Structure* structure, un
|| hasContiguous(structure->indexingType()));
void* temp;
- if (!vm.heap.tryAllocateStorage(0, Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp))
+ if (!vm.heap.tryAllocateStorage(0, Butterfly::totalSize(0, outOfLineStorage, true, vectorLength * sizeof(EncodedJSValue)), &temp))
return 0;
- butterfly = Butterfly::fromBase(temp, 0, 0);
+ butterfly = Butterfly::fromBase(temp, 0, outOfLineStorage);
butterfly->setVectorLength(vectorLength);
butterfly->setPublicLength(initialLength);
if (hasDouble(structure->indexingType())) {
for (unsigned i = initialLength; i < vectorLength; ++i)
- butterfly->contiguousDouble()[i] = QNaN;
+ butterfly->contiguousDouble()[i] = PNaN;
}
} else {
void* temp;
- if (!vm.heap.tryAllocateStorage(0, Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength)), &temp))
+ if (!vm.heap.tryAllocateStorage(0, Butterfly::totalSize(0, outOfLineStorage, true, ArrayStorage::sizeFor(vectorLength)), &temp))
return 0;
- butterfly = Butterfly::fromBase(temp, 0, 0);
+ butterfly = Butterfly::fromBase(temp, 0, outOfLineStorage);
*butterfly->indexingHeader() = indexingHeaderForArray(initialLength, vectorLength);
ArrayStorage* storage = butterfly->arrayStorage();
storage->m_indexBias = 0;
storage->m_sparseMap.clear();
storage->m_numValuesInVector = initialLength;
}
-
+
+ return createWithButterfly(vm, structure, butterfly);
+}
+
+inline JSArray* JSArray::createWithButterfly(VM& vm, Structure* structure, Butterfly* butterfly)
+{
JSArray* array = new (NotNull, allocateCell<JSArray>(vm.heap)) JSArray(vm, structure, butterfly);
array->finishCreation(vm);
return array;
diff --git a/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp b/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp
index b24e09ef9..62ab89a3d 100644
--- a/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp
+++ b/Source/JavaScriptCore/runtime/JSArrayBuffer.cpp
@@ -26,13 +26,13 @@
#include "config.h"
#include "JSArrayBuffer.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "Reject.h"
namespace JSC {
const ClassInfo JSArrayBuffer::s_info = {
- "ArrayBuffer", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArrayBuffer)};
+ "ArrayBuffer", &Base::s_info, 0, CREATE_METHOD_TABLE(JSArrayBuffer)};
JSArrayBuffer::JSArrayBuffer(VM& vm, Structure* structure, PassRefPtr<ArrayBuffer> arrayBuffer)
: Base(vm, structure)
@@ -119,7 +119,7 @@ void JSArrayBuffer::getOwnNonIndexPropertyNames(
{
JSArrayBuffer* thisObject = jsCast<JSArrayBuffer*>(object);
- if (mode == IncludeDontEnumProperties)
+ if (mode.includeDontEnumProperties())
array.add(exec->propertyNames().byteLength);
Base::getOwnNonIndexPropertyNames(thisObject, exec, array, mode);
diff --git a/Source/JavaScriptCore/runtime/JSArrayBuffer.h b/Source/JavaScriptCore/runtime/JSArrayBuffer.h
index 319b82e5a..7529e3634 100644
--- a/Source/JavaScriptCore/runtime/JSArrayBuffer.h
+++ b/Source/JavaScriptCore/runtime/JSArrayBuffer.h
@@ -34,6 +34,7 @@ namespace JSC {
class JSArrayBuffer : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetPropertyNames | OverridesGetOwnPropertySlot;
protected:
JSArrayBuffer(VM&, Structure*, PassRefPtr<ArrayBuffer>);
@@ -56,8 +57,6 @@ protected:
static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
- static const unsigned StructureFlags = OverridesGetPropertyNames | OverridesGetOwnPropertySlot | Base::StructureFlags;
-
private:
ArrayBuffer* m_impl;
};
diff --git a/Source/JavaScriptCore/runtime/JSArrayBufferConstructor.cpp b/Source/JavaScriptCore/runtime/JSArrayBufferConstructor.cpp
index ca7e030e8..03f077784 100644
--- a/Source/JavaScriptCore/runtime/JSArrayBufferConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/JSArrayBufferConstructor.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 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,17 +28,18 @@
#include "Error.h"
#include "ExceptionHelpers.h"
+#include "GetterSetter.h"
#include "JSArrayBuffer.h"
#include "JSArrayBufferPrototype.h"
#include "JSGlobalObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
static EncodedJSValue JSC_HOST_CALL arrayBufferFuncIsView(ExecState*);
const ClassInfo JSArrayBufferConstructor::s_info = {
- "Function", &Base::s_info, 0, 0,
+ "Function", &Base::s_info, 0,
CREATE_METHOD_TABLE(JSArrayBufferConstructor)
};
@@ -47,22 +48,23 @@ JSArrayBufferConstructor::JSArrayBufferConstructor(VM& vm, Structure* structure)
{
}
-void JSArrayBufferConstructor::finishCreation(VM& vm, JSArrayBufferPrototype* prototype)
+void JSArrayBufferConstructor::finishCreation(VM& vm, JSArrayBufferPrototype* prototype, GetterSetter* speciesSymbol)
{
- Base::finishCreation(vm, "ArrayBuffer");
+ Base::finishCreation(vm, ASCIILiteral("ArrayBuffer"));
putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly);
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), DontEnum | DontDelete | ReadOnly);
+ putDirectNonIndexAccessor(vm, vm.propertyNames->speciesSymbol, speciesSymbol, Accessor | ReadOnly | DontEnum);
JSGlobalObject* globalObject = this->globalObject();
- JSC_NATIVE_FUNCTION(vm.propertyNames->isView, arrayBufferFuncIsView, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->isView, arrayBufferFuncIsView, DontEnum, 1);
}
-JSArrayBufferConstructor* JSArrayBufferConstructor::create(VM& vm, Structure* structure, JSArrayBufferPrototype* prototype)
+JSArrayBufferConstructor* JSArrayBufferConstructor::create(VM& vm, Structure* structure, JSArrayBufferPrototype* prototype, GetterSetter* speciesSymbol)
{
JSArrayBufferConstructor* result =
new (NotNull, allocateCell<JSArrayBufferConstructor>(vm.heap))
JSArrayBufferConstructor(vm, structure);
- result->finishCreation(vm, prototype);
+ result->finishCreation(vm, prototype, speciesSymbol);
return result;
}
@@ -92,14 +94,19 @@ static EncodedJSValue JSC_HOST_CALL constructArrayBuffer(ExecState* exec)
RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(length, 1);
if (!buffer)
- return throwVMError(exec, createOutOfMemoryError(constructor->globalObject()));
-
- JSArrayBuffer* result = JSArrayBuffer::create(
- exec->vm(), constructor->globalObject()->arrayBufferStructure(), buffer);
+ return throwVMError(exec, createOutOfMemoryError(exec));
+
+ Structure* arrayBufferStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), constructor->globalObject()->arrayBufferStructure());
+ JSArrayBuffer* result = JSArrayBuffer::create(exec->vm(), arrayBufferStructure, buffer.release());
return JSValue::encode(result);
}
+static EncodedJSValue JSC_HOST_CALL callArrayBuffer(ExecState* exec)
+{
+ return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(exec, "ArrayBuffer"));
+}
+
ConstructType JSArrayBufferConstructor::getConstructData(
JSCell*, ConstructData& constructData)
{
@@ -109,7 +116,7 @@ ConstructType JSArrayBufferConstructor::getConstructData(
CallType JSArrayBufferConstructor::getCallData(JSCell*, CallData& callData)
{
- callData.native.function = constructArrayBuffer;
+ callData.native.function = callArrayBuffer;
return CallTypeHost;
}
diff --git a/Source/JavaScriptCore/runtime/JSArrayBufferConstructor.h b/Source/JavaScriptCore/runtime/JSArrayBufferConstructor.h
index b65b523b6..61ee80326 100644
--- a/Source/JavaScriptCore/runtime/JSArrayBufferConstructor.h
+++ b/Source/JavaScriptCore/runtime/JSArrayBufferConstructor.h
@@ -31,6 +31,7 @@
namespace JSC {
class JSArrayBufferPrototype;
+class GetterSetter;
class JSArrayBufferConstructor : public InternalFunction {
public:
@@ -38,10 +39,10 @@ public:
protected:
JSArrayBufferConstructor(VM&, Structure*);
- void finishCreation(VM&, JSArrayBufferPrototype*);
+ void finishCreation(VM&, JSArrayBufferPrototype*, GetterSetter* speciesSymbol);
public:
- static JSArrayBufferConstructor* create(VM&, Structure*, JSArrayBufferPrototype*);
+ static JSArrayBufferConstructor* create(VM&, Structure*, JSArrayBufferPrototype*, GetterSetter* speciesSymbol);
DECLARE_INFO;
diff --git a/Source/JavaScriptCore/runtime/JSArrayBufferPrototype.cpp b/Source/JavaScriptCore/runtime/JSArrayBufferPrototype.cpp
index 42889f7ea..d29e283f2 100644
--- a/Source/JavaScriptCore/runtime/JSArrayBufferPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/JSArrayBufferPrototype.cpp
@@ -30,7 +30,7 @@
#include "ExceptionHelpers.h"
#include "JSArrayBuffer.h"
#include "JSFunction.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "TypedArrayAdaptors.h"
namespace JSC {
@@ -41,10 +41,10 @@ static EncodedJSValue JSC_HOST_CALL arrayBufferProtoFuncSlice(ExecState* exec)
JSArrayBuffer* thisObject = jsDynamicCast<JSArrayBuffer*>(exec->thisValue());
if (!thisObject)
- return throwVMError(exec, createTypeError(exec, "Receiver of slice must be an array buffer."));
+ return throwVMError(exec, createTypeError(exec, ASCIILiteral("Receiver of slice must be an array buffer.")));
if (!exec->argumentCount())
- return throwVMError(exec, createTypeError(exec, "Slice requires at least one argument."));
+ return throwVMError(exec, createTypeError(exec, ASCIILiteral("Slice requires at least one argument.")));
int32_t begin = exec->argument(0).toInt32(exec);
if (exec->hadException())
@@ -60,7 +60,7 @@ static EncodedJSValue JSC_HOST_CALL arrayBufferProtoFuncSlice(ExecState* exec)
RefPtr<ArrayBuffer> newBuffer = thisObject->impl()->slice(begin, end);
if (!newBuffer)
- return throwVMError(exec, createOutOfMemoryError(callee->globalObject()));
+ return throwVMError(exec, createOutOfMemoryError(exec));
Structure* structure = callee->globalObject()->arrayBufferStructure();
@@ -70,7 +70,7 @@ static EncodedJSValue JSC_HOST_CALL arrayBufferProtoFuncSlice(ExecState* exec)
}
const ClassInfo JSArrayBufferPrototype::s_info = {
- "ArrayBufferPrototype", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArrayBufferPrototype)
+ "ArrayBufferPrototype", &Base::s_info, 0, CREATE_METHOD_TABLE(JSArrayBufferPrototype)
};
JSArrayBufferPrototype::JSArrayBufferPrototype(VM& vm, Structure* structure)
@@ -82,7 +82,8 @@ void JSArrayBufferPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject
{
Base::finishCreation(vm);
- JSC_NATIVE_FUNCTION(vm.propertyNames->slice, arrayBufferProtoFuncSlice, DontEnum, 2);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->slice, arrayBufferProtoFuncSlice, DontEnum, 2);
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "ArrayBuffer"), DontEnum | ReadOnly);
}
JSArrayBufferPrototype* JSArrayBufferPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
diff --git a/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp b/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp
index c9812688e..b514fa0f9 100644
--- a/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp
+++ b/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -27,13 +27,13 @@
#include "JSArrayBufferView.h"
#include "JSArrayBuffer.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "Reject.h"
namespace JSC {
const ClassInfo JSArrayBufferView::s_info = {
- "ArrayBufferView", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArrayBufferView)
+ "ArrayBufferView", &Base::s_info, 0, CREATE_METHOD_TABLE(JSArrayBufferView)
};
JSArrayBufferView::ConstructionContext::ConstructionContext(
@@ -78,7 +78,7 @@ JSArrayBufferView::ConstructionContext::ConstructionContext(
return;
}
- vm.heap.reportExtraMemoryCost(static_cast<size_t>(length) * elementSize);
+ vm.heap.reportExtraMemoryAllocated(static_cast<size_t>(length) * elementSize);
m_structure = structure;
m_mode = OversizeTypedArray;
@@ -88,10 +88,10 @@ JSArrayBufferView::ConstructionContext::ConstructionContext(
VM& vm, Structure* structure, PassRefPtr<ArrayBuffer> arrayBuffer,
unsigned byteOffset, unsigned length)
: m_structure(structure)
- , m_vector(static_cast<uint8_t*>(arrayBuffer->data()) + byteOffset)
, m_length(length)
, m_mode(WastefulTypedArray)
{
+ m_vector = static_cast<uint8_t*>(arrayBuffer->data()) + byteOffset;
IndexingHeader indexingHeader;
indexingHeader.setArrayBuffer(arrayBuffer.get());
m_butterfly = Butterfly::create(vm, 0, 0, 0, true, indexingHeader, 0);
@@ -101,19 +101,19 @@ JSArrayBufferView::ConstructionContext::ConstructionContext(
Structure* structure, PassRefPtr<ArrayBuffer> arrayBuffer,
unsigned byteOffset, unsigned length, DataViewTag)
: m_structure(structure)
- , m_vector(static_cast<uint8_t*>(arrayBuffer->data()) + byteOffset)
, m_length(length)
, m_mode(DataViewMode)
, m_butterfly(0)
{
+ m_vector = static_cast<uint8_t*>(arrayBuffer->data()) + byteOffset;
}
JSArrayBufferView::JSArrayBufferView(VM& vm, ConstructionContext& context)
: Base(vm, context.structure(), context.butterfly())
- , m_vector(context.vector())
, m_length(context.length())
, m_mode(context.mode())
{
+ m_vector.setWithoutBarrier(static_cast<char*>(context.vector()));
}
void JSArrayBufferView::finishCreation(VM& vm)
@@ -140,10 +140,6 @@ bool JSArrayBufferView::getOwnPropertySlot(
JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(object);
- if (propertyName == exec->propertyNames().byteOffset) {
- slot.setValue(thisObject, DontDelete | ReadOnly, jsNumber(thisObject->byteOffset()));
- return true;
- }
if (propertyName == exec->propertyNames().buffer) {
slot.setValue(
@@ -160,9 +156,7 @@ void JSArrayBufferView::put(
PutPropertySlot& slot)
{
JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(cell);
- if (propertyName == exec->propertyNames().byteLength
- || propertyName == exec->propertyNames().byteOffset
- || propertyName == exec->propertyNames().buffer) {
+ if (propertyName == exec->propertyNames().buffer) {
reject(exec, slot.isStrictMode(), "Attempting to write to read-only typed array property.");
return;
}
@@ -175,9 +169,7 @@ bool JSArrayBufferView::defineOwnProperty(
const PropertyDescriptor& descriptor, bool shouldThrow)
{
JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(object);
- if (propertyName == exec->propertyNames().byteLength
- || propertyName == exec->propertyNames().byteOffset
- || propertyName == exec->propertyNames().buffer)
+ if (propertyName == exec->propertyNames().buffer)
return reject(exec, shouldThrow, "Attempting to define read-only typed array property.");
return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
@@ -187,9 +179,7 @@ bool JSArrayBufferView::deleteProperty(
JSCell* cell, ExecState* exec, PropertyName propertyName)
{
JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(cell);
- if (propertyName == exec->propertyNames().byteLength
- || propertyName == exec->propertyNames().byteOffset
- || propertyName == exec->propertyNames().buffer)
+ if (propertyName == exec->propertyNames().buffer)
return false;
return Base::deleteProperty(thisObject, exec, propertyName);
@@ -200,12 +190,9 @@ void JSArrayBufferView::getOwnNonIndexPropertyNames(
{
JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(object);
- // length/byteOffset/byteLength are DontEnum, at least in Firefox.
- if (mode == IncludeDontEnumProperties) {
- array.add(exec->propertyNames().byteOffset);
- array.add(exec->propertyNames().byteLength);
+ if (mode.includeDontEnumProperties())
array.add(exec->propertyNames().buffer);
- }
+
Base::getOwnNonIndexPropertyNames(thisObject, exec, array, mode);
}
@@ -215,8 +202,33 @@ void JSArrayBufferView::finalize(JSCell* cell)
JSArrayBufferView* thisObject = static_cast<JSArrayBufferView*>(cell);
ASSERT(thisObject->m_mode == OversizeTypedArray || thisObject->m_mode == WastefulTypedArray);
if (thisObject->m_mode == OversizeTypedArray)
- fastFree(thisObject->m_vector);
+ fastFree(thisObject->m_vector.getWithoutBarrier());
}
} // namespace JSC
+namespace WTF {
+
+using namespace JSC;
+
+void printInternal(PrintStream& out, TypedArrayMode mode)
+{
+ switch (mode) {
+ case FastTypedArray:
+ out.print("FastTypedArray");
+ return;
+ case OversizeTypedArray:
+ out.print("OversizeTypedArray");
+ return;
+ case WastefulTypedArray:
+ out.print("WastefulTypedArray");
+ return;
+ case DataViewMode:
+ out.print("DataViewMode");
+ return;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace WTF
+
diff --git a/Source/JavaScriptCore/runtime/JSArrayBufferView.h b/Source/JavaScriptCore/runtime/JSArrayBufferView.h
index 3feb03b72..769150b36 100644
--- a/Source/JavaScriptCore/runtime/JSArrayBufferView.h
+++ b/Source/JavaScriptCore/runtime/JSArrayBufferView.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -93,6 +93,7 @@ inline bool hasArrayBuffer(TypedArrayMode mode)
class JSArrayBufferView : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetPropertyNames | OverridesGetOwnPropertySlot;
static const unsigned fastSizeLimit = 1000;
@@ -158,9 +159,18 @@ public:
ArrayBuffer* buffer();
PassRefPtr<ArrayBufferView> impl();
+ bool isNeutered() { return hasArrayBuffer() && !vector(); }
void neuter();
- void* vector() { return m_vector; }
+ void* vector()
+ {
+ return m_vector.getPredicated(
+ this,
+ [this] () -> bool {
+ return mode() == FastTypedArray;
+ });
+ }
+
unsigned byteOffset();
unsigned length() const { return m_length; }
@@ -174,16 +184,20 @@ private:
static void finalize(JSCell*);
protected:
- static const unsigned StructureFlags = OverridesGetPropertyNames | OverridesGetOwnPropertySlot | Base::StructureFlags;
-
ArrayBuffer* existingBufferInButterfly();
- void* m_vector;
+ CopyBarrier<char> m_vector; // this is really a void*, but void would not work here.
uint32_t m_length;
TypedArrayMode m_mode;
};
} // namespace JSC
+namespace WTF {
+
+void printInternal(PrintStream&, JSC::TypedArrayMode);
+
+} // namespace WTF
+
#endif // JSArrayBufferView_h
diff --git a/Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h b/Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h
index de4e8587c..3c4b054ba 100644
--- a/Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h
+++ b/Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h
@@ -59,16 +59,18 @@ inline void JSArrayBufferView::neuter()
{
ASSERT(hasArrayBuffer());
m_length = 0;
- m_vector = 0;
+ m_vector.clear();
}
inline unsigned JSArrayBufferView::byteOffset()
{
if (!hasArrayBuffer())
return 0;
-
+
+ ASSERT(!vector() == !buffer()->data());
+
ptrdiff_t delta =
- static_cast<uint8_t*>(m_vector) - static_cast<uint8_t*>(buffer()->data());
+ bitwise_cast<uint8_t*>(vector()) - static_cast<uint8_t*>(buffer()->data());
unsigned result = static_cast<unsigned>(delta);
ASSERT(static_cast<ptrdiff_t>(result) == delta);
diff --git a/Source/JavaScriptCore/runtime/JSArrayIterator.cpp b/Source/JavaScriptCore/runtime/JSArrayIterator.cpp
index d506c4ebd..0abc9d120 100644
--- a/Source/JavaScriptCore/runtime/JSArrayIterator.cpp
+++ b/Source/JavaScriptCore/runtime/JSArrayIterator.cpp
@@ -29,141 +29,42 @@
#include "JSCJSValueInlines.h"
#include "JSCellInlines.h"
#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
namespace JSC {
-const ClassInfo JSArrayIterator::s_info = { "ArrayIterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArrayIterator) };
+const ClassInfo JSArrayIterator::s_info = { "Array Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(JSArrayIterator) };
-static EncodedJSValue JSC_HOST_CALL arrayIteratorNextKey(ExecState*);
-static EncodedJSValue JSC_HOST_CALL arrayIteratorNextValue(ExecState*);
-static EncodedJSValue JSC_HOST_CALL arrayIteratorNextGeneric(ExecState*);
-
-void JSArrayIterator::finishCreation(VM& vm, JSGlobalObject* globalObject, ArrayIterationKind kind, JSObject* iteratedObject)
+void JSArrayIterator::finishCreation(VM& vm, JSGlobalObject*, ArrayIterationKind kind, JSObject* iteratedObject)
{
Base::finishCreation(vm);
ASSERT(inherits(info()));
- m_iterationKind = kind;
- m_iteratedObject.set(vm, this, iteratedObject);
- switch (kind) {
- case ArrayIterateKey:
- JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->iteratorNextPrivateName, arrayIteratorNextKey, DontEnum, 0, ArrayIteratorNextKeyIntrinsic);
- break;
- case ArrayIterateValue:
- JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->iteratorNextPrivateName, arrayIteratorNextValue, DontEnum, 0, ArrayIteratorNextValueIntrinsic);
- break;
- default:
- JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->iteratorNextPrivateName, arrayIteratorNextGeneric, DontEnum, 0, ArrayIteratorNextGenericIntrinsic);
- break;
- }
+ putDirect(vm, vm.propertyNames->iteratedObjectPrivateName, iteratedObject);
+ putDirect(vm, vm.propertyNames->arrayIteratorNextIndexPrivateName, jsNumber(0));
+ putDirect(vm, vm.propertyNames->arrayIterationKindPrivateName, jsNumber(kind));
}
-
-
-void JSArrayIterator::visitChildren(JSCell* cell, SlotVisitor& visitor)
-{
- JSArrayIterator* thisObject = jsCast<JSArrayIterator*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
- Base::visitChildren(thisObject, visitor);
- visitor.append(&thisObject->m_iteratedObject);
-}
-
-static EncodedJSValue createIteratorResult(CallFrame* callFrame, ArrayIterationKind kind, size_t index, JSValue result, bool done)
+ArrayIterationKind JSArrayIterator::kind(ExecState* exec) const
{
- if (done)
- return JSValue::encode(callFrame->vm().iterationTerminator.get());
-
- switch (kind & ~ArrayIterateSparseTag) {
- case ArrayIterateKey:
- return JSValue::encode(jsNumber(index));
-
- case ArrayIterateValue:
- return JSValue::encode(result);
-
- case ArrayIterateKeyValue: {
- MarkedArgumentBuffer args;
- args.append(jsNumber(index));
- args.append(result);
- JSGlobalObject* globalObject = callFrame->callee()->globalObject();
- return JSValue::encode(constructArray(callFrame, 0, globalObject, args));
-
- }
- default:
- RELEASE_ASSERT_NOT_REACHED();
- }
- return JSValue::encode(JSValue());
+ JSValue kindValue = getDirect(exec->vm(), exec->vm().propertyNames->arrayIterationKindPrivateName);
+ return static_cast<ArrayIterationKind>(kindValue.asInt32());
}
-static inline EncodedJSValue JSC_HOST_CALL arrayIteratorNext(CallFrame* callFrame)
-{
- JSArrayIterator* iterator = jsDynamicCast<JSArrayIterator*>(callFrame->thisValue());
- if (!iterator) {
- ASSERT_NOT_REACHED();
- return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot call ArrayIterator.next() on a non-ArrayIterator object")));
- }
- JSObject* iteratedObject = iterator->iteratedObject();
- size_t index = iterator->nextIndex();
- ArrayIterationKind kind = iterator->iterationKind();
- JSValue jsLength = JSValue(iteratedObject).get(callFrame, callFrame->propertyNames().length);
- if (callFrame->hadException())
- return JSValue::encode(jsNull());
-
- size_t length = jsLength.toUInt32(callFrame);
- if (callFrame->hadException())
- return JSValue::encode(jsNull());
-
- if (index >= length) {
- iterator->finish();
- return createIteratorResult(callFrame, kind, index, jsUndefined(), true);
- }
- if (JSValue result = iteratedObject->tryGetIndexQuickly(index)) {
- iterator->setNextIndex(index + 1);
- return createIteratorResult(callFrame, kind, index, result, false);
- }
-
- JSValue result = jsUndefined();
- PropertySlot slot(iteratedObject);
- if (kind > ArrayIterateSparseTag) {
- // We assume that the indexed property will be an own property so cache the getOwnProperty
- // method locally
- auto getOwnPropertySlotByIndex = iteratedObject->methodTable()->getOwnPropertySlotByIndex;
- while (index < length) {
- if (getOwnPropertySlotByIndex(iteratedObject, callFrame, index, slot)) {
- result = slot.getValue(callFrame, index);
- break;
- }
- if (iteratedObject->getPropertySlot(callFrame, index, slot)) {
- result = slot.getValue(callFrame, index);
- break;
- }
- index++;
- }
- } else if (iteratedObject->getPropertySlot(callFrame, index, slot))
- result = slot.getValue(callFrame, index);
-
- if (index == length)
- iterator->finish();
- else
- iterator->setNextIndex(index + 1);
- return createIteratorResult(callFrame, kind, index, jsUndefined(), index == length);
-}
-
-EncodedJSValue JSC_HOST_CALL arrayIteratorNextKey(CallFrame* callFrame)
-{
- return arrayIteratorNext(callFrame);
-}
-
-EncodedJSValue JSC_HOST_CALL arrayIteratorNextValue(CallFrame* callFrame)
+JSValue JSArrayIterator::iteratedValue(ExecState* exec) const
{
- return arrayIteratorNext(callFrame);
+ return getDirect(exec->vm(), exec->vm().propertyNames->iteratedObjectPrivateName);
}
-
-EncodedJSValue JSC_HOST_CALL arrayIteratorNextGeneric(CallFrame* callFrame)
+
+JSArrayIterator* JSArrayIterator::clone(ExecState* exec)
{
- return arrayIteratorNext(callFrame);
+ VM& vm = exec->vm();
+ JSValue iteratedObject = getDirect(vm, vm.propertyNames->iteratedObjectPrivateName);
+ JSValue nextIndex = getDirect(vm, vm.propertyNames->arrayIteratorNextIndexPrivateName);
+
+ auto clone = JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), kind(exec), asObject(iteratedObject));
+ clone->putDirect(vm, vm.propertyNames->arrayIteratorNextIndexPrivateName, nextIndex);
+ return clone;
}
}
diff --git a/Source/JavaScriptCore/runtime/JSArrayIterator.h b/Source/JavaScriptCore/runtime/JSArrayIterator.h
index 2994a67d1..0166bd2e5 100644
--- a/Source/JavaScriptCore/runtime/JSArrayIterator.h
+++ b/Source/JavaScriptCore/runtime/JSArrayIterator.h
@@ -33,11 +33,7 @@ namespace JSC {
enum ArrayIterationKind : uint32_t {
ArrayIterateKey,
ArrayIterateValue,
- ArrayIterateKeyValue,
- ArrayIterateSparseTag = 4,
- ArrayIterateSparseKey,
- ArrayIterateSparseValue,
- ArrayIterateSparseKeyValue
+ ArrayIterateKeyValue
};
class JSArrayIterator : public JSNonFinalObject {
@@ -59,33 +55,18 @@ public:
return instance;
}
- ArrayIterationKind iterationKind() const { return m_iterationKind; }
- JSObject* iteratedObject() const { return m_iteratedObject.get(); }
- size_t nextIndex() const { return m_nextIndex; }
- void setNextIndex(size_t nextIndex) { m_nextIndex = nextIndex; }
- void finish() { m_nextIndex = std::numeric_limits<uint32_t>::max(); }
-
- using JSNonFinalObject::arrayStorageOrNull;
- static ptrdiff_t offsetOfIterationKind() { return OBJECT_OFFSETOF(JSArrayIterator, m_iterationKind); }
- static ptrdiff_t offsetOfIteratedObject() { return OBJECT_OFFSETOF(JSArrayIterator, m_iteratedObject); }
- static ptrdiff_t offsetOfNextIndex() { return OBJECT_OFFSETOF(JSArrayIterator, m_nextIndex); }
+ ArrayIterationKind kind(ExecState*) const;
+ JSValue iteratedValue(ExecState*) const;
+ JSArrayIterator* clone(ExecState*);
+ using JSNonFinalObject::arrayStorageOrNull;
private:
-
- static const unsigned StructureFlags = Base::StructureFlags | OverridesVisitChildren;
-
JSArrayIterator(VM& vm, Structure* structure)
: Base(vm, structure)
- , m_nextIndex(0)
{
}
void finishCreation(VM&, JSGlobalObject*, ArrayIterationKind, JSObject* iteratedObject);
- static void visitChildren(JSCell*, SlotVisitor&);
-
- ArrayIterationKind m_iterationKind;
- WriteBarrier<JSObject> m_iteratedObject;
- uint32_t m_nextIndex;
};
}
diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
index f22827a37..febe9897d 100644
--- a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
@@ -28,11 +28,11 @@
#include "GetterSetter.h"
#include "JSGlobalObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
-const ClassInfo JSBoundFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSBoundFunction) };
+const ClassInfo JSBoundFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(JSBoundFunction) };
EncodedJSValue JSC_HOST_CALL boundFunctionCall(ExecState* exec)
{
@@ -74,23 +74,31 @@ EncodedJSValue JSC_HOST_CALL boundFunctionConstruct(ExecState* exec)
return JSValue::encode(construct(exec, targetFunction, constructType, constructData, args));
}
+EncodedJSValue JSC_HOST_CALL isBoundFunction(ExecState* exec)
+{
+ return JSValue::encode(JSValue(static_cast<bool>(jsDynamicCast<JSBoundFunction*>(exec->uncheckedArgument(0)))));
+}
+
+EncodedJSValue JSC_HOST_CALL hasInstanceBoundFunction(ExecState* exec)
+{
+ JSBoundFunction* boundObject = jsCast<JSBoundFunction*>(exec->uncheckedArgument(0));
+ JSValue value = exec->uncheckedArgument(1);
+
+ return JSValue::encode(jsBoolean(boundObject->targetFunction()->hasInstance(exec, value)));
+}
+
JSBoundFunction* JSBoundFunction::create(VM& vm, JSGlobalObject* globalObject, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs, int length, const String& name)
{
ConstructData constructData;
ConstructType constructType = JSC::getConstructData(targetFunction, constructData);
bool canConstruct = constructType != ConstructTypeNone;
- NativeExecutable* executable = vm.getHostFunction(boundFunctionCall, canConstruct ? boundFunctionConstruct : callHostFunctionAsConstructor);
+ NativeExecutable* executable = vm.getHostFunction(boundFunctionCall, canConstruct ? boundFunctionConstruct : callHostFunctionAsConstructor, ASCIILiteral("Function.prototype.bind result"));
JSBoundFunction* function = new (NotNull, allocateCell<JSBoundFunction>(vm.heap)) JSBoundFunction(vm, globalObject, globalObject->boundFunctionStructure(), targetFunction, boundThis, boundArgs);
- function->finishCreation(vm, executable, length, name);
+ function->finishCreation(vm, executable, length, makeString("bound ", name));
return function;
}
-void JSBoundFunction::destroy(JSCell* cell)
-{
- static_cast<JSBoundFunction*>(cell)->JSBoundFunction::~JSBoundFunction();
-}
-
bool JSBoundFunction::customHasInstance(JSObject* object, ExecState* exec, JSValue value)
{
return jsCast<JSBoundFunction*>(object)->m_targetFunction->hasInstance(exec, value);
@@ -117,8 +125,6 @@ void JSBoundFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSBoundFunction* thisObject = jsCast<JSBoundFunction*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
Base::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_targetFunction);
@@ -126,4 +132,9 @@ void JSBoundFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitor.append(&thisObject->m_boundArgs);
}
+String JSBoundFunction::toStringName(ExecState* exec)
+{
+ return m_targetFunction->get(exec, exec->vm().propertyNames->name).toWTFString(exec);
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.h b/Source/JavaScriptCore/runtime/JSBoundFunction.h
index 7852f78ce..320ba630a 100644
--- a/Source/JavaScriptCore/runtime/JSBoundFunction.h
+++ b/Source/JavaScriptCore/runtime/JSBoundFunction.h
@@ -32,21 +32,24 @@ namespace JSC {
EncodedJSValue JSC_HOST_CALL boundFunctionCall(ExecState*);
EncodedJSValue JSC_HOST_CALL boundFunctionConstruct(ExecState*);
+EncodedJSValue JSC_HOST_CALL isBoundFunction(ExecState*);
+EncodedJSValue JSC_HOST_CALL hasInstanceBoundFunction(ExecState*);
class JSBoundFunction : public JSFunction {
public:
typedef JSFunction Base;
+ const static unsigned StructureFlags = ~ImplementsDefaultHasInstance & Base::StructureFlags;
static JSBoundFunction* create(VM&, JSGlobalObject*, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs, int, const String&);
- static void destroy(JSCell*);
-
static bool customHasInstance(JSObject*, ExecState*, JSValue);
JSObject* targetFunction() { return m_targetFunction.get(); }
JSValue boundThis() { return m_boundThis.get(); }
JSValue boundArgs() { return m_boundArgs.get(); }
+ String toStringName(ExecState*);
+
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
ASSERT(globalObject);
@@ -56,8 +59,6 @@ public:
DECLARE_INFO;
protected:
- const static unsigned StructureFlags = OverridesHasInstance | OverridesVisitChildren | Base::StructureFlags;
-
static void visitChildren(JSCell*, SlotVisitor&);
private:
diff --git a/Source/JavaScriptCore/runtime/JSBoundSlotBaseFunction.cpp b/Source/JavaScriptCore/runtime/JSBoundSlotBaseFunction.cpp
new file mode 100644
index 000000000..983b17ca5
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSBoundSlotBaseFunction.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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. 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 "JSBoundSlotBaseFunction.h"
+
+#include "CustomGetterSetter.h"
+#include "GetterSetter.h"
+#include "JSCInlines.h"
+#include "JSGlobalObject.h"
+
+namespace JSC {
+
+const ClassInfo JSBoundSlotBaseFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(JSBoundSlotBaseFunction) };
+
+EncodedJSValue JSC_HOST_CALL boundSlotBaseFunctionCall(ExecState* exec)
+{
+ JSBoundSlotBaseFunction* boundSlotBaseFunction = jsCast<JSBoundSlotBaseFunction*>(exec->callee());
+ JSObject* baseObject = boundSlotBaseFunction->boundSlotBase();
+ CustomGetterSetter* customGetterSetter = boundSlotBaseFunction->customGetterSetter();
+
+ if (boundSlotBaseFunction->isSetter()) {
+ callCustomSetter(exec, customGetterSetter, true, baseObject, exec->thisValue(), exec->argument(0));
+ return JSValue::encode(jsUndefined());
+ }
+
+ CustomGetterSetter::CustomGetter getter = customGetterSetter->getter();
+ if (!getter)
+ return JSValue::encode(jsUndefined());
+
+ const String& name = boundSlotBaseFunction->name(exec);
+ return getter(exec, JSValue::encode(exec->thisValue()), PropertyName(Identifier::fromString(exec, name)));
+}
+
+JSBoundSlotBaseFunction::JSBoundSlotBaseFunction(VM& vm, JSGlobalObject* globalObject, Structure* structure, const Type type)
+ : Base(vm, globalObject, structure)
+ , m_type(type)
+{
+}
+
+JSBoundSlotBaseFunction* JSBoundSlotBaseFunction::create(VM& vm, JSGlobalObject* globalObject, JSObject* boundSlotBase, CustomGetterSetter* getterSetter, const Type type, const String& name)
+{
+ NativeExecutable* executable = vm.getHostFunction(boundSlotBaseFunctionCall, callHostFunctionAsConstructor, name);
+
+ JSBoundSlotBaseFunction* function = new (NotNull, allocateCell<JSBoundSlotBaseFunction>(vm.heap)) JSBoundSlotBaseFunction(vm, globalObject, globalObject->boundSlotBaseFunctionStructure(), type);
+
+ // Can't do this during initialization because getHostFunction might do a GC allocation.
+ function->finishCreation(vm, executable, boundSlotBase, getterSetter, name);
+ return function;
+}
+
+void JSBoundSlotBaseFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSBoundSlotBaseFunction* thisObject = jsCast<JSBoundSlotBaseFunction*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_boundSlotBase);
+ visitor.append(&thisObject->m_getterSetter);
+}
+
+void JSBoundSlotBaseFunction::finishCreation(VM& vm, NativeExecutable* executable, JSObject* boundSlotBase, CustomGetterSetter* getterSetter, const String& name)
+{
+ Base::finishCreation(vm, executable, isSetter(), name);
+ ASSERT(inherits(info()));
+ ASSERT(boundSlotBase);
+ ASSERT(getterSetter);
+ m_boundSlotBase.set(vm, this, boundSlotBase);
+ m_getterSetter.set(vm, this, getterSetter);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSBoundSlotBaseFunction.h b/Source/JavaScriptCore/runtime/JSBoundSlotBaseFunction.h
new file mode 100644
index 000000000..c11427970
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSBoundSlotBaseFunction.h
@@ -0,0 +1,75 @@
+/*
+ * 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. 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.
+ */
+
+#ifndef JSBoundSlotBaseFunction_h
+#define JSBoundSlotBaseFunction_h
+
+#include "JSFunction.h"
+
+namespace JSC {
+
+class CustomGetterSetter;
+
+EncodedJSValue JSC_HOST_CALL boundSlotBaseFunctionCall(ExecState*);
+
+class JSBoundSlotBaseFunction : public JSFunction {
+public:
+ typedef JSFunction Base;
+
+ // The Type is set to the number of arguments the resultant function will have.
+ enum class Type { Getter = 0, Setter = 1 };
+
+ static const unsigned StructureFlags = Base::StructureFlags;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ ASSERT(globalObject);
+ return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
+ }
+
+ static JSBoundSlotBaseFunction* create(VM&, JSGlobalObject*, JSObject*, CustomGetterSetter*, const Type, const String&);
+
+ JSObject* boundSlotBase() const { return m_boundSlotBase.get(); }
+ CustomGetterSetter* customGetterSetter() const { return m_getterSetter.get(); }
+ bool isSetter() const { return m_type == Type::Setter; }
+
+ DECLARE_EXPORT_INFO;
+
+protected:
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+private:
+ JSBoundSlotBaseFunction(VM&, JSGlobalObject*, Structure*, Type);
+
+ void finishCreation(VM&, NativeExecutable*, JSObject*, CustomGetterSetter*, const String&);
+
+ WriteBarrier<JSObject> m_boundSlotBase;
+ WriteBarrier<CustomGetterSetter> m_getterSetter;
+ Type m_type;
+};
+
+} // namespace JSC
+
+#endif // JSBoundSlotBaseFunction_h
diff --git a/Source/JavaScriptCore/runtime/JSCInlines.h b/Source/JavaScriptCore/runtime/JSCInlines.h
new file mode 100644
index 000000000..e6b4f57c9
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSCInlines.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef JSCInlines_h
+#define JSCInlines_h
+
+// This file's only purpose is to collect commonly used *Inlines.h files, so that you don't
+// have to include all of them in every .cpp file. Instead you just include this. It's good
+// style to make sure that every .cpp file includes JSCInlines.h.
+//
+// JSC should never include this file, or any *Inline.h file, from interface headers, since
+// this could lead to a circular dependency.
+//
+// WebCore, or any other downstream client of JSC, is allowed to include this file in headers.
+// In fact, it can make a lot of sense: outside of JSC, this file becomes a kind of umbrella
+// header that pulls in most (all?) of the interesting things in JSC.
+
+#include "ExceptionHelpers.h"
+#include "GCIncomingRefCountedInlines.h"
+#include "HeapInlines.h"
+#include "IdentifierInlines.h"
+#include "Interpreter.h"
+#include "JSArrayBufferViewInlines.h"
+#include "JSCJSValueInlines.h"
+#include "JSFunctionInlines.h"
+#include "JSObjectInlines.h"
+#include "JSProxy.h"
+#include "JSString.h"
+#include "Operations.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+#include "WeakGCMapInlines.h"
+
+#endif // JSCInlines_h
diff --git a/Source/JavaScriptCore/runtime/JSCJSValue.cpp b/Source/JavaScriptCore/runtime/JSCJSValue.cpp
index cca6888bf..b9dd0a417 100644
--- a/Source/JavaScriptCore/runtime/JSCJSValue.cpp
+++ b/Source/JavaScriptCore/runtime/JSCJSValue.cpp
@@ -25,6 +25,7 @@
#include "BooleanConstructor.h"
#include "BooleanPrototype.h"
+#include "CustomGetterSetter.h"
#include "Error.h"
#include "ExceptionHelpers.h"
#include "GetterSetter.h"
@@ -33,6 +34,7 @@
#include "JSGlobalObject.h"
#include "JSNotAnObject.h"
#include "NumberObject.h"
+#include "StructureInlines.h"
#include <wtf/MathExtras.h>
#include <wtf/StringExtras.h>
@@ -54,6 +56,18 @@ double JSValue::toIntegerPreserveNaN(ExecState* exec) const
return trunc(toNumber(exec));
}
+double JSValue::toLength(ExecState* exec) const
+{
+ // ECMA 7.1.15
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-tolength
+ double d = toInteger(exec);
+ if (d <= 0)
+ return 0.0;
+ if (std::isinf(d))
+ return 9007199254740991.0; // 2 ** 53 - 1
+ return std::min(d, 9007199254740991.0);
+}
+
double JSValue::toNumberSlowCase(ExecState* exec) const
{
ASSERT(!isInt32() && !isDouble());
@@ -61,7 +75,7 @@ double JSValue::toNumberSlowCase(ExecState* exec) const
return asCell()->toNumber(exec);
if (isTrue())
return 1.0;
- return isUndefined() ? QNaN : 0; // null and false both convert to 0.
+ return isUndefined() ? PNaN : 0; // null and false both convert to 0.
}
JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObject) const
@@ -97,8 +111,10 @@ JSValue JSValue::toThisSlowCase(ExecState* exec, ECMAMode ecmaMode) const
JSObject* JSValue::synthesizePrototype(ExecState* exec) const
{
if (isCell()) {
- ASSERT(isString());
- return exec->lexicalGlobalObject()->stringPrototype();
+ if (isString())
+ return exec->lexicalGlobalObject()->stringPrototype();
+ ASSERT(isSymbol());
+ return exec->lexicalGlobalObject()->symbolPrototype();
}
if (isNumber())
@@ -117,9 +133,8 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue
{
VM& vm = exec->vm();
- unsigned index = propertyName.asIndex();
- if (index != PropertyName::NotAnIndex) {
- putToPrimitiveByIndex(exec, index, value, slot.isStrictMode());
+ if (Optional<uint32_t> index = parseIndex(propertyName)) {
+ putToPrimitiveByIndex(exec, index.value(), value, slot.isStrictMode());
return;
}
@@ -139,8 +154,7 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue
for (; ; obj = asObject(prototype)) {
unsigned attributes;
- JSCell* specificValue;
- PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue);
+ PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes);
if (offset != invalidOffset) {
if (attributes & ReadOnly) {
if (slot.isStrictMode())
@@ -154,6 +168,11 @@ void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue
return;
}
+ if (gs.isCustomGetterSetter()) {
+ callCustomSetter(exec, gs, attributes & CustomAccessor, obj, slot.thisValue(), value);
+ return;
+ }
+
// If there's an existing property on the object or one of its
// prototypes it should be replaced, so break here.
break;
@@ -191,6 +210,13 @@ void JSValue::dump(PrintStream& out) const
void JSValue::dumpInContext(PrintStream& out, DumpContext* context) const
{
+ dumpInContextAssumingStructure(
+ out, context, (!!*this && isCell()) ? asCell()->structure() : nullptr);
+}
+
+void JSValue::dumpInContextAssumingStructure(
+ PrintStream& out, DumpContext* context, Structure* structure) const
+{
if (!*this)
out.print("<JSValue()>");
else if (isInt32())
@@ -207,7 +233,7 @@ void JSValue::dumpInContext(PrintStream& out, DumpContext* context) const
out.printf("Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble());
#endif
} else if (isCell()) {
- if (asCell()->inherits(JSString::info())) {
+ if (structure->classInfo()->isSubClassOf(JSString::info())) {
JSString* string = jsCast<JSString*>(asCell());
out.print("String");
if (string->isRope())
@@ -216,18 +242,62 @@ void JSValue::dumpInContext(PrintStream& out, DumpContext* context) const
if (impl) {
if (impl->isAtomic())
out.print(" (atomic)");
- if (impl->isIdentifier())
+ if (impl->isAtomic())
out.print(" (identifier)");
- if (impl->isEmptyUnique())
- out.print(" (unique)");
+ if (impl->isSymbol())
+ out.print(" (symbol)");
} else
out.print(" (unresolved)");
out.print(": ", impl);
- } else if (asCell()->inherits(Structure::info()))
+ } else if (structure->classInfo()->isSubClassOf(Structure::info()))
out.print("Structure: ", inContext(*jsCast<Structure*>(asCell()), context));
else {
out.print("Cell: ", RawPointer(asCell()));
- out.print(" (", inContext(*asCell()->structure(), context), ")");
+ out.print(" (", inContext(*structure, context), ")");
+ }
+#if USE(JSVALUE64)
+ out.print(", ID: ", asCell()->structureID());
+#endif
+ } else if (isTrue())
+ out.print("True");
+ else if (isFalse())
+ out.print("False");
+ else if (isNull())
+ out.print("Null");
+ else if (isUndefined())
+ out.print("Undefined");
+ else
+ out.print("INVALID");
+}
+
+void JSValue::dumpForBacktrace(PrintStream& out) const
+{
+ if (!*this)
+ out.print("<JSValue()>");
+ else if (isInt32())
+ out.printf("%d", asInt32());
+ else if (isDouble())
+ out.printf("%lf", asDouble());
+ else if (isCell()) {
+ if (asCell()->inherits(JSString::info())) {
+ JSString* string = jsCast<JSString*>(asCell());
+ const StringImpl* impl = string->tryGetValueImpl();
+ if (impl)
+ out.print("\"", impl, "\"");
+ else
+ out.print("(unresolved string)");
+ } else if (asCell()->inherits(Structure::info())) {
+ out.print("Structure[ ", asCell()->structure()->classInfo()->className);
+#if USE(JSVALUE64)
+ out.print(" ID: ", asCell()->structureID());
+#endif
+ out.print("]: ", RawPointer(asCell()));
+ } else {
+ out.print("Cell[", asCell()->structure()->classInfo()->className);
+#if USE(JSVALUE64)
+ out.print(" ID: ", asCell()->structureID());
+#endif
+ out.print("]: ", RawPointer(asCell()));
}
} else if (isTrue())
out.print("True");
@@ -291,12 +361,22 @@ bool JSValue::isValidCallee()
return asObject(asCell())->globalObject();
}
-JSString* JSValue::toStringSlowCase(ExecState* exec) const
+JSString* JSValue::toStringSlowCase(ExecState* exec, bool returnEmptyStringOnError) const
{
+ auto errorValue = [&] () -> JSString* {
+ if (returnEmptyStringOnError)
+ return jsEmptyString(exec);
+ return nullptr;
+ };
+
VM& vm = exec->vm();
ASSERT(!isString());
- if (isInt32())
- return jsString(&vm, vm.numericStrings.add(asInt32()));
+ if (isInt32()) {
+ auto integer = asInt32();
+ if (static_cast<unsigned>(integer) <= 9)
+ return vm.smallStrings.singleCharacterString(integer + '0');
+ return jsNontrivialString(&vm, vm.numericStrings.add(integer));
+ }
if (isDouble())
return jsString(&vm, vm.numericStrings.add(asDouble()));
if (isTrue())
@@ -307,18 +387,38 @@ JSString* JSValue::toStringSlowCase(ExecState* exec) const
return vm.smallStrings.nullString();
if (isUndefined())
return vm.smallStrings.undefinedString();
+ if (isSymbol()) {
+ throwTypeError(exec);
+ return errorValue();
+ }
ASSERT(isCell());
JSValue value = asCell()->toPrimitive(exec, PreferString);
- if (exec->hadException())
- return jsEmptyString(exec);
+ if (vm.exception())
+ return errorValue();
ASSERT(!value.isObject());
- return value.toString(exec);
+ JSString* result = value.toString(exec);
+ if (vm.exception())
+ return errorValue();
+ return result;
}
String JSValue::toWTFStringSlowCase(ExecState* exec) const
{
- return inlineJSValueNotStringtoString(*this, exec);
+ VM& vm = exec->vm();
+ if (isInt32())
+ return vm.numericStrings.add(asInt32());
+ if (isDouble())
+ return vm.numericStrings.add(asDouble());
+ if (isTrue())
+ return vm.propertyNames->trueKeyword.string();
+ if (isFalse())
+ return vm.propertyNames->falseKeyword.string();
+ if (isNull())
+ return vm.propertyNames->nullKeyword.string();
+ if (isUndefined())
+ return vm.propertyNames->undefinedKeyword.string();
+ return toString(exec)->value(exec);
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSCJSValue.h b/Source/JavaScriptCore/runtime/JSCJSValue.h
index 85ac32bdd..4ca069ecb 100644
--- a/Source/JavaScriptCore/runtime/JSCJSValue.h
+++ b/Source/JavaScriptCore/runtime/JSCJSValue.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, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2012, 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 Library General Public
@@ -23,23 +23,23 @@
#ifndef JSCJSValue_h
#define JSCJSValue_h
+#include "JSExportMacros.h"
+#include "PureNaN.h"
+#include <functional>
#include <math.h>
-#include <stddef.h> // for size_t
+#include <stddef.h>
#include <stdint.h>
#include <wtf/Assertions.h>
#include <wtf/Forward.h>
#include <wtf/HashMap.h>
#include <wtf/HashTraits.h>
#include <wtf/MathExtras.h>
+#include <wtf/MediaTime.h>
#include <wtf/StdLibExtras.h>
#include <wtf/TriState.h>
namespace JSC {
-// This is used a lot throughout JavaScriptCore for everything from value boxing to marking
-// values as being missing, so it is useful to have it abbreviated.
-#define QNaN (std::numeric_limits<double>::quiet_NaN())
-
class AssemblyHelpers;
class ExecState;
class JSCell;
@@ -48,9 +48,11 @@ class VM;
class JSGlobalObject;
class JSObject;
class JSString;
+class Identifier;
class PropertyName;
class PropertySlot;
class PutPropertySlot;
+class Structure;
#if ENABLE(DFG_JIT)
namespace DFG {
class JITCompiler;
@@ -58,7 +60,7 @@ class OSRExitCompiler;
class SpeculativeJIT;
}
#endif
-#if ENABLE(LLINT_C_LOOP)
+#if !ENABLE(JIT)
namespace LLInt {
class CLoop;
}
@@ -97,6 +99,15 @@ union EncodedValueDescriptor {
#endif
};
+#define TagOffset (OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag))
+#define PayloadOffset (OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))
+
+#if USE(JSVALUE64)
+#define CellPayloadOffset 0
+#else
+#define CellPayloadOffset PayloadOffset
+#endif
+
enum WhichValueWord {
TagWord,
PayloadWord
@@ -113,8 +124,18 @@ inline uint32_t toUInt32(double number)
return toInt32(number);
}
+int64_t tryConvertToInt52(double);
+bool isInt52(double);
+
+enum class SourceCodeRepresentation {
+ Other,
+ Integer,
+ Double
+};
+
class JSValue {
friend struct EncodedJSValueHashTraits;
+ friend struct EncodedJSValueWithRepresentationHashTraits;
friend class AssemblyHelpers;
friend class JIT;
friend class JITSlowPathCall;
@@ -128,7 +149,7 @@ class JSValue {
friend class DFG::OSRExitCompiler;
friend class DFG::SpeculativeJIT;
#endif
-#if ENABLE(LLINT_C_LOOP)
+#if !ENABLE(JIT)
friend class LLInt::CLoop;
#endif
@@ -176,8 +197,7 @@ public:
explicit JSValue(long long);
explicit JSValue(unsigned long long);
- typedef void* (JSValue::*UnspecifiedBoolType);
- operator UnspecifiedBoolType*() const;
+ explicit operator bool() const;
bool operator==(const JSValue& other) const;
bool operator!=(const JSValue& other) const;
@@ -193,10 +213,13 @@ public:
double asDouble() const;
bool asBoolean() const;
double asNumber() const;
+
+ int32_t asInt32ForArithmetic() const; // Boolean becomes an int, but otherwise like asInt32().
// Querying the type.
bool isEmpty() const;
bool isFunction() const;
+ bool isConstructor() const;
bool isUndefined() const;
bool isNull() const;
bool isUndefinedOrNull() const;
@@ -204,8 +227,10 @@ public:
bool isMachineInt() const;
bool isNumber() const;
bool isString() const;
+ bool isSymbol() const;
bool isPrimitive() const;
bool isGetterSetter() const;
+ bool isCustomGetterSetter() const;
bool isObject() const;
bool inherits(const ClassInfo*) const;
@@ -227,20 +252,22 @@ public:
// toNumber conversion is expected to be side effect free if an exception has
// been set in the ExecState already.
double toNumber(ExecState*) const;
- JSString* toString(ExecState*) const;
+ JSString* toString(ExecState*) const; // On exception, this returns the empty string.
+ JSString* toStringOrNull(ExecState*) const; // On exception, this returns null, to make exception checks faster.
+ Identifier toPropertyKey(ExecState*) const;
WTF::String toWTFString(ExecState*) const;
- WTF::String toWTFStringInline(ExecState*) const;
JSObject* toObject(ExecState*) const;
JSObject* toObject(ExecState*, JSGlobalObject*) const;
// Integer conversions.
JS_EXPORT_PRIVATE double toInteger(ExecState*) const;
- double toIntegerPreserveNaN(ExecState*) const;
+ JS_EXPORT_PRIVATE double toIntegerPreserveNaN(ExecState*) const;
int32_t toInt32(ExecState*) const;
uint32_t toUInt32(ExecState*) const;
+ double toLength(ExecState*) const;
- // Floating point conversions (this is a convenience method for webcore;
- // signle precision float is not a representation used in JS or JSC).
+ // Floating point conversions (this is a convenience function for WebCore;
+ // single precision float is not a representation used in JS or JSC).
float toFloat(ExecState* exec) const { return static_cast<float>(toNumber(exec)); }
// Object operations, with the toObject operation included.
@@ -248,9 +275,13 @@ public:
JSValue get(ExecState*, PropertyName, PropertySlot&) const;
JSValue get(ExecState*, unsigned propertyName) const;
JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const;
+
+ bool getPropertySlot(ExecState*, PropertyName, PropertySlot&) const;
+
void put(ExecState*, PropertyName, JSValue, PutPropertySlot&);
- void putToPrimitive(ExecState*, PropertyName, JSValue, PutPropertySlot&);
- void putToPrimitiveByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
+ void putInline(ExecState*, PropertyName, JSValue, PutPropertySlot&);
+ JS_EXPORT_PRIVATE void putToPrimitive(ExecState*, PropertyName, JSValue, PutPropertySlot&);
+ JS_EXPORT_PRIVATE void putToPrimitiveByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
void putByIndex(ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
JSValue toThis(ExecState*, ECMAMode) const;
@@ -266,35 +297,26 @@ public:
bool isCell() const;
JSCell* asCell() const;
JS_EXPORT_PRIVATE bool isValidCallee();
-
+
JSValue structureOrUndefined() const;
JS_EXPORT_PRIVATE void dump(PrintStream&) const;
void dumpInContext(PrintStream&, DumpContext*) const;
+ void dumpInContextAssumingStructure(PrintStream&, DumpContext*, Structure*) const;
+ void dumpForBacktrace(PrintStream&) const;
JS_EXPORT_PRIVATE JSObject* synthesizePrototype(ExecState*) const;
+ bool requireObjectCoercible(ExecState*) const;
// Constants used for Int52. Int52 isn't part of JSValue right now, but JSValues may be
// converted to Int52s and back again.
static const unsigned numberOfInt52Bits = 52;
+ static const int64_t notInt52 = static_cast<int64_t>(1) << numberOfInt52Bits;
static const unsigned int52ShiftAmount = 12;
static ptrdiff_t offsetOfPayload() { return OBJECT_OFFSETOF(JSValue, u.asBits.payload); }
static ptrdiff_t offsetOfTag() { return OBJECT_OFFSETOF(JSValue, u.asBits.tag); }
-private:
- template <class T> JSValue(WriteBarrierBase<T>);
-
- enum HashTableDeletedValueTag { HashTableDeletedValue };
- JSValue(HashTableDeletedValueTag);
-
- inline const JSValue asValue() const { return *this; }
- JS_EXPORT_PRIVATE double toNumberSlowCase(ExecState*) const;
- JS_EXPORT_PRIVATE JSString* toStringSlowCase(ExecState*) const;
- JS_EXPORT_PRIVATE WTF::String toWTFStringSlowCase(ExecState*) const;
- JS_EXPORT_PRIVATE JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const;
- JS_EXPORT_PRIVATE JSValue toThisSlowCase(ExecState*, ECMAMode) const;
-
#if USE(JSVALUE32_64)
/*
* On 32-bit platforms USE(JSVALUE32_64) should be defined, and we use a NaN-encoded
@@ -317,7 +339,7 @@ private:
uint32_t tag() const;
int32_t payload() const;
-#if ENABLE(LLINT_C_LOOP)
+#if !ENABLE(JIT)
// This should only be used by the LLInt C Loop interpreter who needs
// synthesize JSValue from its "register"s holding tag and payload
// values.
@@ -340,7 +362,7 @@ private:
*
* This range of NaN space is represented by 64-bit numbers begining with the 16-bit
* hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no valid double-precision
- * numbers will begin fall in these ranges.
+ * numbers will fall in these ranges.
*
* The top 16-bits denote the type of the encoded JSValue:
*
@@ -354,7 +376,7 @@ private:
* 64-bit integer addition of the value 2^48 to the number. After this manipulation
* no encoded double-precision value will begin with the pattern 0x0000 or 0xFFFF.
* Values must be decoded by reversing this operation before subsequent floating point
- * operations my be peformed.
+ * operations may be peformed.
*
* 32-bit signed integers are marked with the 16-bit tag 0xFFFF.
*
@@ -407,6 +429,19 @@ private:
#define ValueDeleted 0x4ll
#endif
+private:
+ template <class T> JSValue(WriteBarrierBase<T>);
+
+ enum HashTableDeletedValueTag { HashTableDeletedValue };
+ JSValue(HashTableDeletedValueTag);
+
+ inline const JSValue asValue() const { return *this; }
+ JS_EXPORT_PRIVATE double toNumberSlowCase(ExecState*) const;
+ JS_EXPORT_PRIVATE JSString* toStringSlowCase(ExecState*, bool returnEmptyStringOnError) const;
+ JS_EXPORT_PRIVATE WTF::String toWTFStringSlowCase(ExecState*) const;
+ JS_EXPORT_PRIVATE JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const;
+ JS_EXPORT_PRIVATE JSValue toThisSlowCase(ExecState*, ECMAMode) const;
+
EncodedValueDescriptor u;
};
@@ -426,7 +461,26 @@ struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> {
};
#endif
-typedef HashMap<EncodedJSValue, unsigned, EncodedJSValueHash, EncodedJSValueHashTraits> JSValueMap;
+typedef std::pair<EncodedJSValue, SourceCodeRepresentation> EncodedJSValueWithRepresentation;
+
+struct EncodedJSValueWithRepresentationHashTraits : HashTraits<EncodedJSValueWithRepresentation> {
+ static const bool emptyValueIsZero = false;
+ static EncodedJSValueWithRepresentation emptyValue() { return std::make_pair(JSValue::encode(JSValue()), SourceCodeRepresentation::Other); }
+ static void constructDeletedValue(EncodedJSValueWithRepresentation& slot) { slot = std::make_pair(JSValue::encode(JSValue(JSValue::HashTableDeletedValue)), SourceCodeRepresentation::Other); }
+ static bool isDeletedValue(EncodedJSValueWithRepresentation value) { return value == std::make_pair(JSValue::encode(JSValue(JSValue::HashTableDeletedValue)), SourceCodeRepresentation::Other); }
+};
+
+struct EncodedJSValueWithRepresentationHash {
+ static unsigned hash(const EncodedJSValueWithRepresentation& value)
+ {
+ return WTF::pairIntHash(EncodedJSValueHash::hash(value.first), IntHash<SourceCodeRepresentation>::hash(value.second));
+ }
+ static bool equal(const EncodedJSValueWithRepresentation& a, const EncodedJSValueWithRepresentation& b)
+ {
+ return a == b;
+ }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
// Stand-alone helper functions.
inline JSValue jsNull()
@@ -439,6 +493,11 @@ inline JSValue jsUndefined()
return JSValue(JSValue::JSUndefined);
}
+inline JSValue jsTDZValue()
+{
+ return JSValue();
+}
+
inline JSValue jsBoolean(bool b)
{
return b ? JSValue(JSValue::JSTrue) : JSValue(JSValue::JSFalse);
@@ -456,6 +515,11 @@ ALWAYS_INLINE JSValue jsNumber(double d)
return JSValue(d);
}
+ALWAYS_INLINE JSValue jsNumber(MediaTime t)
+{
+ return jsNumber(t.toDouble());
+}
+
ALWAYS_INLINE JSValue jsNumber(char i)
{
return JSValue(i);
diff --git a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h
index b34adf809..6ce961517 100644
--- a/Source/JavaScriptCore/runtime/JSCJSValueInlines.h
+++ b/Source/JavaScriptCore/runtime/JSCJSValueInlines.h
@@ -26,10 +26,14 @@
#ifndef JSValueInlines_h
#define JSValueInlines_h
+#include "ExceptionHelpers.h"
+#include "Identifier.h"
#include "InternalFunction.h"
#include "JSCJSValue.h"
#include "JSCellInlines.h"
+#include "JSObject.h"
#include "JSFunction.h"
+#include <wtf/text/StringImpl.h>
namespace JSC {
@@ -42,7 +46,7 @@ ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
inline uint32_t JSValue::toUInt32(ExecState* exec) const
{
- // See comment on JSC::toUInt32, above.
+ // See comment on JSC::toUInt32, in JSCJSValue.h.
return toInt32(exec);
}
@@ -65,7 +69,7 @@ inline double JSValue::asNumber() const
inline JSValue jsNaN()
{
- return JSValue(QNaN);
+ return JSValue(PNaN);
}
inline JSValue::JSValue(char i)
@@ -210,10 +214,10 @@ inline JSValue::JSValue(const JSCell* ptr)
u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr));
}
-inline JSValue::operator UnspecifiedBoolType*() const
+inline JSValue::operator bool() const
{
ASSERT(tag() != DeletedValueTag);
- return tag() != EmptyValueTag ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
+ return tag() != EmptyValueTag;
}
inline bool JSValue::operator==(const JSValue& other) const
@@ -301,6 +305,7 @@ ALWAYS_INLINE JSCell* JSValue::asCell() const
ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
{
+ ASSERT(!isImpureNaN(d));
u.asDouble = d;
}
@@ -310,7 +315,7 @@ inline JSValue::JSValue(int i)
u.asBits.payload = i;
}
-#if ENABLE(LLINT_C_LOOP)
+#if !ENABLE(JIT)
inline JSValue::JSValue(int32_t tag, int32_t payload)
{
u.asBits.tag = tag;
@@ -325,7 +330,7 @@ inline bool JSValue::isNumber() const
inline bool JSValue::isBoolean() const
{
- return isTrue() || isFalse();
+ return tag() == BooleanTag;
}
inline bool JSValue::asBoolean() const
@@ -358,9 +363,9 @@ inline JSValue::JSValue(const JSCell* ptr)
u.asInt64 = reinterpret_cast<uintptr_t>(const_cast<JSCell*>(ptr));
}
-inline JSValue::operator UnspecifiedBoolType*() const
+inline JSValue::operator bool() const
{
- return u.asInt64 ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
+ return u.asInt64;
}
inline bool JSValue::operator==(const JSValue& other) const
@@ -467,6 +472,7 @@ inline double reinterpretInt64ToDouble(int64_t value)
ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
{
+ ASSERT(!isImpureNaN(d));
u.asInt64 = reinterpretDoubleToInt64(d) + DoubleEncodeOffset;
}
@@ -494,25 +500,43 @@ ALWAYS_INLINE JSCell* JSValue::asCell() const
#endif // USE(JSVALUE64)
-inline bool JSValue::isMachineInt() const
+inline int64_t tryConvertToInt52(double number)
{
- if (isInt32())
- return true;
- if (!isNumber())
- return false;
- double number = asDouble();
if (number != number)
- return false;
+ return JSValue::notInt52;
+#if OS(WINDOWS) && CPU(X86)
+ // The VS Compiler for 32-bit builds generates a floating point error when attempting to cast
+ // from an infinity to a 64-bit integer. We leave this routine with the floating point error
+ // left in a register, causing undefined behavior in later floating point operations.
+ //
+ // To avoid this issue, we check for infinity here, and return false in that case.
+ if (std::isinf(number))
+ return JSValue::notInt52;
+#endif
int64_t asInt64 = static_cast<int64_t>(number);
if (asInt64 != number)
- return false;
+ return JSValue::notInt52;
if (!asInt64 && std::signbit(number))
+ return JSValue::notInt52;
+ if (asInt64 >= (static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits - 1)))
+ return JSValue::notInt52;
+ if (asInt64 < -(static_cast<int64_t>(1) << (JSValue::numberOfInt52Bits - 1)))
+ return JSValue::notInt52;
+ return asInt64;
+}
+
+inline bool isInt52(double number)
+{
+ return tryConvertToInt52(number) != JSValue::notInt52;
+}
+
+inline bool JSValue::isMachineInt() const
+{
+ if (isInt32())
+ return true;
+ if (!isNumber())
return false;
- if (asInt64 >= (static_cast<int64_t>(1) << (numberOfInt52Bits - 1)))
- return false;
- if (asInt64 < -(static_cast<int64_t>(1) << (numberOfInt52Bits - 1)))
- return false;
- return true;
+ return isInt52(asDouble());
}
inline int64_t JSValue::asMachineInt() const
@@ -528,9 +552,14 @@ inline bool JSValue::isString() const
return isCell() && asCell()->isString();
}
+inline bool JSValue::isSymbol() const
+{
+ return isCell() && asCell()->isSymbol();
+}
+
inline bool JSValue::isPrimitive() const
{
- return !isCell() || asCell()->isString();
+ return !isCell() || asCell()->isString() || asCell()->isSymbol();
}
inline bool JSValue::isGetterSetter() const
@@ -538,6 +567,11 @@ inline bool JSValue::isGetterSetter() const
return isCell() && asCell()->isGetterSetter();
}
+inline bool JSValue::isCustomGetterSetter() const
+{
+ return isCell() && asCell()->isCustomGetterSetter();
+}
+
inline bool JSValue::isObject() const
{
return isCell() && asCell()->isObject();
@@ -578,6 +612,17 @@ ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
return false;
}
+ALWAYS_INLINE Identifier JSValue::toPropertyKey(ExecState* exec) const
+{
+ if (isString())
+ return asString(*this)->toIdentifier(exec);
+
+ JSValue primitive = toPrimitive(exec, PreferString);
+ if (primitive.isSymbol())
+ return Identifier::fromUid(asSymbol(primitive)->privateName());
+ return primitive.toString(exec)->toIdentifier(exec);
+}
+
inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
{
return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
@@ -608,7 +653,7 @@ inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue
return true;
}
ASSERT(isUndefined());
- number = QNaN;
+ number = PNaN;
value = *this;
return true;
}
@@ -637,6 +682,16 @@ inline bool JSValue::isFunction() const
return isCell() && (asCell()->inherits(JSFunction::info()) || asCell()->inherits(InternalFunction::info()));
}
+// FIXME: We could do this in a smarter way. See: https://bugs.webkit.org/show_bug.cgi?id=153670
+inline bool JSValue::isConstructor() const
+{
+ if (isFunction()) {
+ ConstructData data;
+ return getConstructData(*this, data) != ConstructTypeNone;
+ }
+ return false;
+}
+
// this method is here to be after the inline declaration of JSCell::inherits
inline bool JSValue::inherits(const ClassInfo* classInfo) const
{
@@ -645,45 +700,49 @@ inline bool JSValue::inherits(const ClassInfo* classInfo) const
inline JSValue JSValue::toThis(ExecState* exec, ECMAMode ecmaMode) const
{
- return isCell() ? asCell()->methodTable()->toThis(asCell(), exec, ecmaMode) : toThisSlowCase(exec, ecmaMode);
+ return isCell() ? asCell()->methodTable(exec->vm())->toThis(asCell(), exec, ecmaMode) : toThisSlowCase(exec, ecmaMode);
}
-inline JSValue JSValue::get(ExecState* exec, PropertyName propertyName) const
+ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, PropertyName propertyName) const
{
- PropertySlot slot(asValue());
+ PropertySlot slot(asValue(), PropertySlot::InternalMethodType::Get);
return get(exec, propertyName, slot);
}
-inline JSValue JSValue::get(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const
+ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const
+{
+ return getPropertySlot(exec, propertyName, slot) ?
+ slot.getValue(exec, propertyName) : jsUndefined();
+}
+
+ALWAYS_INLINE bool JSValue::getPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) const
{
// If this is a primitive, we'll need to synthesize the prototype -
// and if it's a string there are special properties to check first.
JSObject* object;
if (UNLIKELY(!isObject())) {
- if (isCell() && asString(*this)->getStringPropertySlot(exec, propertyName, slot))
- return slot.getValue(exec, propertyName);
+ if (isString() && asString(*this)->getStringPropertySlot(exec, propertyName, slot))
+ return true;
object = synthesizePrototype(exec);
} else
object = asObject(asCell());
- if (object->getPropertySlot(exec, propertyName, slot))
- return slot.getValue(exec, propertyName);
- return jsUndefined();
+ return object->getPropertySlot(exec, propertyName, slot);
}
-inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
+ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
{
- PropertySlot slot(asValue());
+ PropertySlot slot(asValue(), PropertySlot::InternalMethodType::Get);
return get(exec, propertyName, slot);
}
-inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
+ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
{
// If this is a primitive, we'll need to synthesize the prototype -
// and if it's a string there are special properties to check first.
JSObject* object;
if (UNLIKELY(!isObject())) {
- if (isCell() && asString(*this)->getStringPropertySlot(exec, propertyName, slot))
+ if (isString() && asString(*this)->getStringPropertySlot(exec, propertyName, slot))
return slot.getValue(exec, propertyName);
object = synthesizePrototype(exec);
} else
@@ -700,7 +759,25 @@ inline void JSValue::put(ExecState* exec, PropertyName propertyName, JSValue val
putToPrimitive(exec, propertyName, value, slot);
return;
}
- asCell()->methodTable()->put(asCell(), exec, propertyName, value, slot);
+ asCell()->methodTable(exec->vm())->put(asCell(), exec, propertyName, value, slot);
+}
+
+ALWAYS_INLINE void JSValue::putInline(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
+ if (UNLIKELY(!isCell())) {
+ putToPrimitive(exec, propertyName, value, slot);
+ return;
+ }
+ JSCell* cell = asCell();
+ auto putMethod = cell->methodTable(exec->vm())->put;
+ if (LIKELY(putMethod == JSObject::put)) {
+ JSObject::putInline(cell, exec, propertyName, value, slot);
+ return;
+ }
+
+ PutPropertySlot otherSlot = slot;
+ putMethod(cell, exec, propertyName, value, otherSlot);
+ slot = otherSlot;
}
inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
@@ -709,7 +786,7 @@ inline void JSValue::putByIndex(ExecState* exec, unsigned propertyName, JSValue
putToPrimitiveByIndex(exec, propertyName, value, shouldThrow);
return;
}
- asCell()->methodTable()->putByIndex(asCell(), exec, propertyName, value, shouldThrow);
+ asCell()->methodTable(exec->vm())->putByIndex(asCell(), exec, propertyName, value, shouldThrow);
}
inline JSValue JSValue::structureOrUndefined() const
@@ -730,6 +807,7 @@ inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2)
ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2)
{
+ VM& vm = exec->vm();
do {
if (v1.isNumber() && v2.isNumber())
return v1.asNumber() == v2.asNumber();
@@ -737,20 +815,20 @@ ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSV
bool s1 = v1.isString();
bool s2 = v2.isString();
if (s1 && s2)
- return asString(v1)->value(exec) == asString(v2)->value(exec);
+ return WTF::equal(*asString(v1)->value(exec).impl(), *asString(v2)->value(exec).impl());
if (v1.isUndefinedOrNull()) {
if (v2.isUndefinedOrNull())
return true;
if (!v2.isCell())
return false;
- return v2.asCell()->structure()->masqueradesAsUndefined(exec->lexicalGlobalObject());
+ return v2.asCell()->structure(vm)->masqueradesAsUndefined(exec->lexicalGlobalObject());
}
if (v2.isUndefinedOrNull()) {
if (!v1.isCell())
return false;
- return v1.asCell()->structure()->masqueradesAsUndefined(exec->lexicalGlobalObject());
+ return v1.asCell()->structure(vm)->masqueradesAsUndefined(exec->lexicalGlobalObject());
}
if (v1.isObject()) {
@@ -775,6 +853,14 @@ ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSV
continue;
}
+ bool sym1 = v1.isSymbol();
+ bool sym2 = v2.isSymbol();
+ if (sym1 || sym2) {
+ if (sym1 && sym2)
+ return asSymbol(v1)->privateName() == asSymbol(v2)->privateName();
+ return false;
+ }
+
if (s1 || s2) {
double d1 = v1.toNumber(exec);
double d2 = v2.toNumber(exec);
@@ -799,7 +885,9 @@ ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(ExecState* exec, JSValue v
ASSERT(v1.isCell() && v2.isCell());
if (v1.asCell()->isString() && v2.asCell()->isString())
- return asString(v1)->value(exec) == asString(v2)->value(exec);
+ return WTF::equal(*asString(v1)->value(exec).impl(), *asString(v2)->value(exec).impl());
+ if (v1.asCell()->isSymbol() && v2.asCell()->isSymbol())
+ return asSymbol(v1)->privateName() == asSymbol(v2)->privateName();
return v1 == v2;
}
@@ -818,6 +906,13 @@ inline bool JSValue::strictEqual(ExecState* exec, JSValue v1, JSValue v2)
return strictEqualSlowCaseInline(exec, v1, v2);
}
+inline int32_t JSValue::asInt32ForArithmetic() const
+{
+ if (isBoolean())
+ return asBoolean();
+ return asInt32();
+}
+
inline TriState JSValue::pureStrictEqual(JSValue v1, JSValue v2)
{
if (v1.isInt32() && v2.isInt32())
@@ -834,7 +929,7 @@ inline TriState JSValue::pureStrictEqual(JSValue v1, JSValue v2)
const StringImpl* v2String = asString(v2)->tryGetValueImpl();
if (!v1String || !v2String)
return MixedTriState;
- return triState(WTF::equal(v1String, v2String));
+ return triState(WTF::equal(*v1String, *v2String));
}
return triState(v1 == v2);
@@ -851,6 +946,14 @@ inline TriState JSValue::pureToBoolean() const
return isTrue() ? TrueTriState : FalseTriState;
}
+ALWAYS_INLINE bool JSValue::requireObjectCoercible(ExecState* exec) const
+{
+ if (!isUndefinedOrNull())
+ return true;
+ exec->vm().throwException(exec, createNotAnObjectError(exec, *this));
+ return false;
+}
+
} // namespace JSC
#endif // JSValueInlines_h
diff --git a/Source/JavaScriptCore/runtime/JSCallee.cpp b/Source/JavaScriptCore/runtime/JSCallee.cpp
new file mode 100644
index 000000000..d303296cc
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSCallee.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+#include "JSCallee.h"
+
+#include "GetterSetter.h"
+#include "JSCJSValueInlines.h"
+#include "JSCell.h"
+#include "JSCellInlines.h"
+#include "JSGlobalObject.h"
+#include "SlotVisitorInlines.h"
+#include "StackVisitor.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+const ClassInfo JSCallee::s_info = { "Callee", &Base::s_info, 0, CREATE_METHOD_TABLE(JSCallee) };
+
+JSCallee::JSCallee(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+ : Base(vm, structure)
+ , m_scope(vm, this, globalObject)
+{
+}
+
+JSCallee::JSCallee(VM& vm, JSScope* scope, Structure* structure)
+ : Base(vm, structure)
+{
+ setScope(vm, scope);
+}
+
+void JSCallee::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+}
+
+void JSCallee::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSCallee* thisObject = jsCast<JSCallee*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_scope);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSCallee.h b/Source/JavaScriptCore/runtime/JSCallee.h
new file mode 100644
index 000000000..d49925cd1
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSCallee.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef JSCallee_h
+#define JSCallee_h
+
+#include "JSGlobalObject.h"
+#include "JSObject.h"
+#include "JSScope.h"
+
+namespace JSC {
+
+class JSGlobalObject;
+class LLIntOffsetsExtractor;
+
+
+class JSCallee : public JSNonFinalObject {
+ friend class JIT;
+#if ENABLE(DFG_JIT)
+ friend class DFG::SpeculativeJIT;
+ friend class DFG::JITCompiler;
+#endif
+ friend class VM;
+
+public:
+ typedef JSNonFinalObject Base;
+ const static unsigned StructureFlags = Base::StructureFlags | ImplementsHasInstance | ImplementsDefaultHasInstance;
+
+ static JSCallee* create(VM& vm, JSGlobalObject* globalObject, JSScope* scope)
+ {
+ JSCallee* callee = new (NotNull, allocateCell<JSCallee>(vm.heap)) JSCallee(vm, scope, globalObject->calleeStructure());
+ callee->finishCreation(vm);
+ return callee;
+ }
+
+ JSScope* scope()
+ {
+ return m_scope.get();
+ }
+
+ // This method may be called for host functions, in which case it
+ // will return an arbitrary value. This should only be used for
+ // optimized paths in which the return value does not matter for
+ // host functions, and checking whether the function is a host
+ // function is deemed too expensive.
+ JSScope* scopeUnchecked()
+ {
+ return m_scope.get();
+ }
+
+ void setScope(VM& vm, JSScope* scope)
+ {
+ m_scope.set(vm, this, scope);
+ }
+
+ DECLARE_EXPORT_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ ASSERT(globalObject);
+ return Structure::create(vm, globalObject, prototype, TypeInfo(JSCalleeType, StructureFlags), info());
+ }
+
+ static inline ptrdiff_t offsetOfScopeChain()
+ {
+ return OBJECT_OFFSETOF(JSCallee, m_scope);
+ }
+
+protected:
+ JS_EXPORT_PRIVATE JSCallee(VM&, JSGlobalObject*, Structure*);
+ JSCallee(VM&, JSScope*, Structure*);
+
+ void finishCreation(VM&);
+ using Base::finishCreation;
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+private:
+ friend class LLIntOffsetsExtractor;
+
+ WriteBarrier<JSScope> m_scope;
+};
+
+} // namespace JSC
+
+#endif // JSCallee_h
diff --git a/Source/JavaScriptCore/runtime/JSCell.cpp b/Source/JavaScriptCore/runtime/JSCell.cpp
index f472a9679..09af32bf9 100644
--- a/Source/JavaScriptCore/runtime/JSCell.cpp
+++ b/Source/JavaScriptCore/runtime/JSCell.cpp
@@ -28,11 +28,12 @@
#include "JSString.h"
#include "JSObject.h"
#include "NumberObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include <wtf/MathExtras.h>
namespace JSC {
+COMPILE_ASSERT(sizeof(JSCell) == sizeof(uint64_t), jscell_is_eight_bytes);
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSCell);
void JSCell::destroy(JSCell* cell)
@@ -40,6 +41,26 @@ void JSCell::destroy(JSCell* cell)
cell->JSCell::~JSCell();
}
+void JSCell::dump(PrintStream& out) const
+{
+ methodTable()->dumpToStream(this, out);
+}
+
+void JSCell::dumpToStream(const JSCell* cell, PrintStream& out)
+{
+ out.printf("<%p, %s>", cell, cell->className());
+}
+
+size_t JSCell::estimatedSizeInBytes() const
+{
+ return methodTable()->estimatedSize(const_cast<JSCell*>(this));
+}
+
+size_t JSCell::estimatedSize(JSCell* cell)
+{
+ return MarkedBlock::blockFor(cell)->cellSize();
+}
+
void JSCell::copyBackingStore(JSCell*, CopyVisitor&, CopyToken)
{
}
@@ -85,35 +106,35 @@ ConstructType JSCell::getConstructData(JSCell*, ConstructData& constructData)
void JSCell::put(JSCell* cell, ExecState* exec, PropertyName identifier, JSValue value, PutPropertySlot& slot)
{
- if (cell->isString()) {
+ if (cell->isString() || cell->isSymbol()) {
JSValue(cell).putToPrimitive(exec, identifier, value, slot);
return;
}
JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject());
- thisObject->methodTable()->put(thisObject, exec, identifier, value, slot);
+ thisObject->methodTable(exec->vm())->put(thisObject, exec, identifier, value, slot);
}
void JSCell::putByIndex(JSCell* cell, ExecState* exec, unsigned identifier, JSValue value, bool shouldThrow)
{
- if (cell->isString()) {
+ if (cell->isString() || cell->isSymbol()) {
PutPropertySlot slot(cell, shouldThrow);
JSValue(cell).putToPrimitive(exec, Identifier::from(exec, identifier), value, slot);
return;
}
JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject());
- thisObject->methodTable()->putByIndex(thisObject, exec, identifier, value, shouldThrow);
+ thisObject->methodTable(exec->vm())->putByIndex(thisObject, exec, identifier, value, shouldThrow);
}
bool JSCell::deleteProperty(JSCell* cell, ExecState* exec, PropertyName identifier)
{
JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject());
- return thisObject->methodTable()->deleteProperty(thisObject, exec, identifier);
+ return thisObject->methodTable(exec->vm())->deleteProperty(thisObject, exec, identifier);
}
bool JSCell::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned identifier)
{
JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject());
- return thisObject->methodTable()->deletePropertyByIndex(thisObject, exec, identifier);
+ return thisObject->methodTable(exec->vm())->deletePropertyByIndex(thisObject, exec, identifier);
}
JSValue JSCell::toThis(JSCell* cell, ExecState* exec, ECMAMode ecmaMode)
@@ -127,6 +148,8 @@ JSValue JSCell::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredTyp
{
if (isString())
return static_cast<const JSString*>(this)->toPrimitive(exec, preferredType);
+ if (isSymbol())
+ return static_cast<const Symbol*>(this)->toPrimitive(exec, preferredType);
return static_cast<const JSObject*>(this)->toPrimitive(exec, preferredType);
}
@@ -134,6 +157,8 @@ bool JSCell::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value)
{
if (isString())
return static_cast<const JSString*>(this)->getPrimitiveNumber(exec, number, value);
+ if (isSymbol())
+ return static_cast<const Symbol*>(this)->getPrimitiveNumber(exec, number, value);
return static_cast<const JSObject*>(this)->getPrimitiveNumber(exec, number, value);
}
@@ -141,6 +166,8 @@ double JSCell::toNumber(ExecState* exec) const
{
if (isString())
return static_cast<const JSString*>(this)->toNumber(exec);
+ if (isSymbol())
+ return static_cast<const Symbol*>(this)->toNumber(exec);
return static_cast<const JSObject*>(this)->toNumber(exec);
}
@@ -148,6 +175,8 @@ JSObject* JSCell::toObject(ExecState* exec, JSGlobalObject* globalObject) const
{
if (isString())
return static_cast<const JSString*>(this)->toObject(exec, globalObject);
+ if (isSymbol())
+ return static_cast<const Symbol*>(this)->toObject(exec, globalObject);
ASSERT(isObject());
return jsCast<JSObject*>(const_cast<JSCell*>(this));
}
@@ -191,7 +220,7 @@ String JSCell::className(const JSObject*)
return String();
}
-const char* JSCell::className()
+const char* JSCell::className() const
{
return classInfo()->className;
}
@@ -225,4 +254,20 @@ PassRefPtr<ArrayBufferView> JSCell::getTypedArrayImpl(JSArrayBufferView*)
return 0;
}
+uint32_t JSCell::getEnumerableLength(ExecState*, JSObject*)
+{
+ RELEASE_ASSERT_NOT_REACHED();
+ return 0;
+}
+
+void JSCell::getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
+{
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+void JSCell::getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
+{
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h
index de85a4bdc..f98895d2a 100644
--- a/Source/JavaScriptCore/runtime/JSCell.h
+++ b/Source/JavaScriptCore/runtime/JSCell.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, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 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 Library General Public
@@ -24,9 +24,13 @@
#define JSCell_h
#include "CallData.h"
+#include "CellState.h"
#include "ConstructData.h"
+#include "EnumerationMode.h"
#include "Heap.h"
+#include "IndexingType.h"
#include "JSLock.h"
+#include "JSTypeInfo.h"
#include "SlotVisitor.h"
#include "TypedArrayType.h"
#include "WriteBarrier.h"
@@ -36,6 +40,7 @@ namespace JSC {
class CopyVisitor;
class ExecState;
+class Identifier;
class JSArrayBufferView;
class JSDestructibleObject;
class JSGlobalObject;
@@ -44,11 +49,6 @@ class PropertyDescriptor;
class PropertyNameArray;
class Structure;
-enum EnumerationMode {
- ExcludeDontEnumProperties,
- IncludeDontEnumProperties
-};
-
template<typename T> void* allocateCell(Heap&);
template<typename T> void* allocateCell(Heap&, size_t);
@@ -74,7 +74,8 @@ public:
static const unsigned StructureFlags = 0;
static const bool needsDestruction = false;
- static const bool hasImmortalStructure = false;
+
+ static JSCell* seenMultipleCalleeObjects() { return bitwise_cast<JSCell*>(static_cast<uintptr_t>(1)); }
enum CreatingEarlyCellTag { CreatingEarlyCell };
JSCell(CreatingEarlyCellTag);
@@ -86,17 +87,27 @@ protected:
public:
// Querying the type.
bool isString() const;
+ bool isSymbol() const;
bool isObject() const;
bool isGetterSetter() const;
+ bool isCustomGetterSetter() const;
bool isProxy() const;
bool inherits(const ClassInfo*) const;
bool isAPIValueWrapper() const;
+ JSType type() const;
+ IndexingType indexingType() const;
+ StructureID structureID() const { return m_structureID; }
Structure* structure() const;
+ Structure* structure(VM&) const;
void setStructure(VM&, Structure*);
- void clearStructure() { m_structure.clear(); }
+ void clearStructure() { m_structureID = 0; }
+
+ TypeInfo::InlineTypeFlags inlineTypeFlags() const { return m_flags; }
- const char* className();
+ const char* className() const;
+
+ VM* vm() const;
// Extracting the value.
JS_EXPORT_PRIVATE bool getString(ExecState*, String&) const;
@@ -104,6 +115,12 @@ public:
JS_EXPORT_PRIVATE JSObject* getObject(); // NULL if not an object
const JSObject* getObject() const; // NULL if not an object
+ // Returns information about how to call/construct this cell as a function/constructor. May tell
+ // you that the cell is not callable or constructor (default is that it's not either). If it
+ // says that the function is callable, and the TypeOfShouldCallGetCallData type flag is set, and
+ // this is an object, then typeof will return "function" instead of "object". These methods
+ // cannot change their minds and must be thread-safe. They are sometimes called from compiler
+ // threads.
JS_EXPORT_PRIVATE static CallType getCallData(JSCell*, CallData&);
JS_EXPORT_PRIVATE static ConstructType getConstructData(JSCell*, ConstructData&);
@@ -115,13 +132,19 @@ public:
JS_EXPORT_PRIVATE double toNumber(ExecState*) const;
JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const;
+ void dump(PrintStream&) const;
+ JS_EXPORT_PRIVATE static void dumpToStream(const JSCell*, PrintStream&);
+
+ size_t estimatedSizeInBytes() const;
+ JS_EXPORT_PRIVATE static size_t estimatedSize(JSCell*);
+
static void visitChildren(JSCell*, SlotVisitor&);
JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
// Object operations, with the toObject operation included.
const ClassInfo* classInfo() const;
const MethodTable* methodTable() const;
- const MethodTable* methodTableForDestruction() const;
+ const MethodTable* methodTable(VM&) const;
static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
@@ -133,22 +156,41 @@ public:
void zap() { *reinterpret_cast<uintptr_t**>(this) = 0; }
bool isZapped() const { return !*reinterpret_cast<uintptr_t* const*>(this); }
- JSValue fastGetOwnProperty(ExecState*, const String&);
+ static bool canUseFastGetOwnProperty(const Structure&);
+ JSValue fastGetOwnProperty(VM&, Structure&, PropertyName);
- static ptrdiff_t structureOffset()
+ // The recommended idiom for using cellState() is to switch on it or perform an == comparison on it
+ // directly. We deliberately avoid helpers for this, because we want transparency about how the various
+ // CellState values influences our various algorithms.
+ CellState cellState() const { return m_cellState; }
+
+ void setCellState(CellState data) const { const_cast<JSCell*>(this)->m_cellState = data; }
+
+ static ptrdiff_t structureIDOffset()
{
- return OBJECT_OFFSETOF(JSCell, m_structure);
+ return OBJECT_OFFSETOF(JSCell, m_structureID);
}
- void* structureAddress()
+ static ptrdiff_t typeInfoFlagsOffset()
{
- return &m_structure;
+ return OBJECT_OFFSETOF(JSCell, m_flags);
}
-
-#if ENABLE(GC_VALIDATION)
- Structure* unvalidatedStructure() const { return m_structure.unvalidatedGet(); }
-#endif
-
+
+ static ptrdiff_t typeInfoTypeOffset()
+ {
+ return OBJECT_OFFSETOF(JSCell, m_type);
+ }
+
+ static ptrdiff_t indexingTypeOffset()
+ {
+ return OBJECT_OFFSETOF(JSCell, m_indexingType);
+ }
+
+ static ptrdiff_t cellStateOffset()
+ {
+ return OBJECT_OFFSETOF(JSCell, m_cellState);
+ }
+
static const TypedArrayType TypedArrayStorageType = NotTypedArray;
protected:
@@ -160,6 +202,11 @@ protected:
static NO_RETURN_DUE_TO_CRASH void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
static NO_RETURN_DUE_TO_CRASH void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
static NO_RETURN_DUE_TO_CRASH void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+
+ static uint32_t getEnumerableLength(ExecState*, JSObject*);
+ static NO_RETURN_DUE_TO_CRASH void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static NO_RETURN_DUE_TO_CRASH void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+
static String className(const JSObject*);
JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue);
static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
@@ -170,34 +217,42 @@ protected:
private:
friend class LLIntOffsetsExtractor;
-
- WriteBarrier<Structure> m_structure;
+
+ StructureID m_structureID;
+ IndexingType m_indexingType;
+ JSType m_type;
+ TypeInfo::InlineTypeFlags m_flags;
+ CellState m_cellState;
};
template<typename To, typename From>
inline To jsCast(From* from)
{
- ASSERT(!from || from->JSCell::inherits(std::remove_pointer<To>::type::info()));
+ ASSERT_WITH_SECURITY_IMPLICATION(!from || from->JSCell::inherits(std::remove_pointer<To>::type::info()));
return static_cast<To>(from);
}
template<typename To>
inline To jsCast(JSValue from)
{
- ASSERT(from.isCell() && from.asCell()->JSCell::inherits(std::remove_pointer<To>::type::info()));
+ ASSERT_WITH_SECURITY_IMPLICATION(from.isCell() && from.asCell()->JSCell::inherits(std::remove_pointer<To>::type::info()));
return static_cast<To>(from.asCell());
}
template<typename To, typename From>
inline To jsDynamicCast(From* from)
{
- return from->inherits(std::remove_pointer<To>::type::info()) ? static_cast<To>(from) : 0;
+ if (LIKELY(from->inherits(std::remove_pointer<To>::type::info())))
+ return static_cast<To>(from);
+ return nullptr;
}
template<typename To>
inline To jsDynamicCast(JSValue from)
{
- return from.isCell() && from.asCell()->inherits(std::remove_pointer<To>::type::info()) ? static_cast<To>(from.asCell()) : 0;
+ if (LIKELY(from.isCell() && from.asCell()->inherits(std::remove_pointer<To>::type::info())))
+ return static_cast<To>(from.asCell());
+ return nullptr;
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSCellInlines.h b/Source/JavaScriptCore/runtime/JSCellInlines.h
index f7c844645..4274c216f 100644
--- a/Source/JavaScriptCore/runtime/JSCellInlines.h
+++ b/Source/JavaScriptCore/runtime/JSCellInlines.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 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
@@ -30,20 +30,28 @@
#include "DeferGC.h"
#include "Handle.h"
#include "JSCell.h"
+#include "JSDestructibleObject.h"
#include "JSObject.h"
#include "JSString.h"
+#include "MarkedBlock.h"
#include "Structure.h"
+#include "Symbol.h"
#include <wtf/CompilationThread.h>
namespace JSC {
inline JSCell::JSCell(CreatingEarlyCellTag)
+ : m_cellState(CellState::NewWhite)
{
ASSERT(!isCompilationThread());
}
-inline JSCell::JSCell(VM& vm, Structure* structure)
- : m_structure(vm, this, structure)
+inline JSCell::JSCell(VM&, Structure* structure)
+ : m_structureID(structure->id())
+ , m_indexingType(structure->indexingType())
+ , m_type(structure->typeInfo().type())
+ , m_flags(structure->typeInfo().inlineTypeFlags())
+ , m_cellState(CellState::NewWhite)
{
ASSERT(!isCompilationThread());
}
@@ -56,7 +64,7 @@ inline void JSCell::finishCreation(VM& vm)
#else
UNUSED_PARAM(vm);
#endif
- ASSERT(m_structure);
+ ASSERT(m_structureID);
}
inline void JSCell::finishCreation(VM& vm, Structure* structure, CreatingEarlyCellTag)
@@ -64,23 +72,57 @@ inline void JSCell::finishCreation(VM& vm, Structure* structure, CreatingEarlyCe
#if ENABLE(GC_VALIDATION)
ASSERT(vm.isInitializingObject());
vm.setInitializingObjectClass(0);
- if (structure)
+ if (structure) {
+#endif
+ m_structureID = structure->id();
+ m_indexingType = structure->indexingType();
+ m_type = structure->typeInfo().type();
+ m_flags = structure->typeInfo().inlineTypeFlags();
+#if ENABLE(GC_VALIDATION)
+ }
+#else
+ UNUSED_PARAM(vm);
#endif
- m_structure.setEarlyValue(vm, this, structure);
// Very first set of allocations won't have a real structure.
- ASSERT(m_structure || !vm.structureStructure);
+ ASSERT(m_structureID || !vm.structureStructure);
+}
+
+inline JSType JSCell::type() const
+{
+ return m_type;
+}
+
+inline IndexingType JSCell::indexingType() const
+{
+ return m_indexingType;
}
inline Structure* JSCell::structure() const
{
- return m_structure.get();
+ return Heap::heap(this)->structureIDTable().get(m_structureID);
+}
+
+inline Structure* JSCell::structure(VM& vm) const
+{
+ return vm.heap.structureIDTable().get(m_structureID);
}
inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
- MARK_LOG_PARENT(visitor, cell);
+ Structure* structure = cell->structure(visitor.vm());
+ visitor.appendUnbarrieredPointer(&structure);
+}
- visitor.append(&cell->m_structure);
+inline VM* JSCell::vm() const
+{
+ return MarkedBlock::blockFor(this)->vm();
+}
+
+inline VM& ExecState::vm() const
+{
+ ASSERT(callee());
+ ASSERT(callee()->vm());
+ return *calleeAsValue().asCell()->vm();
}
template<typename T>
@@ -88,13 +130,7 @@ void* allocateCell(Heap& heap, size_t size)
{
ASSERT(!DisallowGC::isGCDisallowedOnCurrentThread());
ASSERT(size >= sizeof(T));
- JSCell* result = 0;
- if (T::needsDestruction && T::hasImmortalStructure)
- result = static_cast<JSCell*>(heap.allocateWithImmortalStructureDestructor(size));
- else if (T::needsDestruction)
- result = static_cast<JSCell*>(heap.allocateWithNormalDestructor(size));
- else
- result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size));
+ JSCell* result = static_cast<JSCell*>(heap.allocateObjectOfType<T>(size));
#if ENABLE(GC_VALIDATION)
ASSERT(!heap.vm()->isInitializingObject());
heap.vm()->setInitializingObjectClass(T::info());
@@ -116,50 +152,69 @@ inline bool isZapped(const JSCell* cell)
inline bool JSCell::isObject() const
{
- return m_structure->isObject();
+ return TypeInfo::isObject(m_type);
}
inline bool JSCell::isString() const
{
- return m_structure->typeInfo().type() == StringType;
+ return m_type == StringType;
+}
+
+inline bool JSCell::isSymbol() const
+{
+ return m_type == SymbolType;
}
inline bool JSCell::isGetterSetter() const
{
- return m_structure->typeInfo().type() == GetterSetterType;
+ return m_type == GetterSetterType;
+}
+
+inline bool JSCell::isCustomGetterSetter() const
+{
+ return m_type == CustomGetterSetterType;
}
inline bool JSCell::isProxy() const
{
- return structure()->typeInfo().type() == ProxyType;
+ return m_type == ImpureProxyType || m_type == PureForwardingProxyType;
}
inline bool JSCell::isAPIValueWrapper() const
{
- return m_structure->typeInfo().type() == APIValueWrapperType;
+ return m_type == APIValueWrapperType;
}
inline void JSCell::setStructure(VM& vm, Structure* structure)
{
- ASSERT(structure->typeInfo().overridesVisitChildren() == this->structure()->typeInfo().overridesVisitChildren());
- ASSERT(structure->classInfo() == m_structure->classInfo());
- ASSERT(!m_structure
- || m_structure->transitionWatchpointSetHasBeenInvalidated()
- || m_structure.get() == structure);
- m_structure.set(vm, this, structure);
+ ASSERT(structure->classInfo() == this->structure()->classInfo());
+ ASSERT(!this->structure()
+ || this->structure()->transitionWatchpointSetHasBeenInvalidated()
+ || Heap::heap(this)->structureIDTable().get(structure->id()) == structure);
+ vm.heap.writeBarrier(this, structure);
+ m_structureID = structure->id();
+ m_flags = structure->typeInfo().inlineTypeFlags();
+ m_type = structure->typeInfo().type();
+ m_indexingType = structure->indexingType();
}
-inline const MethodTable* JSCell::methodTableForDestruction() const
+inline const MethodTable* JSCell::methodTable() const
{
- return &classInfo()->methodTable;
+ VM& vm = *Heap::heap(this)->vm();
+ Structure* structure = this->structure(vm);
+ if (Structure* rootStructure = structure->structure(vm))
+ RELEASE_ASSERT(rootStructure == rootStructure->structure(vm));
+
+ return &structure->classInfo()->methodTable;
}
-inline const MethodTable* JSCell::methodTable() const
+inline const MethodTable* JSCell::methodTable(VM& vm) const
{
- if (Structure* rootStructure = m_structure->structure())
- RELEASE_ASSERT(rootStructure == rootStructure->structure());
+ Structure* structure = this->structure(vm);
+ if (Structure* rootStructure = structure->structure(vm))
+ RELEASE_ASSERT(rootStructure == rootStructure->structure(vm));
- return &classInfo()->methodTable;
+ return &structure->classInfo()->methodTable;
}
inline bool JSCell::inherits(const ClassInfo* info) const
@@ -167,33 +222,43 @@ inline bool JSCell::inherits(const ClassInfo* info) const
return classInfo()->isSubClassOf(info);
}
-// Fast call to get a property where we may not yet have converted the string to an
-// identifier. The first time we perform a property access with a given string, try
-// performing the property map lookup without forming an identifier. We detect this
-// case by checking whether the hash has yet been set for this string.
-ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(ExecState* exec, const String& name)
+ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(VM& vm, Structure& structure, PropertyName name)
{
- if (!structure()->typeInfo().overridesGetOwnPropertySlot() && !structure()->hasGetterSetterProperties()) {
- PropertyOffset offset = name.impl()->hasHash()
- ? structure()->get(exec->vm(), Identifier(exec, name))
- : structure()->get(exec->vm(), name);
- if (offset != invalidOffset)
- return asObject(this)->locationForOffset(offset)->get();
- }
+ ASSERT(canUseFastGetOwnProperty(structure));
+ PropertyOffset offset = structure.get(vm, name);
+ if (offset != invalidOffset)
+ return asObject(this)->locationForOffset(offset)->get();
return JSValue();
}
+inline bool JSCell::canUseFastGetOwnProperty(const Structure& structure)
+{
+ return !structure.hasGetterSetterProperties()
+ && !structure.hasCustomGetterSetterProperties()
+ && !structure.typeInfo().overridesGetOwnPropertySlot();
+}
+
+inline const ClassInfo* JSCell::classInfo() const
+{
+ MarkedBlock* block = MarkedBlock::blockFor(this);
+ if (block->needsDestruction() && !(inlineTypeFlags() & StructureIsImmortal))
+ return static_cast<const JSDestructibleObject*>(this)->classInfo();
+ return structure(*block->vm())->classInfo();
+}
+
inline bool JSCell::toBoolean(ExecState* exec) const
{
- if (isString())
+ if (isString())
return static_cast<const JSString*>(this)->toBoolean();
return !structure()->masqueradesAsUndefined(exec->lexicalGlobalObject());
}
inline TriState JSCell::pureToBoolean() const
{
- if (isString())
+ if (isString())
return static_cast<const JSString*>(this)->toBoolean() ? TrueTriState : FalseTriState;
+ if (isSymbol())
+ return TrueTriState;
return MixedTriState;
}
diff --git a/Source/JavaScriptCore/runtime/ArrayIteratorConstructor.cpp b/Source/JavaScriptCore/runtime/JSConsole.cpp
index 0916eeef2..7d04abf58 100644
--- a/Source/JavaScriptCore/runtime/ArrayIteratorConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/JSConsole.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple, Inc. All rights reserved.
+ * Copyright (C) 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
@@ -20,23 +20,17 @@
* 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 "ArrayIteratorConstructor.h"
+#include "JSConsole.h"
#include "JSCJSValueInlines.h"
-#include "JSCellInlines.h"
-#include "JSGlobalObject.h"
+#include "StructureInlines.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);
-}
+const ClassInfo JSConsole::s_info = { "Console", &Base::s_info, 0, CREATE_METHOD_TABLE(JSConsole) };
}
diff --git a/Source/JavaScriptCore/runtime/ArrayIteratorConstructor.h b/Source/JavaScriptCore/runtime/JSConsole.h
index 489d5d9e9..de611ec76 100644
--- a/Source/JavaScriptCore/runtime/ArrayIteratorConstructor.h
+++ b/Source/JavaScriptCore/runtime/JSConsole.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple, Inc. All rights reserved.
+ * Copyright (C) 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
@@ -20,44 +20,46 @@
* 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.
*/
-#ifndef ArrayIteratorConstructor_h
-#define ArrayIteratorConstructor_h
+#ifndef JSConsole_h
+#define JSConsole_h
-#include "InternalFunction.h"
+#include "JSObject.h"
namespace JSC {
-class ArrayIteratorPrototype;
-
-class ArrayIteratorConstructor : public JSNonFinalObject {
+class JSConsole : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
- static ArrayIteratorConstructor* create(VM& vm, Structure* structure, ArrayIteratorPrototype*)
+ DECLARE_EXPORT_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- ArrayIteratorConstructor* constructor = new (NotNull, allocateCell<ArrayIteratorConstructor>(vm.heap)) ArrayIteratorConstructor(vm, structure);
- constructor->finishCreation(vm);
- return constructor;
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}
- DECLARE_INFO;
+ static JSConsole* create(VM& vm, Structure* structure)
+ {
+ JSConsole* instance = new (NotNull, allocateCell<JSConsole>(vm.heap)) JSConsole(vm, structure);
+ instance->finishCreation(vm);
+ return instance;
+ }
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ static JSConsole* create(ExecState* exec, Structure* structure)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ return create(exec->vm(), structure);
}
private:
- ArrayIteratorConstructor(VM& vm, Structure* structure)
+ JSConsole(VM& vm, Structure* structure)
: Base(vm, structure)
{
}
- void finishCreation(VM&);
};
}
-#endif // !defined(ArrayIteratorConstructor_h)
+#endif // !defined(JSConsole_h)
diff --git a/Source/JavaScriptCore/runtime/JSDataView.cpp b/Source/JavaScriptCore/runtime/JSDataView.cpp
index 77640cdaf..75c26dbfe 100644
--- a/Source/JavaScriptCore/runtime/JSDataView.cpp
+++ b/Source/JavaScriptCore/runtime/JSDataView.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-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
@@ -29,12 +29,13 @@
#include "ArrayBufferView.h"
#include "DataView.h"
#include "Error.h"
-#include "Operations.h"
+#include "JSCInlines.h"
+#include "Reject.h"
namespace JSC {
const ClassInfo JSDataView::s_info = {
- "DataView", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSDataView)};
+ "DataView", &Base::s_info, 0, CREATE_METHOD_TABLE(JSDataView)};
JSDataView::JSDataView(VM& vm, ConstructionContext& context, ArrayBuffer* buffer)
: Base(vm, context)
@@ -47,10 +48,13 @@ JSDataView* JSDataView::create(
unsigned byteOffset, unsigned byteLength)
{
RefPtr<ArrayBuffer> buffer = passedBuffer;
- if (!ArrayBufferView::verifySubRange<uint8_t>(buffer, byteOffset, byteLength)) {
- throwVMError(
- exec, createRangeError(exec, "Byte offset and length out of range of buffer"));
- return 0;
+ if (!ArrayBufferView::verifySubRangeLength(buffer, byteOffset, byteLength, sizeof(uint8_t))) {
+ throwVMError(exec, createRangeError(exec, ASCIILiteral("Length out of range of buffer")));
+ return nullptr;
+ }
+ if (!ArrayBufferView::verifyByteOffsetAlignment(byteOffset, sizeof(uint8_t))) {
+ exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Byte offset is not aligned")));
+ return nullptr;
}
VM& vm = exec->vm();
ConstructionContext context(
@@ -80,6 +84,12 @@ bool JSDataView::set(ExecState*, JSObject*, unsigned, unsigned)
return false;
}
+bool JSDataView::setIndex(ExecState*, unsigned, JSValue)
+{
+ UNREACHABLE_FOR_PLATFORM();
+ return false;
+}
+
PassRefPtr<DataView> JSDataView::typedImpl()
{
return DataView::create(buffer(), byteOffset(), length());
@@ -93,10 +103,64 @@ bool JSDataView::getOwnPropertySlot(
slot.setValue(thisObject, DontEnum | ReadOnly, jsNumber(thisObject->m_length));
return true;
}
-
+ if (propertyName == exec->propertyNames().byteOffset) {
+ slot.setValue(thisObject, DontEnum | ReadOnly, jsNumber(thisObject->byteOffset()));
+ return true;
+ }
+
return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
}
+void JSDataView::put(
+ JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value,
+ PutPropertySlot& slot)
+{
+ JSDataView* thisObject = jsCast<JSDataView*>(cell);
+ if (propertyName == exec->propertyNames().byteLength
+ || propertyName == exec->propertyNames().byteOffset) {
+ reject(exec, slot.isStrictMode(), "Attempting to write to read-only typed array property.");
+ return;
+ }
+
+ Base::put(thisObject, exec, propertyName, value, slot);
+}
+
+bool JSDataView::defineOwnProperty(
+ JSObject* object, ExecState* exec, PropertyName propertyName,
+ const PropertyDescriptor& descriptor, bool shouldThrow)
+{
+ JSDataView* thisObject = jsCast<JSDataView*>(object);
+ if (propertyName == exec->propertyNames().byteLength
+ || propertyName == exec->propertyNames().byteOffset)
+ return reject(exec, shouldThrow, "Attempting to define read-only typed array property.");
+
+ return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
+}
+
+bool JSDataView::deleteProperty(
+ JSCell* cell, ExecState* exec, PropertyName propertyName)
+{
+ JSDataView* thisObject = jsCast<JSDataView*>(cell);
+ if (propertyName == exec->propertyNames().byteLength
+ || propertyName == exec->propertyNames().byteOffset)
+ return false;
+
+ return Base::deleteProperty(thisObject, exec, propertyName);
+}
+
+void JSDataView::getOwnNonIndexPropertyNames(
+ JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode)
+{
+ JSDataView* thisObject = jsCast<JSDataView*>(object);
+
+ if (mode.includeDontEnumProperties()) {
+ array.add(exec->propertyNames().byteOffset);
+ array.add(exec->propertyNames().byteLength);
+ }
+
+ Base::getOwnNonIndexPropertyNames(thisObject, exec, array, mode);
+}
+
ArrayBuffer* JSDataView::slowDownAndWasteMemory(JSArrayBufferView*)
{
UNREACHABLE_FOR_PLATFORM();
@@ -113,7 +177,7 @@ Structure* JSDataView::createStructure(
VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
return Structure::create(
- vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(),
+ vm, globalObject, prototype, TypeInfo(DataViewType, StructureFlags), info(),
NonArray);
}
diff --git a/Source/JavaScriptCore/runtime/JSDataView.h b/Source/JavaScriptCore/runtime/JSDataView.h
index 950d1d678..ec2e858d0 100644
--- a/Source/JavaScriptCore/runtime/JSDataView.h
+++ b/Source/JavaScriptCore/runtime/JSDataView.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-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
@@ -49,6 +49,7 @@ public:
static JSDataView* createUninitialized(ExecState*, Structure*, unsigned length);
static JSDataView* create(ExecState*, Structure*, unsigned length);
bool set(ExecState*, JSObject*, unsigned offset, unsigned length);
+ bool setIndex(ExecState*, unsigned, JSValue);
ArrayBuffer* buffer() const { return m_buffer; }
@@ -58,6 +59,11 @@ public:
protected:
static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+ static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
+ static bool deleteProperty(JSCell*, ExecState*, PropertyName);
+
+ static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
static ArrayBuffer* slowDownAndWasteMemory(JSArrayBufferView*);
static PassRefPtr<ArrayBufferView> getTypedArrayImpl(JSArrayBufferView*);
diff --git a/Source/JavaScriptCore/runtime/JSDataViewPrototype.cpp b/Source/JavaScriptCore/runtime/JSDataViewPrototype.cpp
index cd7e88313..90fe24e80 100644
--- a/Source/JavaScriptCore/runtime/JSDataViewPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/JSDataViewPrototype.cpp
@@ -29,18 +29,13 @@
#include "Error.h"
#include "JSDataView.h"
#include "Lookup.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "ToNativeFromValue.h"
#include "TypedArrayAdaptors.h"
#include <wtf/FlipBytes.h>
namespace JSC {
-const ClassInfo JSDataViewPrototype::s_info = {
- "DataViewPrototype", &Base::s_info, 0, ExecState::dataViewTable,
- CREATE_METHOD_TABLE(JSDataViewPrototype)
-};
-
/* Source for JSDataViewPrototype.lut.h
@begin dataViewTable
getInt8 dataViewProtoFuncGetInt8 DontEnum|Function 0
@@ -62,6 +57,34 @@ const ClassInfo JSDataViewPrototype::s_info = {
@end
*/
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt8(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt16(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt32(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint8(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint16(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint32(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat32(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat64(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt8(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt16(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt32(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint8(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint16(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint32(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat32(ExecState*);
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat64(ExecState*);
+
+}
+
+#include "JSDataViewPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo JSDataViewPrototype::s_info = {
+ "DataViewPrototype", &Base::s_info, &dataViewTable,
+ CREATE_METHOD_TABLE(JSDataViewPrototype)
+};
+
JSDataViewPrototype::JSDataViewPrototype(VM& vm, Structure* structure)
: Base(vm, structure)
{
@@ -76,6 +99,12 @@ JSDataViewPrototype* JSDataViewPrototype::create(VM& vm, Structure* structure)
return prototype;
}
+void JSDataViewPrototype::finishCreation(JSC::VM& vm)
+{
+ Base::finishCreation(vm);
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "DataView"), DontEnum | ReadOnly);
+}
+
Structure* JSDataViewPrototype::createStructure(
VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
@@ -87,7 +116,7 @@ bool JSDataViewPrototype::getOwnPropertySlot(
JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
return getStaticFunctionSlot<JSObject>(
- exec, ExecState::dataViewTable(exec->vm()), jsCast<JSDataViewPrototype*>(object),
+ exec, dataViewTable, jsCast<JSDataViewPrototype*>(object),
propertyName, slot);
}
@@ -96,10 +125,10 @@ EncodedJSValue getData(ExecState* exec)
{
JSDataView* dataView = jsDynamicCast<JSDataView*>(exec->thisValue());
if (!dataView)
- return throwVMError(exec, createTypeError(exec, "Receiver of DataView method must be a DataView"));
+ return throwVMError(exec, createTypeError(exec, ASCIILiteral("Receiver of DataView method must be a DataView")));
if (!exec->argumentCount())
- return throwVMError(exec, createTypeError(exec, "Need at least one argument (the byteOffset)"));
+ return throwVMError(exec, createTypeError(exec, ASCIILiteral("Need at least one argument (the byteOffset)")));
unsigned byteOffset = exec->uncheckedArgument(0).toUInt32(exec);
if (exec->hadException())
@@ -115,14 +144,25 @@ EncodedJSValue getData(ExecState* exec)
unsigned byteLength = dataView->length();
if (elementSize > byteLength || byteOffset > byteLength - elementSize)
- return throwVMError(exec, createRangeError(exec, "Out of bounds access"));
-
- typename Adaptor::Type value = *reinterpret_cast<typename Adaptor::Type*>(static_cast<uint8_t*>(dataView->vector()) + byteOffset);
-
- if (needToFlipBytesIfLittleEndian(littleEndian))
- value = flipBytes(value);
-
- return JSValue::encode(Adaptor::toJSValue(value));
+ return throwVMError(exec, createRangeError(exec, ASCIILiteral("Out of bounds access")));
+
+ const unsigned dataSize = sizeof(typename Adaptor::Type);
+ union {
+ typename Adaptor::Type value;
+ uint8_t rawBytes[dataSize];
+ } u = { };
+
+ uint8_t* dataPtr = static_cast<uint8_t*>(dataView->vector()) + byteOffset;
+
+ if (needToFlipBytesIfLittleEndian(littleEndian)) {
+ for (unsigned i = dataSize; i--;)
+ u.rawBytes[i] = *dataPtr++;
+ } else {
+ for (unsigned i = 0; i < dataSize; i++)
+ u.rawBytes[i] = *dataPtr++;
+ }
+
+ return JSValue::encode(Adaptor::toJSValue(u.value));
}
template<typename Adaptor>
@@ -130,16 +170,22 @@ EncodedJSValue setData(ExecState* exec)
{
JSDataView* dataView = jsDynamicCast<JSDataView*>(exec->thisValue());
if (!dataView)
- return throwVMError(exec, createTypeError(exec, "Receiver of DataView method must be a DataView"));
+ return throwVMError(exec, createTypeError(exec, ASCIILiteral("Receiver of DataView method must be a DataView")));
if (exec->argumentCount() < 2)
- return throwVMError(exec, createTypeError(exec, "Need at least two argument (the byteOffset and value)"));
+ return throwVMError(exec, createTypeError(exec, ASCIILiteral("Need at least two argument (the byteOffset and value)")));
unsigned byteOffset = exec->uncheckedArgument(0).toUInt32(exec);
if (exec->hadException())
return JSValue::encode(jsUndefined());
-
- typename Adaptor::Type value = toNativeFromValue<Adaptor>(exec, exec->uncheckedArgument(1));
+
+ const unsigned dataSize = sizeof(typename Adaptor::Type);
+ union {
+ typename Adaptor::Type value;
+ uint8_t rawBytes[dataSize];
+ } u;
+
+ u.value = toNativeFromValue<Adaptor>(exec, exec->uncheckedArgument(1));
if (exec->hadException())
return JSValue::encode(jsUndefined());
@@ -153,97 +199,107 @@ EncodedJSValue setData(ExecState* exec)
unsigned byteLength = dataView->length();
if (elementSize > byteLength || byteOffset > byteLength - elementSize)
- return throwVMError(exec, createRangeError(exec, "Out of bounds access"));
-
- if (needToFlipBytesIfLittleEndian(littleEndian))
- value = flipBytes(value);
-
- *reinterpret_cast<typename Adaptor::Type*>(static_cast<uint8_t*>(dataView->vector()) + byteOffset) = value;
-
+ return throwVMError(exec, createRangeError(exec, ASCIILiteral("Out of bounds access")));
+
+ uint8_t* dataPtr = static_cast<uint8_t*>(dataView->vector()) + byteOffset;
+
+ if (needToFlipBytesIfLittleEndian(littleEndian)) {
+ for (unsigned i = dataSize; i--;)
+ *dataPtr++ = u.rawBytes[i];
+ } else {
+ for (unsigned i = 0; i < dataSize; i++)
+ *dataPtr++ = u.rawBytes[i];
+ }
+
return JSValue::encode(jsUndefined());
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt8(ExecState* exec)
+#if COMPILER(CLANG)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-prototypes"
+#endif
+
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt8(ExecState* exec)
{
return getData<Int8Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt16(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt16(ExecState* exec)
{
return getData<Int16Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt32(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetInt32(ExecState* exec)
{
return getData<Int32Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint8(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint8(ExecState* exec)
{
return getData<Uint8Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint16(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint16(ExecState* exec)
{
return getData<Uint16Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint32(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetUint32(ExecState* exec)
{
return getData<Uint32Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat32(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat32(ExecState* exec)
{
return getData<Float32Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat64(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncGetFloat64(ExecState* exec)
{
return getData<Float64Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt8(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt8(ExecState* exec)
{
return setData<Int8Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt16(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt16(ExecState* exec)
{
return setData<Int16Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt32(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetInt32(ExecState* exec)
{
return setData<Int32Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint8(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint8(ExecState* exec)
{
return setData<Uint8Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint16(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint16(ExecState* exec)
{
return setData<Uint16Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint32(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetUint32(ExecState* exec)
{
return setData<Uint32Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat32(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat32(ExecState* exec)
{
return setData<Float32Adaptor>(exec);
}
-static EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat64(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dataViewProtoFuncSetFloat64(ExecState* exec)
{
return setData<Float64Adaptor>(exec);
}
+#if COMPILER(CLANG)
+#pragma clang diagnostic pop
+#endif
} // namespace JSC
-
-#include "JSDataViewPrototype.lut.h"
-
diff --git a/Source/JavaScriptCore/runtime/JSDataViewPrototype.h b/Source/JavaScriptCore/runtime/JSDataViewPrototype.h
index 9d2ba2c6d..46a6d2209 100644
--- a/Source/JavaScriptCore/runtime/JSDataViewPrototype.h
+++ b/Source/JavaScriptCore/runtime/JSDataViewPrototype.h
@@ -33,10 +33,13 @@ namespace JSC {
class JSDataViewPrototype : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
protected:
JSDataViewPrototype(VM&, Structure*);
+ void finishCreation(VM&);
+
public:
static JSDataViewPrototype* create(VM&, Structure*);
@@ -46,8 +49,6 @@ public:
protected:
static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
-
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | Base::StructureFlags;
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSDateMath.cpp b/Source/JavaScriptCore/runtime/JSDateMath.cpp
index 31923d1a5..1482e312f 100644
--- a/Source/JavaScriptCore/runtime/JSDateMath.cpp
+++ b/Source/JavaScriptCore/runtime/JSDateMath.cpp
@@ -74,7 +74,7 @@
#include "JSObject.h"
#include "JSScope.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include <algorithm>
#include <limits.h>
@@ -229,7 +229,7 @@ double parseDateFromNullTerminatedCharacters(VM& vm, const char* dateString)
int offset;
double localTimeMS = WTF::parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset);
if (std::isnan(localTimeMS))
- return QNaN;
+ return std::numeric_limits<double>::quiet_NaN();
// fall back to local timezone.
if (!haveTZ)
diff --git a/Source/JavaScriptCore/runtime/JSDateMath.h b/Source/JavaScriptCore/runtime/JSDateMath.h
index 20a71c93b..4e4d16ff5 100644
--- a/Source/JavaScriptCore/runtime/JSDateMath.h
+++ b/Source/JavaScriptCore/runtime/JSDateMath.h
@@ -50,11 +50,11 @@ namespace JSC {
class VM;
-void msToGregorianDateTime(VM&, double, WTF::TimeType outputTimeType, GregorianDateTime&);
-double gregorianDateTimeToMS(VM&, const GregorianDateTime&, double, WTF::TimeType inputTimeType);
-double getUTCOffset(VM&);
-double parseDateFromNullTerminatedCharacters(VM&, const char* dateString);
-double parseDate(VM&, const WTF::String&);
+JS_EXPORT_PRIVATE void msToGregorianDateTime(VM&, double, WTF::TimeType outputTimeType, GregorianDateTime&);
+JS_EXPORT_PRIVATE double gregorianDateTimeToMS(VM&, const GregorianDateTime&, double, WTF::TimeType inputTimeType);
+JS_EXPORT_PRIVATE double getUTCOffset(VM&);
+JS_EXPORT_PRIVATE double parseDateFromNullTerminatedCharacters(VM&, const char* dateString);
+JS_EXPORT_PRIVATE double parseDate(VM&, const WTF::String&);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSDestructibleObject.h b/Source/JavaScriptCore/runtime/JSDestructibleObject.h
index 27dc06da5..d687b8420 100644
--- a/Source/JavaScriptCore/runtime/JSDestructibleObject.h
+++ b/Source/JavaScriptCore/runtime/JSDestructibleObject.h
@@ -29,17 +29,6 @@ private:
const ClassInfo* m_classInfo;
};
-inline const ClassInfo* JSCell::classInfo() const
-{
- if (MarkedBlock::blockFor(this)->destructorType() == MarkedBlock::Normal)
- return static_cast<const JSDestructibleObject*>(this)->classInfo();
-#if ENABLE(GC_VALIDATION)
- return m_structure.unvalidatedGet()->classInfo();
-#else
- return m_structure->classInfo();
-#endif
-}
-
} // namespace JSC
#endif
diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.cpp b/Source/JavaScriptCore/runtime/JSEnvironmentRecord.cpp
index fc262f5d8..f1d769592 100644
--- a/Source/JavaScriptCore/runtime/JSVariableObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSEnvironmentRecord.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2012, 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
@@ -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.
*
@@ -27,12 +27,20 @@
*/
#include "config.h"
-#include "JSVariableObject.h"
+#include "JSEnvironmentRecord.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
-const ClassInfo JSVariableObject::s_info = { "VariableObject", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSVariableObject) };
+const ClassInfo JSEnvironmentRecord::s_info = { "EnvironmentRecord", &Base::s_info, 0, CREATE_METHOD_TABLE(JSEnvironmentRecord) };
+
+void JSEnvironmentRecord::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSEnvironmentRecord* thisObject = jsCast<JSEnvironmentRecord*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+ visitor.appendValues(thisObject->variables(), thisObject->symbolTable()->scopeSize());
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSEnvironmentRecord.h b/Source/JavaScriptCore/runtime/JSEnvironmentRecord.h
new file mode 100644
index 000000000..8cb3dd029
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSEnvironmentRecord.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2007, 2008, 2012, 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.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ */
+
+#ifndef JSEnvironmentRecord_h
+#define JSEnvironmentRecord_h
+
+#include "JSObject.h"
+#include "JSSymbolTableObject.h"
+#include "Register.h"
+#include "SymbolTable.h"
+
+namespace JSC {
+
+class LLIntOffsetsExtractor;
+class Register;
+
+class JSEnvironmentRecord : public JSSymbolTableObject {
+ friend class JIT;
+ friend class LLIntOffsetsExtractor;
+
+public:
+ typedef JSSymbolTableObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags;
+
+ WriteBarrierBase<Unknown>* variables()
+ {
+ return bitwise_cast<WriteBarrierBase<Unknown>*>(bitwise_cast<char*>(this) + offsetOfVariables());
+ }
+
+ bool isValidScopeOffset(ScopeOffset offset)
+ {
+ return !!offset && offset.offset() < symbolTable()->scopeSize();
+ }
+
+ WriteBarrierBase<Unknown>& variableAt(ScopeOffset offset)
+ {
+ ASSERT(isValidScopeOffset(offset));
+ return variables()[offset.offset()];
+ }
+
+ static size_t offsetOfVariables()
+ {
+ return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(JSEnvironmentRecord));
+ }
+
+ static ptrdiff_t offsetOfVariable(ScopeOffset offset)
+ {
+ return offsetOfVariables() + offset.offset() * sizeof(WriteBarrier<Unknown>);
+ }
+
+ DECLARE_INFO;
+
+ static size_t allocationSizeForScopeSize(unsigned scopeSize)
+ {
+ return offsetOfVariables() + scopeSize * sizeof(WriteBarrier<Unknown>);
+ }
+
+ static size_t allocationSize(SymbolTable* symbolTable)
+ {
+ return allocationSizeForScopeSize(symbolTable->scopeSize());
+ }
+
+protected:
+ JSEnvironmentRecord(
+ VM& vm,
+ Structure* structure,
+ JSScope* scope,
+ SymbolTable* symbolTable)
+ : Base(vm, structure, scope, symbolTable)
+ {
+ }
+
+ void finishCreationUninitialized(VM& vm)
+ {
+ Base::finishCreation(vm);
+ }
+
+ void finishCreation(VM& vm, JSValue value)
+ {
+ finishCreationUninitialized(vm);
+ ASSERT(value == jsUndefined() || value == jsTDZValue());
+ for (unsigned i = symbolTable()->scopeSize(); i--;) {
+ // Filling this with undefined/TDZEmptyValue is useful because that's what variables start out as.
+ variableAt(ScopeOffset(i)).setStartingValue(value);
+ }
+ }
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+};
+
+} // namespace JSC
+
+#endif // JSEnvironmentRecord_h
diff --git a/Source/JavaScriptCore/runtime/JSExportMacros.h b/Source/JavaScriptCore/runtime/JSExportMacros.h
index 77e4b0a33..bd46591b4 100644
--- a/Source/JavaScriptCore/runtime/JSExportMacros.h
+++ b/Source/JavaScriptCore/runtime/JSExportMacros.h
@@ -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
@@ -30,7 +30,6 @@
#ifndef JSExportMacros_h
#define JSExportMacros_h
-#include <wtf/Platform.h>
#include <wtf/ExportMacros.h>
// See note in wtf/Platform.h for more info on EXPORT_MACROS.
@@ -48,7 +47,7 @@
#else // !USE(EXPORT_MACROS)
-#if OS(WINDOWS) && !COMPILER(GCC)
+#if OS(WINDOWS) && !COMPILER(GCC_OR_CLANG)
#if defined(BUILDING_JavaScriptCore) || defined(STATICALLY_LINKED_WITH_JavaScriptCore)
#define JS_EXPORTDATA __declspec(dllexport)
diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp
index 241964610..70ec4fad2 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSFunction.cpp
@@ -1,9 +1,10 @@
/*
* 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) 2003-2009, 2015-2016 Apple Inc. All rights reserved.
* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
* Copyright (C) 2007 Maks Orlovich
+ * Copyright (C) 2015 Canon 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
@@ -25,22 +26,23 @@
#include "config.h"
#include "JSFunction.h"
-#include "Arguments.h"
+#include "ClonedArguments.h"
#include "CodeBlock.h"
#include "CommonIdentifiers.h"
#include "CallFrame.h"
-#include "CallFrameInlines.h"
#include "ExceptionHelpers.h"
#include "FunctionPrototype.h"
+#include "GeneratorPrototype.h"
#include "GetterSetter.h"
#include "JSArray.h"
-#include "JSBoundFunction.h"
+#include "JSBoundFunction.h"
+#include "JSCInlines.h"
+#include "JSFunctionInlines.h"
#include "JSGlobalObject.h"
#include "JSNotAnObject.h"
#include "Interpreter.h"
#include "ObjectConstructor.h"
#include "ObjectPrototype.h"
-#include "Operations.h"
#include "Parser.h"
#include "PropertyNameArray.h"
#include "StackVisitor.h"
@@ -52,51 +54,60 @@ EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec)
return throwVMError(exec, createNotAConstructorError(exec, exec->callee()));
}
-const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFunction) };
+const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(JSFunction) };
bool JSFunction::isHostFunctionNonInline() const
{
return isHostFunction();
}
-JSFunction* JSFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)
+JSFunction* JSFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+ return create(vm, executable, scope, scope->globalObject()->functionStructure());
+}
+
+JSFunction* JSFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
+{
+ JSFunction* result = createImpl(vm, executable, scope, structure);
+ executable->singletonFunction()->notifyWrite(vm, result, "Allocating a function");
+ return result;
+}
+
+#if ENABLE(WEBASSEMBLY)
+JSFunction* JSFunction::create(VM& vm, WebAssemblyExecutable* executable, JSScope* scope)
+{
+ JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, executable, scope);
+ ASSERT(function->structure()->globalObject());
+ function->finishCreation(vm);
+ return function;
+}
+#endif
+
+NativeExecutable* JSFunction::lookUpOrCreateNativeExecutable(VM& vm, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor, const String& name)
{
- NativeExecutable* executable;
#if !ENABLE(JIT)
UNUSED_PARAM(intrinsic);
#else
if (intrinsic != NoIntrinsic && vm.canUseJIT()) {
ASSERT(nativeConstructor == callHostFunctionAsConstructor);
- executable = vm.getHostFunction(nativeFunction, intrinsic);
- } else
+ return vm.getHostFunction(nativeFunction, intrinsic, name);
+ }
#endif
- executable = vm.getHostFunction(nativeFunction, nativeConstructor);
+ return vm.getHostFunction(nativeFunction, nativeConstructor, name);
+}
+JSFunction* JSFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)
+{
+ NativeExecutable* executable = lookUpOrCreateNativeExecutable(vm, nativeFunction, intrinsic, nativeConstructor, name);
JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, globalObject, globalObject->functionStructure());
// Can't do this during initialization because getHostFunction might do a GC allocation.
function->finishCreation(vm, executable, length, name);
return function;
}
-void JSFunction::destroy(JSCell* cell)
-{
- static_cast<JSFunction*>(cell)->JSFunction::~JSFunction();
-}
-
JSFunction::JSFunction(VM& vm, JSGlobalObject* globalObject, Structure* structure)
- : Base(vm, structure)
+ : Base(vm, globalObject, structure)
, m_executable()
- , m_scope(vm, this, globalObject)
- // We initialize blind so that changes to the prototype after function creation but before
- // the optimizer kicks in don't disable optimizations. Once the optimizer kicks in, the
- // watchpoint will start watching and any changes will both force deoptimization and disable
- // future attempts to optimize. This is necessary because we are guaranteed that the
- // allocation profile is changed exactly once prior to optimizations kicking in. We could be
- // smarter and count the number of times the prototype is clobbered and only optimize if it
- // was clobbered exactly once, but that seems like overkill. In almost all cases it will be
- // clobbered once, and if it's clobbered more than once, that will probably only occur
- // before we started optimizing, anyway.
- , m_allocationProfileWatchpoint(ClearWatchpoint)
{
}
@@ -109,14 +120,62 @@ void JSFunction::finishCreation(VM& vm, NativeExecutable* executable, int length
putDirect(vm, vm.propertyNames->length, jsNumber(length), DontDelete | ReadOnly | DontEnum);
}
-ObjectAllocationProfile* JSFunction::createAllocationProfile(ExecState* exec, size_t inlineCapacity)
+JSFunction* JSFunction::createBuiltinFunction(VM& vm, FunctionExecutable* executable, JSGlobalObject* globalObject)
+{
+ JSFunction* function = create(vm, executable, globalObject);
+ function->putDirect(vm, vm.propertyNames->name, jsString(&vm, executable->name().string()), DontDelete | ReadOnly | DontEnum);
+ function->putDirect(vm, vm.propertyNames->length, jsNumber(executable->parameterCount()), DontDelete | ReadOnly | DontEnum);
+ return function;
+}
+
+JSFunction* JSFunction::createBuiltinFunction(VM& vm, FunctionExecutable* executable, JSGlobalObject* globalObject, const String& name)
+{
+ JSFunction* function = create(vm, executable, globalObject);
+ function->putDirect(vm, vm.propertyNames->name, jsString(&vm, name), DontDelete | ReadOnly | DontEnum);
+ function->putDirect(vm, vm.propertyNames->length, jsNumber(executable->parameterCount()), DontDelete | ReadOnly | DontEnum);
+ return function;
+}
+
+FunctionRareData* JSFunction::allocateRareData(VM& vm)
{
+ ASSERT(!m_rareData);
+ FunctionRareData* rareData = FunctionRareData::create(vm);
+
+ // A DFG compilation thread may be trying to read the rare data
+ // We want to ensure that it sees it properly allocated
+ WTF::storeStoreFence();
+
+ m_rareData.set(vm, this, rareData);
+ return m_rareData.get();
+}
+
+FunctionRareData* JSFunction::allocateAndInitializeRareData(ExecState* exec, size_t inlineCapacity)
+{
+ ASSERT(!m_rareData);
+ VM& vm = exec->vm();
+ JSObject* prototype = jsDynamicCast<JSObject*>(get(exec, vm.propertyNames->prototype));
+ if (!prototype)
+ prototype = globalObject()->objectPrototype();
+ FunctionRareData* rareData = FunctionRareData::create(vm);
+ rareData->initializeObjectAllocationProfile(globalObject()->vm(), prototype, inlineCapacity);
+
+ // A DFG compilation thread may be trying to read the rare data
+ // We want to ensure that it sees it properly allocated
+ WTF::storeStoreFence();
+
+ m_rareData.set(vm, this, rareData);
+ return m_rareData.get();
+}
+
+FunctionRareData* JSFunction::initializeRareData(ExecState* exec, size_t inlineCapacity)
+{
+ ASSERT(!!m_rareData);
VM& vm = exec->vm();
JSObject* prototype = jsDynamicCast<JSObject*>(get(exec, vm.propertyNames->prototype));
if (!prototype)
prototype = globalObject()->objectPrototype();
- m_allocationProfile.initialize(globalObject()->vm(), this, prototype, inlineCapacity);
- return &m_allocationProfile;
+ m_rareData->initializeObjectAllocationProfile(globalObject()->vm(), prototype, inlineCapacity);
+ return m_rareData.get();
}
String JSFunction::name(ExecState* exec)
@@ -142,7 +201,7 @@ const String JSFunction::calculatedDisplayName(ExecState* exec)
return explicitName;
const String actualName = name(exec);
- if (!actualName.isEmpty() || isHostFunction())
+ if (!actualName.isEmpty() || isHostOrBuiltinFunction())
return actualName;
return jsExecutable()->inferredName().string();
@@ -150,22 +209,20 @@ const String JSFunction::calculatedDisplayName(ExecState* exec)
const SourceCode* JSFunction::sourceCode() const
{
- if (isHostFunction())
+ if (isHostOrBuiltinFunction())
return 0;
return &jsExecutable()->source();
}
-
+
void JSFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSFunction* thisObject = jsCast<JSFunction*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
Base::visitChildren(thisObject, visitor);
- visitor.append(&thisObject->m_scope);
visitor.append(&thisObject->m_executable);
- thisObject->m_allocationProfile.visitAggregate(visitor);
+ if (thisObject->m_rareData)
+ visitor.append(&thisObject->m_rareData);
}
CallType JSFunction::getCallData(JSCell* cell, CallData& callData)
@@ -212,9 +269,9 @@ static JSValue retrieveArguments(ExecState* exec, JSFunction* functionObj)
return functor.result();
}
-EncodedJSValue JSFunction::argumentsGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue JSFunction::argumentsGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(slotBase));
+ JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(thisValue));
ASSERT(!thisObj->isHostFunction());
return JSValue::encode(retrieveArguments(exec, thisObj));
@@ -267,31 +324,35 @@ static JSValue retrieveCallerFunction(ExecState* exec, JSFunction* functionObj)
return functor.result();
}
-EncodedJSValue JSFunction::callerGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue JSFunction::callerGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(slotBase));
+ JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(thisValue));
ASSERT(!thisObj->isHostFunction());
JSValue caller = retrieveCallerFunction(exec, thisObj);
// See ES5.1 15.3.5.4 - Function.caller may not be used to retrieve a strict caller.
- if (!caller.isObject() || !asObject(caller)->inherits(JSFunction::info()))
+ if (!caller.isObject() || !asObject(caller)->inherits(JSFunction::info())) {
+ // It isn't a JSFunction, but if it is a JSCallee from a program or call eval, return null.
+ if (jsDynamicCast<JSCallee*>(caller))
+ return JSValue::encode(jsNull());
return JSValue::encode(caller);
+ }
JSFunction* function = jsCast<JSFunction*>(caller);
- if (function->isHostFunction() || !function->jsExecutable()->isStrictMode())
+ if (function->isHostOrBuiltinFunction() || !function->jsExecutable()->isStrictMode())
return JSValue::encode(caller);
return JSValue::encode(throwTypeError(exec, ASCIILiteral("Function.caller used to retrieve strict caller")));
}
-EncodedJSValue JSFunction::lengthGetter(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue JSFunction::lengthGetter(ExecState*, EncodedJSValue thisValue, PropertyName)
{
- JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(slotBase));
+ JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(thisValue));
ASSERT(!thisObj->isHostFunction());
return JSValue::encode(jsNumber(thisObj->jsExecutable()->parameterCount()));
}
-EncodedJSValue JSFunction::nameGetter(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue JSFunction::nameGetter(ExecState*, EncodedJSValue thisValue, PropertyName)
{
- JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(slotBase));
+ JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(thisValue));
ASSERT(!thisObj->isHostFunction());
return JSValue::encode(thisObj->jsExecutable()->nameValue());
}
@@ -299,15 +360,20 @@ EncodedJSValue JSFunction::nameGetter(ExecState*, EncodedJSValue slotBase, Encod
bool JSFunction::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
JSFunction* thisObject = jsCast<JSFunction*>(object);
- if (thisObject->isHostFunction())
+ if (thisObject->isHostOrBuiltinFunction())
return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
- if (propertyName == exec->propertyNames().prototype) {
+ if (propertyName == exec->propertyNames().prototype && !thisObject->jsExecutable()->isArrowFunction()) {
VM& vm = exec->vm();
unsigned attributes;
PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName, attributes);
if (!isValidOffset(offset)) {
- JSObject* prototype = constructEmptyObject(exec);
+ JSObject* prototype = nullptr;
+ if (thisObject->jsExecutable()->parseMode() == SourceParseMode::GeneratorWrapperFunctionMode)
+ prototype = constructEmptyObject(exec, thisObject->globalObject()->generatorPrototype());
+ else
+ prototype = constructEmptyObject(exec);
+
prototype->putDirect(vm, exec->propertyNames().constructor, thisObject, DontEnum);
thisObject->putDirect(vm, exec->propertyNames().prototype, prototype, DontDelete | DontEnum);
offset = thisObject->getDirectOffset(vm, exec->propertyNames().prototype, attributes);
@@ -361,15 +427,16 @@ bool JSFunction::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyN
void JSFunction::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
JSFunction* thisObject = jsCast<JSFunction*>(object);
- if (!thisObject->isHostFunction() && (mode == IncludeDontEnumProperties)) {
+ if (!thisObject->isHostOrBuiltinFunction() && mode.includeDontEnumProperties()) {
+ VM& vm = exec->vm();
// Make sure prototype has been reified.
- PropertySlot slot(thisObject);
- thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, exec->propertyNames().prototype, slot);
+ PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
+ thisObject->methodTable(vm)->getOwnPropertySlot(thisObject, exec, vm.propertyNames->prototype, slot);
- propertyNames.add(exec->propertyNames().arguments);
- propertyNames.add(exec->propertyNames().caller);
- propertyNames.add(exec->propertyNames().length);
- propertyNames.add(exec->propertyNames().name);
+ propertyNames.add(vm.propertyNames->arguments);
+ propertyNames.add(vm.propertyNames->caller);
+ propertyNames.add(vm.propertyNames->length);
+ propertyNames.add(vm.propertyNames->name);
}
Base::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
}
@@ -377,18 +444,18 @@ void JSFunction::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec,
void JSFunction::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
{
JSFunction* thisObject = jsCast<JSFunction*>(cell);
- if (thisObject->isHostFunction()) {
+ if (thisObject->isHostOrBuiltinFunction()) {
Base::put(thisObject, exec, propertyName, value, slot);
return;
}
if (propertyName == exec->propertyNames().prototype) {
// Make sure prototype has been reified, such that it can only be overwritten
// following the rules set out in ECMA-262 8.12.9.
- PropertySlot slot(thisObject);
- thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
- thisObject->m_allocationProfile.clear();
- thisObject->m_allocationProfileWatchpoint.fireAll();
- // Don't allow this to be cached, since a [[Put]] must clear m_allocationProfile.
+ PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
+ thisObject->methodTable(exec->vm())->getOwnPropertySlot(thisObject, exec, propertyName, slot);
+ if (thisObject->m_rareData)
+ thisObject->m_rareData->clear("Store to prototype property of a function");
+ // Don't allow this to be cached, since a [[Put]] must clear m_rareData.
PutPropertySlot dontCache(thisObject);
Base::put(thisObject, exec, propertyName, value, dontCache);
return;
@@ -412,36 +479,39 @@ bool JSFunction::deleteProperty(JSCell* cell, ExecState* exec, PropertyName prop
{
JSFunction* thisObject = jsCast<JSFunction*>(cell);
// For non-host functions, don't let these properties by deleted - except by DefineOwnProperty.
- if (!thisObject->isHostFunction() && !exec->vm().isInDefineOwnProperty()
- && (propertyName == exec->propertyNames().arguments
+ if (!thisObject->isHostOrBuiltinFunction() && !exec->vm().isInDefineOwnProperty()) {
+ FunctionExecutable* executable = thisObject->jsExecutable();
+ if (propertyName == exec->propertyNames().arguments
|| propertyName == exec->propertyNames().length
|| propertyName == exec->propertyNames().name
- || propertyName == exec->propertyNames().prototype
- || propertyName == exec->propertyNames().caller))
+ || (propertyName == exec->propertyNames().prototype && !executable->isArrowFunction())
+ || propertyName == exec->propertyNames().caller)
return false;
+ }
+
return Base::deleteProperty(thisObject, exec, propertyName);
}
bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
{
JSFunction* thisObject = jsCast<JSFunction*>(object);
- if (thisObject->isHostFunction())
+ if (thisObject->isHostOrBuiltinFunction())
return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
if (propertyName == exec->propertyNames().prototype) {
// Make sure prototype has been reified, such that it can only be overwritten
// following the rules set out in ECMA-262 8.12.9.
- PropertySlot slot(thisObject);
- thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
- thisObject->m_allocationProfile.clear();
- thisObject->m_allocationProfileWatchpoint.fireAll();
+ PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
+ thisObject->methodTable(exec->vm())->getOwnPropertySlot(thisObject, exec, propertyName, slot);
+ if (thisObject->m_rareData)
+ thisObject->m_rareData->clear("Store to prototype property of a function");
return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
}
bool valueCheck;
if (propertyName == exec->propertyNames().arguments) {
if (thisObject->jsExecutable()->isStrictMode()) {
- PropertySlot slot(thisObject);
+ PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
if (!Base::getOwnPropertySlot(thisObject, exec, propertyName, slot))
thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec->vm()), DontDelete | DontEnum | Accessor);
return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
@@ -449,7 +519,7 @@ bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNa
valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), retrieveArguments(exec, thisObject));
} else if (propertyName == exec->propertyNames().caller) {
if (thisObject->jsExecutable()->isStrictMode()) {
- PropertySlot slot(thisObject);
+ PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
if (!Base::getOwnPropertySlot(thisObject, exec, propertyName, slot))
thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec->vm()), DontDelete | DontEnum | Accessor);
return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
@@ -464,7 +534,7 @@ bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNa
if (descriptor.configurablePresent() && descriptor.configurable()) {
if (throwException)
- exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to configurable attribute of unconfigurable property.")));
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change configurable attribute of unconfigurable property.")));
return false;
}
if (descriptor.enumerablePresent() && descriptor.enumerable()) {
@@ -494,11 +564,17 @@ bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyNa
ConstructType JSFunction::getConstructData(JSCell* cell, ConstructData& constructData)
{
JSFunction* thisObject = jsCast<JSFunction*>(cell);
+
if (thisObject->isHostFunction()) {
constructData.native.function = thisObject->nativeConstructor();
return ConstructTypeHost;
}
- constructData.js.functionExecutable = thisObject->jsExecutable();
+
+ FunctionExecutable* functionExecutable = thisObject->jsExecutable();
+ if (functionExecutable->constructAbility() == ConstructAbility::CannotConstruct)
+ return ConstructTypeNone;
+
+ constructData.js.functionExecutable = functionExecutable;
constructData.js.scope = thisObject->scope();
return ConstructTypeJS;
}
@@ -509,7 +585,7 @@ String getCalculatedDisplayName(CallFrame* callFrame, JSObject* object)
return function->calculatedDisplayName(callFrame);
if (InternalFunction* function = jsDynamicCast<InternalFunction*>(object))
return function->calculatedDisplayName(callFrame);
- return "";
+ return emptyString();
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h
index 7cd14b8c2..878bbab42 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.h
+++ b/Source/JavaScriptCore/runtime/JSFunction.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2006-2009, 2015-2016 Apple Inc. All rights reserved.
* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
* Copyright (C) 2007 Maks Orlovich
*
@@ -24,163 +24,179 @@
#ifndef JSFunction_h
#define JSFunction_h
+#include "FunctionRareData.h"
#include "InternalFunction.h"
-#include "JSDestructibleObject.h"
+#include "JSCallee.h"
#include "JSScope.h"
-#include "ObjectAllocationProfile.h"
#include "Watchpoint.h"
namespace JSC {
- class ExecutableBase;
- class FunctionExecutable;
- class FunctionPrototype;
- class JSActivation;
- class JSGlobalObject;
- class LLIntOffsetsExtractor;
- class NativeExecutable;
- class SourceCode;
- namespace DFG {
- class SpeculativeJIT;
- class JITCompiler;
+class ExecutableBase;
+class FunctionExecutable;
+class FunctionPrototype;
+class JSLexicalEnvironment;
+class JSGlobalObject;
+class LLIntOffsetsExtractor;
+class NativeExecutable;
+class SourceCode;
+class WebAssemblyExecutable;
+class InternalFunction;
+namespace DFG {
+class SpeculativeJIT;
+class JITCompiler;
+}
+
+JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState*);
+
+JS_EXPORT_PRIVATE String getCalculatedDisplayName(CallFrame*, JSObject*);
+
+class JSFunction : public JSCallee {
+ friend class JIT;
+ friend class DFG::SpeculativeJIT;
+ friend class DFG::JITCompiler;
+ friend class VM;
+ friend class InternalFunction;
+
+public:
+ typedef JSCallee Base;
+ const static unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames;
+
+ static size_t allocationSize(size_t inlineCapacity)
+ {
+ ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
+ return sizeof(JSFunction);
}
- JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState*);
+ JS_EXPORT_PRIVATE static JSFunction* create(VM&, JSGlobalObject*, int length, const String& name, NativeFunction, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor);
+
+ static JSFunction* createWithInvalidatedReallocationWatchpoint(VM&, FunctionExecutable*, JSScope*);
+
+ static JSFunction* create(VM&, FunctionExecutable*, JSScope*);
+ static JSFunction* create(VM&, FunctionExecutable*, JSScope*, Structure*);
+#if ENABLE(WEBASSEMBLY)
+ static JSFunction* create(VM&, WebAssemblyExecutable*, JSScope*);
+#endif
+
+ JS_EXPORT_PRIVATE static JSFunction* createBuiltinFunction(VM&, FunctionExecutable*, JSGlobalObject*);
+ static JSFunction* createBuiltinFunction(VM&, FunctionExecutable*, JSGlobalObject*, const String& name);
+
+ JS_EXPORT_PRIVATE String name(ExecState*);
+ JS_EXPORT_PRIVATE String displayName(ExecState*);
+ const String calculatedDisplayName(ExecState*);
+
+ ExecutableBase* executable() const { return m_executable.get(); }
+
+ // To call any of these methods include JSFunctionInlines.h
+ bool isHostFunction() const;
+ FunctionExecutable* jsExecutable() const;
+ Intrinsic intrinsic() const;
+
+ JS_EXPORT_PRIVATE const SourceCode* sourceCode() const;
+
+ DECLARE_EXPORT_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ ASSERT(globalObject);
+ return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
+ }
+
+ NativeFunction nativeFunction();
+ NativeFunction nativeConstructor();
+
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+
+ static inline ptrdiff_t offsetOfExecutable()
+ {
+ return OBJECT_OFFSETOF(JSFunction, m_executable);
+ }
+
+ static inline ptrdiff_t offsetOfRareData()
+ {
+ return OBJECT_OFFSETOF(JSFunction, m_rareData);
+ }
+
+ FunctionRareData* rareData(VM& vm)
+ {
+ if (UNLIKELY(!m_rareData))
+ return allocateRareData(vm);
+ return m_rareData.get();
+ }
+
+ FunctionRareData* rareData(ExecState* exec, unsigned inlineCapacity)
+ {
+ if (UNLIKELY(!m_rareData))
+ return allocateAndInitializeRareData(exec, inlineCapacity);
+ if (UNLIKELY(!m_rareData->isObjectAllocationProfileInitialized()))
+ return initializeRareData(exec, inlineCapacity);
+ return m_rareData.get();
+ }
+
+ FunctionRareData* rareData()
+ {
+ FunctionRareData* rareData = m_rareData.get();
+
+ // The JS thread may be concurrently creating the rare data
+ // If we see it, we want to ensure it has been properly created
+ WTF::loadLoadFence();
+
+ return rareData;
+ }
+
+ bool isHostOrBuiltinFunction() const;
+ bool isBuiltinFunction() const;
+ JS_EXPORT_PRIVATE bool isHostFunctionNonInline() const;
+ bool isClassConstructorFunction() const;
+
+protected:
+ JS_EXPORT_PRIVATE JSFunction(VM&, JSGlobalObject*, Structure*);
+ JSFunction(VM&, FunctionExecutable*, JSScope*, Structure*);
+
+#if ENABLE(WEBASSEMBLY)
+ JSFunction(VM&, WebAssemblyExecutable*, JSScope*);
+#endif
+
+ void finishCreation(VM&, NativeExecutable*, int length, const String& name);
+ using Base::finishCreation;
+
+ FunctionRareData* allocateRareData(VM&);
+ FunctionRareData* allocateAndInitializeRareData(ExecState*, size_t inlineCapacity);
+ FunctionRareData* initializeRareData(ExecState*, size_t inlineCapacity);
- JS_EXPORT_PRIVATE String getCalculatedDisplayName(CallFrame*, JSObject*);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode = EnumerationMode());
+ static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
+
+ static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+
+ static bool deleteProperty(JSCell*, ExecState*, PropertyName);
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+
+ static NativeExecutable* lookUpOrCreateNativeExecutable(VM&, NativeFunction, Intrinsic, NativeFunction nativeConstructor, const String& name);
+
+private:
+ static JSFunction* createImpl(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
+ {
+ JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, executable, scope, structure);
+ ASSERT(function->structure()->globalObject());
+ function->finishCreation(vm);
+ return function;
+ }
- class JSFunction : public JSDestructibleObject {
- friend class JIT;
- friend class DFG::SpeculativeJIT;
- friend class DFG::JITCompiler;
- friend class VM;
-
- public:
- typedef JSDestructibleObject Base;
-
- JS_EXPORT_PRIVATE static JSFunction* create(VM&, JSGlobalObject*, int length, const String& name, NativeFunction, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor);
-
- static JSFunction* create(VM& vm, FunctionExecutable* executable, JSScope* scope)
- {
- JSFunction* function = new (NotNull, allocateCell<JSFunction>(vm.heap)) JSFunction(vm, executable, scope);
- ASSERT(function->structure()->globalObject());
- function->finishCreation(vm);
- return function;
- }
-
- static void destroy(JSCell*);
-
- JS_EXPORT_PRIVATE String name(ExecState*);
- JS_EXPORT_PRIVATE String displayName(ExecState*);
- const String calculatedDisplayName(ExecState*);
-
- JSScope* scope()
- {
- ASSERT(!isHostFunctionNonInline());
- return m_scope.get();
- }
- // This method may be called for host functins, in which case it
- // will return an arbitrary value. This should only be used for
- // optimized paths in which the return value does not matter for
- // host functions, and checking whether the function is a host
- // function is deemed too expensive.
- JSScope* scopeUnchecked()
- {
- return m_scope.get();
- }
- void setScope(VM& vm, JSScope* scope)
- {
- ASSERT(!isHostFunctionNonInline());
- m_scope.set(vm, this, scope);
- }
-
- ExecutableBase* executable() const { return m_executable.get(); }
-
- // To call either of these methods include Executable.h
- inline bool isHostFunction() const;
- FunctionExecutable* jsExecutable() const;
-
- JS_EXPORT_PRIVATE const SourceCode* sourceCode() const;
-
- DECLARE_EXPORT_INFO;
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- ASSERT(globalObject);
- return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
- }
-
- NativeFunction nativeFunction();
- NativeFunction nativeConstructor();
-
- static ConstructType getConstructData(JSCell*, ConstructData&);
- static CallType getCallData(JSCell*, CallData&);
-
- static inline ptrdiff_t offsetOfScopeChain()
- {
- return OBJECT_OFFSETOF(JSFunction, m_scope);
- }
-
- static inline ptrdiff_t offsetOfExecutable()
- {
- return OBJECT_OFFSETOF(JSFunction, m_executable);
- }
-
- static inline ptrdiff_t offsetOfAllocationProfile()
- {
- return OBJECT_OFFSETOF(JSFunction, m_allocationProfile);
- }
-
- ObjectAllocationProfile* allocationProfile(ExecState* exec, unsigned inlineCapacity)
- {
- if (UNLIKELY(m_allocationProfile.isNull()))
- return createAllocationProfile(exec, inlineCapacity);
- return &m_allocationProfile;
- }
-
- Structure* allocationStructure() { return m_allocationProfile.structure(); }
-
- InlineWatchpointSet& allocationProfileWatchpointSet()
- {
- return m_allocationProfileWatchpoint;
- }
-
- protected:
- const static unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
-
- JS_EXPORT_PRIVATE JSFunction(VM&, JSGlobalObject*, Structure*);
- JSFunction(VM&, FunctionExecutable*, JSScope*);
-
- void finishCreation(VM&, NativeExecutable*, int length, const String& name);
- using Base::finishCreation;
-
- ObjectAllocationProfile* createAllocationProfile(ExecState*, size_t inlineCapacity);
-
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode = ExcludeDontEnumProperties);
- static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
-
- static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
-
- static bool deleteProperty(JSCell*, ExecState*, PropertyName);
-
- static void visitChildren(JSCell*, SlotVisitor&);
-
- private:
- friend class LLIntOffsetsExtractor;
-
- JS_EXPORT_PRIVATE bool isHostFunctionNonInline() const;
-
- static EncodedJSValue argumentsGetter(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
- static EncodedJSValue callerGetter(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
- static EncodedJSValue lengthGetter(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
- static EncodedJSValue nameGetter(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-
- WriteBarrier<ExecutableBase> m_executable;
- WriteBarrier<JSScope> m_scope;
- ObjectAllocationProfile m_allocationProfile;
- InlineWatchpointSet m_allocationProfileWatchpoint;
- };
+ friend class LLIntOffsetsExtractor;
+
+ static EncodedJSValue argumentsGetter(ExecState*, EncodedJSValue, PropertyName);
+ static EncodedJSValue callerGetter(ExecState*, EncodedJSValue, PropertyName);
+ static EncodedJSValue lengthGetter(ExecState*, EncodedJSValue, PropertyName);
+ static EncodedJSValue nameGetter(ExecState*, EncodedJSValue, PropertyName);
+
+ WriteBarrier<ExecutableBase> m_executable;
+ WriteBarrier<FunctionRareData> m_rareData;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSFunctionInlines.h b/Source/JavaScriptCore/runtime/JSFunctionInlines.h
index fe4e114ad..ef43d3266 100644
--- a/Source/JavaScriptCore/runtime/JSFunctionInlines.h
+++ b/Source/JavaScriptCore/runtime/JSFunctionInlines.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 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
@@ -31,14 +31,29 @@
namespace JSC {
-inline JSFunction::JSFunction(VM& vm, FunctionExecutable* executable, JSScope* scope)
- : Base(vm, scope->globalObject()->functionStructure())
+inline JSFunction* JSFunction::createWithInvalidatedReallocationWatchpoint(
+ VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+ ASSERT(executable->singletonFunction()->hasBeenInvalidated());
+ return createImpl(vm, executable, scope, scope->globalObject()->functionStructure());
+}
+
+inline JSFunction::JSFunction(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
+ : Base(vm, scope, structure)
, m_executable(vm, this, executable)
- , m_scope(vm, this, scope)
- , m_allocationProfileWatchpoint(ClearWatchpoint) // See comment in JSFunction.cpp concerning the reason for using ClearWatchpoint as opposed to IsWatched.
+ , m_rareData()
{
}
+#if ENABLE(WEBASSEMBLY)
+inline JSFunction::JSFunction(VM& vm, WebAssemblyExecutable* executable, JSScope* scope)
+ : Base(vm, scope, scope->globalObject()->functionStructure())
+ , m_executable(vm, this, executable)
+ , m_rareData()
+{
+}
+#endif
+
inline FunctionExecutable* JSFunction::jsExecutable() const
{
ASSERT(!isHostFunctionNonInline());
@@ -51,18 +66,50 @@ inline bool JSFunction::isHostFunction() const
return m_executable->isHostFunction();
}
+inline Intrinsic JSFunction::intrinsic() const
+{
+ return executable()->intrinsic();
+}
+
+inline bool JSFunction::isBuiltinFunction() const
+{
+#if ENABLE(WEBASSEMBLY)
+ if (m_executable->isWebAssemblyExecutable())
+ return false;
+#endif
+ return !isHostFunction() && jsExecutable()->isBuiltinFunction();
+}
+
+inline bool JSFunction::isHostOrBuiltinFunction() const
+{
+ return isHostFunction() || isBuiltinFunction();
+}
+
+inline bool JSFunction::isClassConstructorFunction() const
+{
+ return !isHostFunction() && jsExecutable()->isClassConstructorFunction();
+}
+
inline NativeFunction JSFunction::nativeFunction()
{
- ASSERT(isHostFunction());
+ ASSERT(isHostFunctionNonInline());
return static_cast<NativeExecutable*>(m_executable.get())->function();
}
inline NativeFunction JSFunction::nativeConstructor()
{
- ASSERT(isHostFunction());
+ ASSERT(isHostFunctionNonInline());
return static_cast<NativeExecutable*>(m_executable.get())->constructor();
}
+inline bool isHostFunction(JSValue value, NativeFunction nativeFunction)
+{
+ JSFunction* function = jsCast<JSFunction*>(getJSFunction(value));
+ if (!function || !function->isHostFunction())
+ return false;
+ return function->nativeFunction() == nativeFunction;
+}
+
} // namespace JSC
#endif // JSFunctionInlines_h
diff --git a/Source/JavaScriptCore/runtime/JSGeneratorFunction.cpp b/Source/JavaScriptCore/runtime/JSGeneratorFunction.cpp
new file mode 100644
index 000000000..34cbce02d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGeneratorFunction.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 "JSGeneratorFunction.h"
+
+#include "Error.h"
+#include "JSCInlines.h"
+#include "JSCJSValue.h"
+#include "JSFunction.h"
+#include "JSFunctionInlines.h"
+#include "JSObject.h"
+#include "PropertySlot.h"
+#include "VM.h"
+
+namespace JSC {
+
+const ClassInfo JSGeneratorFunction::s_info = { "GeneratorFunction", &Base::s_info, nullptr, CREATE_METHOD_TABLE(JSGeneratorFunction) };
+
+JSGeneratorFunction::JSGeneratorFunction(VM& vm, FunctionExecutable* executable, JSScope* scope)
+ : Base(vm, executable, scope, scope->globalObject()->generatorFunctionStructure())
+{
+}
+
+JSGeneratorFunction* JSGeneratorFunction::createImpl(VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+ JSGeneratorFunction* generatorFunction = new (NotNull, allocateCell<JSGeneratorFunction>(vm.heap)) JSGeneratorFunction(vm, executable, scope);
+ ASSERT(generatorFunction->structure()->globalObject());
+ generatorFunction->finishCreation(vm);
+ return generatorFunction;
+}
+
+JSGeneratorFunction* JSGeneratorFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+ JSGeneratorFunction* generatorFunction = createImpl(vm, executable, scope);
+ executable->singletonFunction()->notifyWrite(vm, generatorFunction, "Allocating a generator function");
+ return generatorFunction;
+}
+
+JSGeneratorFunction* JSGeneratorFunction::createWithInvalidatedReallocationWatchpoint(VM& vm, FunctionExecutable* executable, JSScope* scope)
+{
+ return createImpl(vm, executable, scope);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGeneratorFunction.h b/Source/JavaScriptCore/runtime/JSGeneratorFunction.h
new file mode 100644
index 000000000..ff1072a52
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGeneratorFunction.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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.
+ */
+
+#ifndef JSGeneratorFunction_h
+#define JSGeneratorFunction_h
+
+#include "JSFunction.h"
+
+namespace JSC {
+
+class JSGlobalObject;
+class LLIntOffsetsExtractor;
+class LLIntDesiredOffsets;
+
+class JSGeneratorFunction : public JSFunction {
+ friend class JIT;
+#if ENABLE(DFG_JIT)
+ friend class DFG::SpeculativeJIT;
+ friend class DFG::JITCompiler;
+#endif
+ friend class VM;
+public:
+ typedef JSFunction Base;
+
+ enum class GeneratorResumeMode : int32_t {
+ NormalMode = 0,
+ ReturnMode = 1,
+ ThrowMode = 2
+ };
+
+ const static unsigned StructureFlags = Base::StructureFlags;
+
+ DECLARE_EXPORT_INFO;
+
+ static JSGeneratorFunction* create(VM&, FunctionExecutable*, JSScope*);
+ static JSGeneratorFunction* createWithInvalidatedReallocationWatchpoint(VM&, FunctionExecutable*, JSScope*);
+
+ static size_t allocationSize(size_t inlineCapacity)
+ {
+ ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
+ return sizeof(JSGeneratorFunction);
+ }
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ ASSERT(globalObject);
+ return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
+ }
+
+private:
+ JSGeneratorFunction(VM&, FunctionExecutable*, JSScope*);
+
+ static JSGeneratorFunction* createImpl(VM&, FunctionExecutable*, JSScope*);
+
+ friend class LLIntOffsetsExtractor;
+};
+
+} // namespace JSC
+
+#endif // JSGeneratorFunction_h
diff --git a/Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h b/Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h
index 895acbfab..bd437e4ad 100644
--- a/Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h
+++ b/Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h
@@ -87,6 +87,10 @@ template<typename Adaptor>
class JSGenericTypedArrayView : public JSArrayBufferView {
public:
typedef JSArrayBufferView Base;
+ typedef typename Adaptor::Type ElementType;
+
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetPropertyNames | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
+
static const unsigned elementSize = sizeof(typename Adaptor::Type);
protected:
@@ -104,11 +108,11 @@ public:
const typename Adaptor::Type* typedVector() const
{
- return static_cast<const typename Adaptor::Type*>(m_vector);
+ return bitwise_cast<const typename Adaptor::Type*>(vector());
}
typename Adaptor::Type* typedVector()
{
- return static_cast<typename Adaptor::Type*>(m_vector);
+ return bitwise_cast<typename Adaptor::Type*>(vector());
}
// These methods are meant to match indexed access methods that JSObject
@@ -154,15 +158,54 @@ public:
setIndexQuicklyToNativeValue(i, toNativeFromValue<Adaptor>(value));
}
- bool setIndexQuickly(ExecState* exec, unsigned i, JSValue jsValue)
+ bool setIndex(ExecState* exec, unsigned i, JSValue jsValue)
{
typename Adaptor::Type value = toNativeFromValue<Adaptor>(exec, jsValue);
if (exec->hadException())
return false;
+
+ if (i >= m_length)
+ return false;
+
setIndexQuicklyToNativeValue(i, value);
return true;
}
-
+
+ static ElementType toAdaptorNativeFromValue(ExecState* exec, JSValue jsValue) { return toNativeFromValue<Adaptor>(exec, jsValue); }
+
+ bool setRangeToValue(ExecState* exec, unsigned start, unsigned end, JSValue jsValue)
+ {
+ ASSERT(0 <= start && start <= end && end <= m_length);
+
+ typename Adaptor::Type value = toNativeFromValue<Adaptor>(exec, jsValue);
+ if (exec->hadException())
+ return false;
+
+ // We might want to do something faster here (e.g. SIMD) if this is too slow.
+ typename Adaptor::Type* array = typedVector();
+ for (unsigned i = start; i < end; ++i)
+ array[i] = value;
+
+ return true;
+ }
+
+ void sort()
+ {
+ switch (Adaptor::typeValue) {
+ case TypeFloat32:
+ sortFloat<int32_t>();
+ break;
+ case TypeFloat64:
+ sortFloat<int64_t>();
+ break;
+ default: {
+ ElementType* array = typedVector();
+ std::sort(array, array + m_length);
+ break;
+ }
+ }
+ }
+
bool canAccessRangeQuickly(unsigned offset, unsigned length)
{
return offset <= m_length
@@ -186,7 +229,7 @@ public:
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), NonArray);
+ return Structure::create(vm, globalObject, prototype, TypeInfo(typeForTypedArrayType(Adaptor::typeValue), StructureFlags), info(), NonArray);
}
static const ClassInfo s_info; // This is never accessed directly, since that would break linkage on some compilers.
@@ -224,8 +267,6 @@ public:
protected:
friend struct TypedArrayClassInfos;
-
- static const unsigned StructureFlags = OverridesGetPropertyNames | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | Base::StructureFlags;
static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
@@ -236,9 +277,9 @@ protected:
static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
- static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
-
+
+ static size_t estimatedSize(JSCell*);
static void visitChildren(JSCell*, SlotVisitor&);
static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
@@ -253,14 +294,72 @@ private:
bool setWithSpecificType(
ExecState*, JSGenericTypedArrayView<OtherAdaptor>*,
unsigned offset, unsigned length);
+
+ // The ECMA 6 spec states that floating point Typed Arrays should have the following ordering:
+ //
+ // -Inifinity < negative finite numbers < -0.0 < 0.0 < positive finite numbers < Infinity < NaN
+ // Note: regardless of the sign or exact representation of a NaN it is greater than all other values.
+ //
+ // An interesting fact about IEEE 754 floating point numbers is that have an adjacent representation
+ // i.e. for any finite floating point x there does not exist a finite floating point y such that
+ // ((float) ((int) x + 1)) > y > x (where int represents a signed bit integer with the same number
+ // of bits as float). Thus, if we have an array of floating points if we view it as an
+ // array of signed bit integers it will sort in the format we desire. Note, denormal
+ // numbers fit this property as they are floating point numbers with a exponent field of all
+ // zeros so they will be closer to the signed zeros than any normalized number.
+ //
+ // All the processors we support, however, use twos complement. Fortunately, if you compare a signed
+ // bit number as if it were twos complement the result will be correct assuming both numbers are not
+ // negative. e.g.
+ //
+ // - <=> - = reversed (-30 > -20 = true)
+ // + <=> + = ordered (30 > 20 = true)
+ // - <=> + = ordered (-30 > 20 = false)
+ // + <=> - = ordered (30 > -20 = true)
+ //
+ // For NaN, we normalize the NaN to a peticular representation; the sign bit is 0, all exponential bits
+ // are 1 and only the MSB of the mantissa is 1. So, NaN is recognized as the largest integral numbers.
+
+ void purifyArray()
+ {
+ ElementType* array = typedVector();
+ for (unsigned i = 0; i < m_length; i++)
+ array[i] = purifyNaN(array[i]);
+ }
+
+ template<typename IntegralType>
+ static bool ALWAYS_INLINE sortComparison(IntegralType a, IntegralType b)
+ {
+ if (a >= 0 || b >= 0)
+ return a < b;
+ return a > b;
+ }
+
+ template<typename IntegralType>
+ void sortFloat()
+ {
+ ASSERT(sizeof(IntegralType) == sizeof(ElementType));
+
+ // Since there might be another view that sets the bits of
+ // our floats to NaNs with negative sign bits we need to
+ // purify the array.
+ // We use a separate function here to avoid the strict aliasing rule.
+ // We could use a union but ASAN seems to frown upon that.
+ purifyArray();
+
+ IntegralType* array = reinterpret_cast_ptr<IntegralType*>(typedVector());
+ std::sort(array, array + m_length, sortComparison<IntegralType>);
+
+ }
+
};
template<typename Adaptor>
-inline PassRefPtr<typename Adaptor::ViewType> toNativeTypedView(JSValue value)
+inline RefPtr<typename Adaptor::ViewType> toNativeTypedView(JSValue value)
{
typename Adaptor::JSViewType* wrapper = jsDynamicCast<typename Adaptor::JSViewType*>(value);
if (!wrapper)
- return 0;
+ return nullptr;
return wrapper->typedImpl();
}
diff --git a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.h b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.h
index 3dffe3c23..5590df42e 100644
--- a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.h
+++ b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructor.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-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
@@ -37,11 +37,11 @@ public:
protected:
JSGenericTypedArrayViewConstructor(VM&, Structure*);
- void finishCreation(VM&, JSObject* prototype, const String& name);
+ void finishCreation(VM&, JSGlobalObject*, JSObject* prototype, const String& name, FunctionExecutable* privateAllocator);
public:
static JSGenericTypedArrayViewConstructor* create(
- VM&, Structure*, JSObject* prototype, const String& name);
+ VM&, JSGlobalObject*, Structure*, JSObject* prototype, const String& name, FunctionExecutable* privateAllocator);
DECLARE_INFO;
diff --git a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructorInlines.h b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructorInlines.h
index 2ddc29f71..e7592c0b0 100644
--- a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructorInlines.h
+++ b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewConstructorInlines.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -27,9 +27,13 @@
#define JSGenericTypedArrayViewConstructorInlines_h
#include "Error.h"
+#include "IteratorOperations.h"
#include "JSArrayBuffer.h"
+#include "JSCJSValueInlines.h"
+#include "JSDataView.h"
#include "JSGenericTypedArrayViewConstructor.h"
#include "JSGlobalObject.h"
+#include "StructureInlines.h"
namespace JSC {
@@ -40,24 +44,27 @@ JSGenericTypedArrayViewConstructor<ViewClass>::JSGenericTypedArrayViewConstructo
}
template<typename ViewClass>
-void JSGenericTypedArrayViewConstructor<ViewClass>::finishCreation(VM& vm, JSObject* prototype, const String& name)
+void JSGenericTypedArrayViewConstructor<ViewClass>::finishCreation(VM& vm, JSGlobalObject* globalObject, JSObject* prototype, const String& name, FunctionExecutable* privateAllocator)
{
Base::finishCreation(vm, name);
putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly);
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(3), DontEnum | DontDelete | ReadOnly);
putDirectWithoutTransition(vm, vm.propertyNames->BYTES_PER_ELEMENT, jsNumber(ViewClass::elementSize), DontEnum | ReadOnly | DontDelete);
+
+ if (privateAllocator)
+ putDirectBuiltinFunction(vm, globalObject, vm.propertyNames->allocateTypedArrayPrivateName, privateAllocator, DontEnum | DontDelete | ReadOnly);
}
template<typename ViewClass>
JSGenericTypedArrayViewConstructor<ViewClass>*
JSGenericTypedArrayViewConstructor<ViewClass>::create(
- VM& vm, Structure* structure, JSObject* prototype,
- const String& name)
+ VM& vm, JSGlobalObject* globalObject, Structure* structure, JSObject* prototype,
+ const String& name, FunctionExecutable* privateAllocator)
{
JSGenericTypedArrayViewConstructor* result =
new (NotNull, allocateCell<JSGenericTypedArrayViewConstructor>(vm.heap))
JSGenericTypedArrayViewConstructor(vm, structure);
- result->finishCreation(vm, prototype, name);
+ result->finishCreation(vm, globalObject, prototype, name, privateAllocator);
return result;
}
@@ -70,80 +77,175 @@ Structure* JSGenericTypedArrayViewConstructor<ViewClass>::createStructure(
}
template<typename ViewClass>
-static EncodedJSValue JSC_HOST_CALL constructGenericTypedArrayView(ExecState* exec)
+static JSObject* constructGenericTypedArrayViewFromIterator(ExecState* exec, Structure* structure, JSValue iterator)
{
- Structure* structure =
- asInternalFunction(exec->callee())->globalObject()->typedArrayStructure(
- ViewClass::TypedArrayStorageType);
-
- if (!exec->argumentCount()) {
- if (ViewClass::TypedArrayStorageType == TypeDataView)
- return throwVMError(exec, createTypeError(exec, "DataView constructor requires at least one argument."));
-
- // Even though the documentation doesn't say so, it's correct to say
- // "new Int8Array()". This is the same as allocating an array of zero
- // length.
- return JSValue::encode(ViewClass::create(exec, structure, 0));
+ if (!iterator.isObject())
+ return throwTypeError(exec, "Symbol.Iterator for the first argument did not return an object.");
+
+ MarkedArgumentBuffer storage;
+ while (true) {
+ JSValue next = iteratorStep(exec, iterator);
+ if (exec->hadException())
+ return nullptr;
+
+ if (next.isFalse())
+ break;
+
+ JSValue nextItem = iteratorValue(exec, next);
+ if (exec->hadException())
+ return nullptr;
+
+ storage.append(nextItem);
}
-
- if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(exec->argument(0))) {
+
+ ViewClass* result = ViewClass::createUninitialized(exec, structure, storage.size());
+ if (!result) {
+ ASSERT(exec->hadException());
+ return nullptr;
+ }
+
+ for (unsigned i = 0; i < storage.size(); ++i) {
+ if (!result->setIndex(exec, i, storage.at(i))) {
+ ASSERT(exec->hadException());
+ return nullptr;
+ }
+ }
+
+ return result;
+}
+
+template<typename ViewClass>
+static JSObject* constructGenericTypedArrayViewWithArguments(ExecState* exec, Structure* structure, EncodedJSValue firstArgument, unsigned offset, Optional<unsigned> lengthOpt)
+{
+ JSValue firstValue = JSValue::decode(firstArgument);
+ VM& vm = exec->vm();
+
+ if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(firstValue)) {
RefPtr<ArrayBuffer> buffer = jsBuffer->impl();
-
- unsigned offset = (exec->argumentCount() > 1) ? exec->uncheckedArgument(1).toUInt32(exec) : 0;
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
unsigned length = 0;
- if (exec->argumentCount() > 2) {
- length = exec->uncheckedArgument(2).toUInt32(exec);
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
- } else {
+
+ if (lengthOpt)
+ length = lengthOpt.value();
+ else {
if ((buffer->byteLength() - offset) % ViewClass::elementSize)
- return throwVMError(exec, createRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size"));
+ return throwRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size");
length = (buffer->byteLength() - offset) / ViewClass::elementSize;
+
}
- return JSValue::encode(ViewClass::create(exec, structure, buffer, offset, length));
+
+ return ViewClass::create(exec, structure, buffer, offset, length);
}
+ ASSERT(!offset && !lengthOpt);
if (ViewClass::TypedArrayStorageType == TypeDataView)
- return throwVMError(exec, createTypeError(exec, "Expected ArrayBuffer for the first argument."));
+ return throwTypeError(exec, "Expected ArrayBuffer for the first argument.");
// For everything but DataView, we allow construction with any of:
// - Another array. This creates a copy of the of that array.
// - An integer. This creates a new typed array of that length and zero-initializes it.
-
- if (JSObject* object = jsDynamicCast<JSObject*>(exec->uncheckedArgument(0))) {
- unsigned length =
- object->get(exec, exec->vm().propertyNames->length).toUInt32(exec);
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
+
+ if (JSObject* object = jsDynamicCast<JSObject*>(firstValue)) {
+ unsigned length;
+
+ if (isTypedView(object->classInfo()->typedArrayStorageType))
+ length = jsCast<JSArrayBufferView*>(object)->length();
+ else {
+ PropertySlot lengthSlot(object, PropertySlot::InternalMethodType::Get);
+ object->getPropertySlot(exec, vm.propertyNames->length, lengthSlot);
+
+ JSValue iteratorFunc = object->get(exec, vm.propertyNames->iteratorSymbol);
+ if (exec->hadException())
+ return nullptr;
+
+ // We would like not use the iterator as it is painfully slow. Fortunately, unless
+ // 1) The iterator is not a known iterator.
+ // 2) The base object does not have a length getter.
+ // 3) The base object might have indexed getters.
+ // it should not be observable that we do not use the iterator.
+
+ if (!iteratorFunc.isUndefined()
+ && (iteratorFunc != object->globalObject()->arrayProtoValuesFunction()
+ || lengthSlot.isAccessor() || lengthSlot.isCustom()
+ || hasAnyArrayStorage(object->indexingType()))) {
+
+ CallData callData;
+ CallType callType = getCallData(iteratorFunc, callData);
+ if (callType == CallTypeNone)
+ return throwTypeError(exec, "Symbol.Iterator for the first argument cannot be called.");
+
+ ArgList arguments;
+ JSValue iterator = call(exec, iteratorFunc, callType, callData, object, arguments);
+ if (exec->hadException())
+ return nullptr;
+
+ return constructGenericTypedArrayViewFromIterator<ViewClass>(exec, structure, iterator);
+ }
+
+ length = lengthSlot.isUnset() ? 0 : lengthSlot.getValue(exec, vm.propertyNames->length).toUInt32(exec);
+ if (exec->hadException())
+ return nullptr;
+ }
+
ViewClass* result = ViewClass::createUninitialized(exec, structure, length);
if (!result) {
ASSERT(exec->hadException());
- return JSValue::encode(jsUndefined());
+ return nullptr;
}
if (!result->set(exec, object, 0, length))
- return JSValue::encode(jsUndefined());
+ return nullptr;
- return JSValue::encode(result);
+ return result;
}
int length;
- if (exec->uncheckedArgument(0).isInt32())
- length = exec->uncheckedArgument(0).asInt32();
- else if (!exec->uncheckedArgument(0).isNumber())
- return throwVMError(exec, createTypeError(exec, "Invalid array length argument"));
+ if (firstValue.isInt32())
+ length = firstValue.asInt32();
+ else if (!firstValue.isNumber())
+ return throwTypeError(exec, "Invalid array length argument");
else {
- length = static_cast<int>(exec->uncheckedArgument(0).asNumber());
- if (length != exec->uncheckedArgument(0).asNumber())
- return throwVMError(exec, createTypeError(exec, "Invalid array length argument (fractional lengths not allowed)"));
+ length = static_cast<int>(firstValue.asNumber());
+ if (length != firstValue.asNumber())
+ return throwTypeError(exec, "Invalid array length argument (fractional lengths not allowed)");
}
if (length < 0)
- return throwVMError(exec, createRangeError(exec, "Requested length is negative"));
- return JSValue::encode(ViewClass::create(exec, structure, length));
+ return throwRangeError(exec, "Requested length is negative");
+ return ViewClass::create(exec, structure, length);
+}
+
+template<typename ViewClass>
+static EncodedJSValue JSC_HOST_CALL constructGenericTypedArrayView(ExecState* exec)
+{
+ Structure* structure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), asInternalFunction(exec->callee())->globalObject()->typedArrayStructure(ViewClass::TypedArrayStorageType));
+
+ size_t argCount = exec->argumentCount();
+
+ if (!argCount) {
+ if (ViewClass::TypedArrayStorageType == TypeDataView)
+ return throwVMError(exec, createTypeError(exec, "DataView constructor requires at least one argument."));
+
+ return JSValue::encode(ViewClass::create(exec, structure, 0));
+ }
+
+ JSValue firstValue = exec->uncheckedArgument(0);
+ unsigned offset = 0;
+ Optional<unsigned> length = Nullopt;
+ if (jsDynamicCast<JSArrayBuffer*>(firstValue) && argCount > 1) {
+ offset = exec->uncheckedArgument(1).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (argCount > 2) {
+ length = exec->uncheckedArgument(2).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ }
+
+ }
+
+ return JSValue::encode(constructGenericTypedArrayViewWithArguments<ViewClass>(exec, structure, JSValue::encode(firstValue), offset, length));
}
template<typename ViewClass>
@@ -154,10 +256,16 @@ ConstructType JSGenericTypedArrayViewConstructor<ViewClass>::getConstructData(JS
}
template<typename ViewClass>
+static EncodedJSValue JSC_HOST_CALL callGenericTypedArrayView(ExecState* exec)
+{
+ return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(exec, ViewClass::info()->className));
+}
+
+template<typename ViewClass>
CallType JSGenericTypedArrayViewConstructor<ViewClass>::getCallData(JSCell*, CallData& callData)
{
- callData.native.function = constructGenericTypedArrayView<ViewClass>;
- return CallTypeNone;
+ callData.native.function = callGenericTypedArrayView<ViewClass>;
+ return CallTypeHost;
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h
index 6db86274c..4dac83b59 100644
--- a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h
+++ b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -30,6 +30,7 @@
#include "DeferGC.h"
#include "Error.h"
#include "ExceptionHelpers.h"
+#include "JSArrayBuffer.h"
#include "JSGenericTypedArrayView.h"
#include "Reject.h"
#include "TypedArrays.h"
@@ -49,7 +50,7 @@ JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::create(
{
ConstructionContext context(exec->vm(), structure, length, sizeof(typename Adaptor::Type));
if (!context) {
- exec->vm().throwException(exec, createOutOfMemoryError(structure->globalObject()));
+ exec->vm().throwException(exec, createOutOfMemoryError(exec));
return 0;
}
JSGenericTypedArrayView* result =
@@ -67,7 +68,7 @@ JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::createUninit
exec->vm(), structure, length, sizeof(typename Adaptor::Type),
ConstructionContext::DontInitialize);
if (!context) {
- exec->vm().throwException(exec, createOutOfMemoryError(structure->globalObject()));
+ exec->vm().throwException(exec, createOutOfMemoryError(exec));
return 0;
}
JSGenericTypedArrayView* result =
@@ -83,10 +84,14 @@ JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::create(
unsigned byteOffset, unsigned length)
{
RefPtr<ArrayBuffer> buffer = passedBuffer;
- if (!ArrayBufferView::verifySubRange<typename Adaptor::Type>(buffer, byteOffset, length)) {
- exec->vm().throwException(
- exec, createRangeError(exec, "Byte offset and length out of range of buffer"));
- return 0;
+ size_t size = sizeof(typename Adaptor::Type);
+ if (!ArrayBufferView::verifySubRangeLength(buffer, byteOffset, length, size)) {
+ exec->vm().throwException(exec, createRangeError(exec, "Length out of range of buffer"));
+ return nullptr;
+ }
+ if (!ArrayBufferView::verifyByteOffsetAlignment(byteOffset, size)) {
+ exec->vm().throwException(exec, createRangeError(exec, "Byte offset is not aligned"));
+ return nullptr;
}
ConstructionContext context(exec->vm(), structure, buffer, byteOffset, length);
ASSERT(context);
@@ -266,7 +271,8 @@ bool JSGenericTypedArrayView<Adaptor>::set(
return false;
// We could optimize this case. But right now, we don't.
for (unsigned i = 0; i < length; ++i) {
- if (!setIndexQuickly(exec, offset + i, object->get(exec, i)))
+ JSValue value = object->get(exec, i);
+ if (!setIndex(exec, offset + i, value))
return false;
}
return true;
@@ -287,19 +293,10 @@ bool JSGenericTypedArrayView<Adaptor>::getOwnPropertySlot(
JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
- if (propertyName == exec->propertyNames().length) {
- slot.setValue(thisObject, DontDelete | ReadOnly, jsNumber(thisObject->length()));
- return true;
- }
-
- if (propertyName == exec->propertyNames().byteLength) {
- slot.setValue(thisObject, DontDelete | ReadOnly, jsNumber(thisObject->byteLength()));
- return true;
- }
-
- unsigned index = propertyName.asIndex();
- if (index != PropertyName::NotAnIndex && thisObject->canGetIndexQuickly(index)) {
- slot.setValue(thisObject, DontDelete | ReadOnly, thisObject->getIndexQuickly(index));
+
+ Optional<uint32_t> index = parseIndex(propertyName);
+ if (index && thisObject->canGetIndexQuickly(index.value())) {
+ slot.setValue(thisObject, DontDelete | ReadOnly, thisObject->getIndexQuickly(index.value()));
return true;
}
@@ -313,15 +310,8 @@ void JSGenericTypedArrayView<Adaptor>::put(
{
JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
- if (propertyName == exec->propertyNames().length) {
- // Firefox appears to simply ignore attempts to store to the length property.
- // Even in strict mode. I will do the same.
- return;
- }
-
- unsigned index = propertyName.asIndex();
- if (index != PropertyName::NotAnIndex) {
- putByIndex(thisObject, exec, index, value, slot.isStrictMode());
+ if (Optional<uint32_t> index = parseIndex(propertyName)) {
+ putByIndex(thisObject, exec, index.value(), value, slot.isStrictMode());
return;
}
@@ -338,8 +328,7 @@ bool JSGenericTypedArrayView<Adaptor>::defineOwnProperty(
// This is matching Firefox behavior. In particular, it rejects all attempts to
// defineOwnProperty for indexed properties on typed arrays, even if they're out
// of bounds.
- if (propertyName == exec->propertyNames().length
- || propertyName.asIndex() != PropertyName::NotAnIndex)
+ if (parseIndex(propertyName))
return reject(exec, shouldThrow, "Attempting to write to a read-only typed array property.");
return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
@@ -351,8 +340,7 @@ bool JSGenericTypedArrayView<Adaptor>::deleteProperty(
{
JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
- if (propertyName == exec->propertyNames().length
- || propertyName.asIndex() != PropertyName::NotAnIndex)
+ if (parseIndex(propertyName))
return false;
return Base::deleteProperty(thisObject, exec, propertyName);
@@ -389,13 +377,7 @@ void JSGenericTypedArrayView<Adaptor>::putByIndex(
return;
}
- if (!thisObject->canSetIndexQuickly(propertyName)) {
- // Yes, really. Firefox returns without throwing anything if you store beyond
- // the bounds.
- return;
- }
-
- thisObject->setIndexQuickly(exec, propertyName, value);
+ thisObject->setIndex(exec, propertyName, value);
}
template<typename Adaptor>
@@ -411,27 +393,30 @@ bool JSGenericTypedArrayView<Adaptor>::deletePropertyByIndex(
}
template<typename Adaptor>
-void JSGenericTypedArrayView<Adaptor>::getOwnNonIndexPropertyNames(
+void JSGenericTypedArrayView<Adaptor>::getOwnPropertyNames(
JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode)
{
JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
+
+ if (array.includeStringProperties()) {
+ for (unsigned i = 0; i < thisObject->m_length; ++i)
+ array.add(Identifier::from(exec, i));
+ }
- if (mode == IncludeDontEnumProperties)
- array.add(exec->propertyNames().length);
-
- Base::getOwnNonIndexPropertyNames(thisObject, exec, array, mode);
+ return Base::getOwnPropertyNames(object, exec, array, mode);
}
template<typename Adaptor>
-void JSGenericTypedArrayView<Adaptor>::getOwnPropertyNames(
- JSObject* object, ExecState* exec, PropertyNameArray& array, EnumerationMode mode)
+size_t JSGenericTypedArrayView<Adaptor>::estimatedSize(JSCell* cell)
{
- JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
-
- for (unsigned i = 0; i < thisObject->m_length; ++i)
- array.add(Identifier::from(exec, i));
-
- return Base::getOwnPropertyNames(object, exec, array, mode);
+ JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
+
+ if (thisObject->m_mode == OversizeTypedArray)
+ return Base::estimatedSize(thisObject) + thisObject->byteSize();
+ if (thisObject->m_mode == FastTypedArray && thisObject->m_vector)
+ return Base::estimatedSize(thisObject) + thisObject->byteSize();
+
+ return Base::estimatedSize(thisObject);
}
template<typename Adaptor>
@@ -442,16 +427,17 @@ void JSGenericTypedArrayView<Adaptor>::visitChildren(JSCell* cell, SlotVisitor&
switch (thisObject->m_mode) {
case FastTypedArray: {
if (thisObject->m_vector)
- visitor.copyLater(thisObject, TypedArrayVectorCopyToken, thisObject->m_vector, thisObject->byteSize());
+ visitor.copyLater(thisObject, TypedArrayVectorCopyToken, thisObject->m_vector.getWithoutBarrier(), thisObject->byteSize());
break;
}
case OversizeTypedArray: {
- visitor.reportExtraMemoryUsage(thisObject, thisObject->byteSize());
+ visitor.reportExtraMemoryVisited(thisObject->byteSize());
break;
}
case WastefulTypedArray:
+ RELEASE_ASSERT(thisObject->existingBufferInButterfly());
break;
case DataViewMode:
@@ -469,12 +455,12 @@ void JSGenericTypedArrayView<Adaptor>::copyBackingStore(
JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(cell);
if (token == TypedArrayVectorCopyToken
- && visitor.checkIfShouldCopy(thisObject->m_vector)) {
+ && visitor.checkIfShouldCopy(thisObject->m_vector.getWithoutBarrier())) {
ASSERT(thisObject->m_vector);
- void* oldVector = thisObject->m_vector;
+ void* oldVector = thisObject->vector();
void* newVector = visitor.allocateNewSpace(thisObject->byteSize());
memcpy(newVector, oldVector, thisObject->byteSize());
- thisObject->m_vector = newVector;
+ thisObject->m_vector.setWithoutBarrier(static_cast<char*>(newVector));
visitor.didCopy(oldVector, thisObject->byteSize());
}
@@ -509,9 +495,10 @@ ArrayBuffer* JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory(JSArrayBuf
&& !thisObject->butterfly() && size >= sizeof(IndexingHeader)) {
ASSERT(thisObject->m_vector);
// Reuse already allocated memory if at all possible.
- thisObject->m_butterfly.setWithoutWriteBarrier(
- static_cast<IndexingHeader*>(thisObject->m_vector)->butterfly());
+ thisObject->m_butterfly.setWithoutBarrier(
+ bitwise_cast<IndexingHeader*>(thisObject->vector())->butterfly());
} else {
+ RELEASE_ASSERT(!thisObject->hasIndexingHeader());
VM& vm = *heap->vm();
thisObject->m_butterfly.set(vm, thisObject, Butterfly::createOrGrowArrayRight(
thisObject->butterfly(), vm, thisObject, thisObject->structure(),
@@ -522,14 +509,14 @@ ArrayBuffer* JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory(JSArrayBuf
switch (thisObject->m_mode) {
case FastTypedArray:
- buffer = ArrayBuffer::create(thisObject->m_vector, thisObject->byteLength());
+ buffer = ArrayBuffer::create(thisObject->vector(), thisObject->byteLength());
break;
case OversizeTypedArray:
// FIXME: consider doing something like "subtracting" from extra memory
// cost, since right now this case will cause the GC to think that we reallocated
// the whole buffer.
- buffer = ArrayBuffer::createAdopted(thisObject->m_vector, thisObject->byteLength());
+ buffer = ArrayBuffer::createAdopted(thisObject->vector(), thisObject->byteLength());
break;
default:
@@ -538,7 +525,7 @@ ArrayBuffer* JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory(JSArrayBuf
}
thisObject->butterfly()->indexingHeader()->setArrayBuffer(buffer.get());
- thisObject->m_vector = buffer->data();
+ thisObject->m_vector.setWithoutBarrier(static_cast<char*>(buffer->data()));
thisObject->m_mode = WastefulTypedArray;
heap->addReference(thisObject, buffer.get());
diff --git a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeFunctions.h b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeFunctions.h
new file mode 100644
index 000000000..36c0409d7
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeFunctions.h
@@ -0,0 +1,432 @@
+/*
+ * 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.
+ */
+
+#ifndef JSGenericTypedArrayViewPrototypeFunctions_h
+#define JSGenericTypedArrayViewPrototypeFunctions_h
+
+#include "ArrayPrototype.h"
+#include "Error.h"
+#include "ExceptionHelpers.h"
+#include "JSArrayBufferViewInlines.h"
+#include "JSArrayIterator.h"
+#include "JSCBuiltins.h"
+#include "JSCJSValueInlines.h"
+#include "JSFunction.h"
+#include "JSGenericTypedArrayViewInlines.h"
+#include "JSGenericTypedArrayViewPrototypeInlines.h"
+#include "JSStringJoiner.h"
+#include "StructureInlines.h"
+#include "TypedArrayAdaptors.h"
+#include <wtf/StdLibExtras.h>
+
+namespace JSC {
+
+static const char* typedArrayBufferHasBeenDetachedErrorMessage = "Underlying ArrayBuffer has been detached from the view";
+
+inline unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0)
+{
+ JSValue value = exec->argument(argument);
+ if (value.isUndefined())
+ return undefinedValue;
+
+ double indexDouble = value.toInteger(exec);
+ if (indexDouble < 0) {
+ indexDouble += length;
+ return indexDouble < 0 ? 0 : static_cast<unsigned>(indexDouble);
+ }
+ return indexDouble > length ? length : static_cast<unsigned>(indexDouble);
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncSet(ExecState* exec)
+{
+ // 22.2.3.22
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+
+ if (!exec->argumentCount())
+ return throwVMError(exec, createTypeError(exec, "Expected at least one argument"));
+
+ unsigned offset;
+ if (exec->argumentCount() >= 2) {
+ double offsetNumber = exec->uncheckedArgument(1).toInteger(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (offsetNumber < 0)
+ return throwVMRangeError(exec, "Offset should not be negative");
+ offset = static_cast<unsigned>(std::min(offsetNumber, static_cast<double>(std::numeric_limits<unsigned>::max())));
+ } else
+ offset = 0;
+
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ JSObject* sourceArray = jsDynamicCast<JSObject*>(exec->uncheckedArgument(0));
+ if (!sourceArray)
+ return throwVMError(exec, createTypeError(exec, "First argument should be an object"));
+
+ unsigned length;
+ if (isTypedView(sourceArray->classInfo()->typedArrayStorageType)) {
+ JSArrayBufferView* sourceView = jsCast<JSArrayBufferView*>(sourceArray);
+ if (sourceView->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ length = jsCast<JSArrayBufferView*>(sourceArray)->length();
+ } else
+ length = sourceArray->get(exec, exec->vm().propertyNames->length).toUInt32(exec);
+
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ thisObject->set(exec, sourceArray, offset, length);
+ return JSValue::encode(jsUndefined());
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncEntries(ExecState* exec)
+{
+ // 22.2.3.6
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateKeyValue, thisObject));
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncCopyWithin(ExecState* exec)
+{
+ // 22.2.3.5
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ if (exec->argumentCount() < 2)
+ return throwVMError(exec, createTypeError(exec, "Expected at least two arguments"));
+
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ long length = thisObject->length();
+ long to = argumentClampedIndexFromStartOrEnd(exec, 0, length);
+ long from = argumentClampedIndexFromStartOrEnd(exec, 1, length);
+ long final = argumentClampedIndexFromStartOrEnd(exec, 2, length, length);
+
+ if (final < from)
+ return JSValue::encode(exec->thisValue());
+
+ long count = std::min(length - std::max(to, from), final - from);
+
+ typename ViewClass::ElementType* array = thisObject->typedVector();
+ memmove(array + to, array + from, count * thisObject->elementSize);
+
+ return JSValue::encode(exec->thisValue());
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncFill(ExecState* exec)
+{
+ // 22.2.3.8
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ JSValue valueToInsert = exec->argument(0);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ unsigned length = thisObject->length();
+ unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 1, length);
+ unsigned end = argumentClampedIndexFromStartOrEnd(exec, 2, length, length);
+
+ if (end < begin)
+ return JSValue::encode(exec->thisValue());
+
+ if (!thisObject->setRangeToValue(exec, begin, end, valueToInsert))
+ return JSValue::encode(jsUndefined());
+
+ return JSValue::encode(exec->thisValue());
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncIndexOf(ExecState* exec)
+{
+ // 22.2.3.13
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ if (!exec->argumentCount())
+ return throwVMError(exec, createTypeError(exec, "Expected at least one argument"));
+
+ unsigned length = thisObject->length();
+
+ JSValue valueToFind = exec->argument(0);
+ unsigned index = argumentClampedIndexFromStartOrEnd(exec, 1, length);
+
+ typename ViewClass::ElementType* array = thisObject->typedVector();
+ typename ViewClass::ElementType target = ViewClass::toAdaptorNativeFromValue(exec, valueToFind);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ for (; index < length; ++index) {
+ if (array[index] == target)
+ return JSValue::encode(jsNumber(index));
+ }
+
+ return JSValue::encode(jsNumber(-1));
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncJoin(ExecState* exec)
+{
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ // 22.2.3.14
+ auto joinWithSeparator = [&] (StringView separator) -> EncodedJSValue {
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+ unsigned length = thisObject->length();
+
+ JSStringJoiner joiner(*exec, separator, length);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ for (unsigned i = 0; i < length; i++) {
+ joiner.append(*exec, thisObject->getIndexQuickly(i));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ }
+ return JSValue::encode(joiner.join(*exec));
+ };
+
+ JSValue separatorValue = exec->argument(0);
+ if (separatorValue.isUndefined()) {
+ const LChar* comma = reinterpret_cast<const LChar*>(",");
+ return joinWithSeparator({ comma, 1 });
+ }
+
+ JSString* separatorString = separatorValue.toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ return joinWithSeparator(separatorString->view(exec).get());
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncKeys(ExecState* exec)
+{
+ // 22.2.3.15
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateKey, thisObject));
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncLastIndexOf(ExecState* exec)
+{
+ // 22.2.3.16
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ if (!exec->argumentCount())
+ return throwVMError(exec, createTypeError(exec, "Expected at least one argument"));
+
+ unsigned length = thisObject->length();
+
+ JSValue valueToFind = exec->argument(0);
+
+ int 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<unsigned>(fromDouble);
+ }
+
+ typename ViewClass::ElementType* array = thisObject->typedVector();
+ typename ViewClass::ElementType target = ViewClass::toAdaptorNativeFromValue(exec, valueToFind);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ for (; index >= 0; --index) {
+ if (array[index] == target)
+ return JSValue::encode(jsNumber(index));
+ }
+
+ return JSValue::encode(jsNumber(-1));
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoGetterFuncLength(ExecState* exec)
+{
+ // 22.2.3.17
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+
+ return JSValue::encode(jsNumber(thisObject->length()));
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoGetterFuncByteLength(ExecState* exec)
+{
+ // 22.2.3.2
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+
+ return JSValue::encode(jsNumber(thisObject->byteLength()));
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoGetterFuncByteOffset(ExecState* exec)
+{
+ // 22.2.3.3
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+
+ return JSValue::encode(jsNumber(thisObject->byteOffset()));
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncReverse(ExecState* exec)
+{
+ // 22.2.3.21
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ typename ViewClass::ElementType* array = thisObject->typedVector();
+ std::reverse(array, array + thisObject->length());
+
+ return JSValue::encode(thisObject);
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewPrivateFuncSort(ExecState* exec)
+{
+ // 22.2.3.25
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->argument(0));
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ thisObject->sort();
+
+ return JSValue::encode(thisObject);
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncSlice(ExecState* exec)
+{
+ // 22.2.3.26
+ JSFunction* callee = jsCast<JSFunction*>(exec->callee());
+
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ if (!exec->argumentCount())
+ return throwVMError(exec, createTypeError(exec, "Expected at least one argument"));
+
+ unsigned thisLength = thisObject->length();
+
+ unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, thisLength);
+ unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, thisLength, thisLength);
+
+ // Clamp end to begin.
+ end = std::max(begin, end);
+
+ ASSERT(end >= begin);
+ unsigned length = end - begin;
+
+ typename ViewClass::ElementType* array = thisObject->typedVector();
+
+ Structure* structure =
+ callee->globalObject()->typedArrayStructure(ViewClass::TypedArrayStorageType);
+
+ ViewClass* result = ViewClass::createUninitialized(exec, structure, length);
+
+ // We can use memcpy since we know this a new buffer
+ memcpy(static_cast<void*>(result->typedVector()), static_cast<void*>(array + begin), length * thisObject->elementSize);
+
+ return JSValue::encode(result);
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncSubarray(ExecState* exec)
+{
+ // 22.2.3.23
+ JSFunction* callee = jsCast<JSFunction*>(exec->callee());
+
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ if (!exec->argumentCount())
+ return throwVMError(exec, createTypeError(exec, "Expected at least one argument"));
+
+ // Get the length here; later assert that the length didn't change.
+ unsigned thisLength = thisObject->length();
+
+ unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, thisLength);
+ unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, thisLength, thisLength);
+
+ // Clamp end to begin.
+ end = std::max(begin, end);
+
+ ASSERT(end >= begin);
+ unsigned offset = begin;
+ unsigned length = end - begin;
+
+ RefPtr<ArrayBuffer> arrayBuffer = thisObject->buffer();
+ RELEASE_ASSERT(thisLength == thisObject->length());
+
+ Structure* structure =
+ callee->globalObject()->typedArrayStructure(ViewClass::TypedArrayStorageType);
+
+ ViewClass* result = ViewClass::create(
+ exec, structure, arrayBuffer,
+ thisObject->byteOffset() + offset * ViewClass::elementSize,
+ length);
+
+ return JSValue::encode(result);
+}
+
+template<typename ViewClass>
+EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncValues(ExecState* exec)
+{
+ // 22.2.3.29
+ ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, typedArrayBufferHasBeenDetachedErrorMessage);
+
+ return JSValue::encode(JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), ArrayIterateValue, thisObject));
+}
+
+} // namespace JSC
+
+#endif /* JSGenericTypedArrayViewPrototypeFunctions_h */
diff --git a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeInlines.h b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeInlines.h
index 459997a46..dab55bcd0 100644
--- a/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeInlines.h
+++ b/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeInlines.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-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
@@ -26,104 +26,10 @@
#ifndef JSGenericTypedArrayViewPrototypeInlines_h
#define JSGenericTypedArrayViewPrototypeInlines_h
-#include "Error.h"
-#include "ExceptionHelpers.h"
-#include "JSFunction.h"
#include "JSGenericTypedArrayViewPrototype.h"
-#include <wtf/StdLibExtras.h>
namespace JSC {
-
-template<typename ViewClass>
-EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncSet(ExecState* exec)
-{
- ViewClass* thisObject = jsDynamicCast<ViewClass*>(exec->thisValue());
- if (!thisObject)
- return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view"));
-
- if (!exec->argumentCount())
- return throwVMError(exec, createTypeError(exec, "Expected at least one argument"));
- JSObject* sourceArray = jsDynamicCast<JSObject*>(exec->uncheckedArgument(0));
- if (!sourceArray)
- return throwVMError(exec, createTypeError(exec, "First argument should be an object"));
-
- unsigned offset;
- if (exec->argumentCount() >= 2) {
- offset = exec->uncheckedArgument(1).toUInt32(exec);
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
- } else
- offset = 0;
-
- unsigned length = sourceArray->get(exec, exec->vm().propertyNames->length).toUInt32(exec);
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- thisObject->set(exec, sourceArray, offset, length);
- return JSValue::encode(jsUndefined());
-}
-
-template<typename ViewClass>
-EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoFuncSubarray(ExecState* exec)
-{
- JSFunction* callee = jsCast<JSFunction*>(exec->callee());
-
- ViewClass* thisObject = jsDynamicCast<ViewClass*>(exec->thisValue());
- if (!thisObject)
- return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view"));
-
- if (!exec->argumentCount())
- return throwVMError(exec, createTypeError(exec, "Expected at least one argument"));
-
- int32_t begin = exec->uncheckedArgument(0).toInt32(exec);
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- int32_t end;
- if (exec->argumentCount() >= 2) {
- end = exec->uncheckedArgument(1).toInt32(exec);
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
- } else
- end = thisObject->length();
-
- // Get the length here; later assert that the length didn't change.
- unsigned thisLength = thisObject->length();
-
- // Handle negative indices: -x => length - x
- if (begin < 0)
- begin = std::max(static_cast<int>(thisLength + begin), 0);
- if (end < 0)
- end = std::max(static_cast<int>(thisLength + end), 0);
-
- // Clamp the indices to the bounds of the array.
- ASSERT(begin >= 0);
- ASSERT(end >= 0);
- begin = std::min(begin, static_cast<int32_t>(thisLength));
- end = std::min(end, static_cast<int32_t>(thisLength));
-
- // Clamp end to begin.
- end = std::max(begin, end);
-
- ASSERT(end >= begin);
- unsigned offset = begin;
- unsigned length = end - begin;
-
- RefPtr<ArrayBuffer> arrayBuffer = thisObject->buffer();
- RELEASE_ASSERT(thisLength == thisObject->length());
-
- Structure* structure =
- callee->globalObject()->typedArrayStructure(ViewClass::TypedArrayStorageType);
-
- ViewClass* result = ViewClass::create(
- exec, structure, arrayBuffer,
- thisObject->byteOffset() + offset * ViewClass::elementSize,
- length);
-
- return JSValue::encode(result);
-}
-
template<typename ViewClass>
JSGenericTypedArrayViewPrototype<ViewClass>::JSGenericTypedArrayViewPrototype(VM& vm, Structure* structure)
: Base(vm, structure)
@@ -132,15 +38,14 @@ JSGenericTypedArrayViewPrototype<ViewClass>::JSGenericTypedArrayViewPrototype(VM
template<typename ViewClass>
void JSGenericTypedArrayViewPrototype<ViewClass>::finishCreation(
- VM& vm, JSGlobalObject* globalObject)
+ VM& vm, JSGlobalObject*)
{
Base::finishCreation(vm);
ASSERT(inherits(info()));
-
- JSC_NATIVE_FUNCTION(vm.propertyNames->set, genericTypedArrayViewProtoFuncSet<ViewClass>, DontEnum, 2);
- JSC_NATIVE_FUNCTION(vm.propertyNames->subarray, genericTypedArrayViewProtoFuncSubarray<ViewClass>, DontEnum, 2);
+
putDirect(vm, vm.propertyNames->BYTES_PER_ELEMENT, jsNumber(ViewClass::elementSize), DontEnum | ReadOnly | DontDelete);
+
}
template<typename ViewClass>
diff --git a/Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.cpp b/Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.cpp
new file mode 100644
index 000000000..6d176086e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "JSGlobalLexicalEnvironment.h"
+
+#include "JSCInlines.h"
+
+namespace JSC {
+
+const ClassInfo JSGlobalLexicalEnvironment::s_info = { "JSGlobalLexicalEnvironment", &Base::s_info, 0, CREATE_METHOD_TABLE(JSGlobalLexicalEnvironment) };
+
+bool JSGlobalLexicalEnvironment::getOwnPropertySlot(JSObject* object, ExecState*, PropertyName propertyName, PropertySlot& slot)
+{
+ JSGlobalLexicalEnvironment* thisObject = jsCast<JSGlobalLexicalEnvironment*>(object);
+ return symbolTableGet(thisObject, propertyName, slot);
+}
+
+void JSGlobalLexicalEnvironment::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
+ JSGlobalLexicalEnvironment* thisObject = jsCast<JSGlobalLexicalEnvironment*>(cell);
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
+ bool alwaysThrowWhenAssigningToConstProperty = true;
+ bool ignoreConstAssignmentError = slot.isInitialization();
+ symbolTablePutTouchWatchpointSet(thisObject, exec, propertyName, value, alwaysThrowWhenAssigningToConstProperty, ignoreConstAssignmentError);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.h b/Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.h
new file mode 100644
index 000000000..643f095dd
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#ifndef JSGlobalLexicalEnvironment_h
+#define JSGlobalLexicalEnvironment_h
+
+#include "JSSegmentedVariableObject.h"
+
+namespace JSC {
+
+class JSGlobalLexicalEnvironment : public JSSegmentedVariableObject {
+
+public:
+ typedef JSSegmentedVariableObject Base;
+
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static JSGlobalLexicalEnvironment* create(VM& vm, Structure* structure, JSScope* parentScope)
+ {
+ JSGlobalLexicalEnvironment* result =
+ new (NotNull, allocateCell<JSGlobalLexicalEnvironment>(vm.heap)) JSGlobalLexicalEnvironment(vm, structure, parentScope);
+ result->finishCreation(vm);
+ result->symbolTable()->setScopeType(SymbolTable::ScopeType::GlobalLexicalScope);
+ return result;
+ }
+
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+
+ bool isEmpty() const { return !symbolTable()->size(); }
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject)
+ {
+ return Structure::create(vm, globalObject, jsNull(), TypeInfo(ClosureObjectType, StructureFlags), info());
+ }
+
+protected:
+ JSGlobalLexicalEnvironment(VM& vm, Structure* structure, JSScope* scope)
+ : Base(vm, structure, scope)
+ {
+ }
+};
+
+} // namespace JSC
+
+#endif // JSGlobalLexicalEnvironment_h
+
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
index 2c274c1a7..9e613a212 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2014, 2015 Apple Inc. All rights reserved.
* Copyright (C) 2008 Cameron Zwarich (cwzwarich@uwaterloo.ca)
*
* Redistribution and use in source and binary forms, with or without
@@ -7,13 +7,13 @@
* are met:
*
* 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
+ * 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.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * documentation and/or other materials provided with the distribution.
+ * 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.
+ * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -30,114 +30,156 @@
#include "config.h"
#include "JSGlobalObject.h"
-#include "Arguments.h"
-#include "ArgumentsIteratorConstructor.h"
-#include "ArgumentsIteratorPrototype.h"
#include "ArrayConstructor.h"
-#include "ArrayIteratorConstructor.h"
#include "ArrayIteratorPrototype.h"
#include "ArrayPrototype.h"
#include "BooleanConstructor.h"
#include "BooleanPrototype.h"
+#include "BuiltinNames.h"
+#include "ClonedArguments.h"
#include "CodeBlock.h"
#include "CodeCache.h"
+#include "ConsolePrototype.h"
#include "DateConstructor.h"
#include "DatePrototype.h"
#include "Debugger.h"
+#include "DebuggerScope.h"
+#include "DirectArguments.h"
#include "Error.h"
#include "ErrorConstructor.h"
#include "ErrorPrototype.h"
#include "FunctionConstructor.h"
#include "FunctionPrototype.h"
+#include "GeneratorFunctionConstructor.h"
+#include "GeneratorFunctionPrototype.h"
+#include "GeneratorPrototype.h"
#include "GetterSetter.h"
#include "HeapIterationScope.h"
+#include "InspectorInstrumentationObject.h"
#include "Interpreter.h"
+#include "IteratorPrototype.h"
#include "JSAPIWrapperObject.h"
-#include "JSActivation.h"
-#include "JSArgumentsIterator.h"
#include "JSArrayBuffer.h"
#include "JSArrayBufferConstructor.h"
#include "JSArrayBufferPrototype.h"
#include "JSArrayIterator.h"
#include "JSBoundFunction.h"
+#include "JSBoundSlotBaseFunction.h"
+#include "JSCInlines.h"
#include "JSCallbackConstructor.h"
#include "JSCallbackFunction.h"
#include "JSCallbackObject.h"
+#include "JSConsole.h"
#include "JSDataView.h"
#include "JSDataViewPrototype.h"
+#include "JSDollarVM.h"
+#include "JSDollarVMPrototype.h"
#include "JSFunction.h"
+#include "JSGeneratorFunction.h"
#include "JSGenericTypedArrayViewConstructorInlines.h"
#include "JSGenericTypedArrayViewInlines.h"
#include "JSGenericTypedArrayViewPrototypeInlines.h"
#include "JSGlobalObjectFunctions.h"
+#include "JSInternalPromise.h"
+#include "JSInternalPromiseConstructor.h"
+#include "JSInternalPromisePrototype.h"
+#include "JSJob.h"
+#include "JSLexicalEnvironment.h"
#include "JSLock.h"
#include "JSMap.h"
#include "JSMapIterator.h"
-#include "JSNameScope.h"
+#include "JSModuleEnvironment.h"
+#include "JSModuleNamespaceObject.h"
+#include "JSModuleRecord.h"
+#include "JSNativeStdFunction.h"
#include "JSONObject.h"
+#include "JSPromise.h"
+#include "JSPromiseConstructor.h"
+#include "JSPromisePrototype.h"
+#include "JSPropertyNameIterator.h"
#include "JSSet.h"
#include "JSSetIterator.h"
+#include "JSStringIterator.h"
+#include "JSTemplateRegistryKey.h"
#include "JSTypedArrayConstructors.h"
#include "JSTypedArrayPrototypes.h"
+#include "JSTypedArrayViewConstructor.h"
+#include "JSTypedArrayViewPrototype.h"
#include "JSTypedArrays.h"
+#include "JSWASMModule.h"
#include "JSWeakMap.h"
+#include "JSWeakSet.h"
#include "JSWithScope.h"
#include "LegacyProfiler.h"
#include "Lookup.h"
#include "MapConstructor.h"
-#include "MapIteratorConstructor.h"
#include "MapIteratorPrototype.h"
#include "MapPrototype.h"
#include "MathObject.h"
#include "Microtask.h"
-#include "NameConstructor.h"
-#include "NameInstance.h"
-#include "NamePrototype.h"
+#include "ModuleLoaderObject.h"
#include "NativeErrorConstructor.h"
#include "NativeErrorPrototype.h"
+#include "NullGetterFunction.h"
+#include "NullSetterFunction.h"
#include "NumberConstructor.h"
#include "NumberPrototype.h"
#include "ObjCCallbackFunction.h"
#include "ObjectConstructor.h"
#include "ObjectPrototype.h"
-#include "Operations.h"
#include "ParserError.h"
+#include "ProxyConstructor.h"
+#include "ProxyObject.h"
+#include "ReflectObject.h"
#include "RegExpConstructor.h"
#include "RegExpMatchesArray.h"
#include "RegExpObject.h"
#include "RegExpPrototype.h"
+#include "ScopedArguments.h"
#include "SetConstructor.h"
-#include "SetIteratorConstructor.h"
#include "SetIteratorPrototype.h"
#include "SetPrototype.h"
#include "StrictEvalActivation.h"
#include "StringConstructor.h"
+#include "StringIteratorPrototype.h"
#include "StringPrototype.h"
+#include "Symbol.h"
+#include "SymbolConstructor.h"
+#include "SymbolPrototype.h"
+#include "VariableWriteFireDetail.h"
+#include "WeakGCMapInlines.h"
#include "WeakMapConstructor.h"
#include "WeakMapPrototype.h"
+#include "WeakSetConstructor.h"
+#include "WeakSetPrototype.h"
-#if ENABLE(PROMISES)
-#include "JSPromise.h"
-#include "JSPromiseConstructor.h"
-#include "JSPromisePrototype.h"
-#endif // ENABLE(PROMISES)
+#if ENABLE(INTL)
+#include "IntlObject.h"
+#include <unicode/ucol.h>
+#include <unicode/udat.h>
+#include <unicode/unum.h>
+#endif // ENABLE(INTL)
#if ENABLE(REMOTE_INSPECTOR)
#include "JSGlobalObjectDebuggable.h"
-#include "RemoteInspector.h"
+#include "JSGlobalObjectInspectorController.h"
+#endif
+
+#if ENABLE(WEB_REPLAY)
+#include "EmptyInputCursor.h"
+#include "JSReplayInputs.h"
#endif
#include "JSGlobalObject.lut.h"
namespace JSC {
-const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &Base::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(JSGlobalObject) };
+const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &Base::s_info, &globalObjectTable, CREATE_METHOD_TABLE(JSGlobalObject) };
-const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled, 0, &shouldInterruptScriptBeforeTimeout };
+const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsLegacyProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, nullptr, &shouldInterruptScriptBeforeTimeout, nullptr, nullptr, nullptr, nullptr, nullptr };
/* Source for JSGlobalObject.lut.h
@begin globalObjectTable
- parseInt globalFuncParseInt DontEnum|Function 2
parseFloat globalFuncParseFloat DontEnum|Function 1
isNaN globalFuncIsNaN DontEnum|Function 1
isFinite globalFuncIsFinite DontEnum|Function 1
@@ -150,19 +192,52 @@ const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &all
@end
*/
+static EncodedJSValue JSC_HOST_CALL getTemplateObject(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ ASSERT(thisValue.inherits(JSTemplateRegistryKey::info()));
+ return JSValue::encode(exec->lexicalGlobalObject()->templateRegistry().getTemplateObject(exec, jsCast<JSTemplateRegistryKey*>(thisValue)->templateRegistryKey()));
+}
+
+
+static EncodedJSValue JSC_HOST_CALL enqueueJob(ExecState* exec)
+{
+ VM& vm = exec->vm();
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+
+ JSValue job = exec->argument(0);
+ JSValue arguments = exec->argument(1);
+ ASSERT(arguments.inherits(JSArray::info()));
+
+ globalObject->queueMicrotask(createJSJob(vm, job, jsCast<JSArray*>(arguments)));
+
+ return JSValue::encode(jsUndefined());
+}
+
JSGlobalObject::JSGlobalObject(VM& vm, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable)
: Base(vm, structure, 0)
+ , m_vm(vm)
+#if ENABLE(WEB_REPLAY)
+ , m_inputCursor(EmptyInputCursor::create())
+#endif
, m_masqueradesAsUndefinedWatchpoint(adoptRef(new WatchpointSet(IsWatched)))
, m_havingABadTimeWatchpoint(adoptRef(new WatchpointSet(IsWatched)))
, m_varInjectionWatchpoint(adoptRef(new WatchpointSet(IsWatched)))
, m_weakRandom(Options::forceWeakRandomSeed() ? Options::forcedWeakRandomSeed() : static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
+ , m_templateRegistry(vm)
, m_evalEnabled(true)
+ , m_runtimeFlags()
+ , m_consoleClient(nullptr)
, m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable)
{
}
JSGlobalObject::~JSGlobalObject()
{
+#if ENABLE(REMOTE_INSPECTOR)
+ m_inspectorController->globalObjectDestroyed();
+#endif
+
if (m_debugger)
m_debugger->detach(this, Debugger::GlobalObjectIsDestructing);
@@ -176,114 +251,71 @@ void JSGlobalObject::destroy(JSCell* cell)
}
void JSGlobalObject::setGlobalThis(VM& vm, JSObject* globalThis)
-{
+{
m_globalThis.set(vm, this, globalThis);
}
-void JSGlobalObject::init(JSObject* thisValue)
+void JSGlobalObject::init(VM& vm)
{
- ASSERT(vm().currentThreadIsHoldingAPILock());
+ ASSERT(vm.currentThreadIsHoldingAPILock());
- setGlobalThis(vm(), thisValue);
- JSGlobalObject::globalExec()->init(0, 0, this, CallFrame::noCaller(), 0, 0);
+ JSGlobalObject::globalExec()->init(0, 0, CallFrame::noCaller(), 0, 0);
m_debugger = 0;
#if ENABLE(REMOTE_INSPECTOR)
+ m_inspectorController = std::make_unique<Inspector::JSGlobalObjectInspectorController>(*this);
m_inspectorDebuggable = std::make_unique<JSGlobalObjectDebuggable>(*this);
m_inspectorDebuggable->init();
- m_inspectorDebuggable->setRemoteDebuggingAllowed(true);
+ m_consoleClient = m_inspectorController->consoleClient();
#endif
- reset(prototype());
-}
-
-void JSGlobalObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
-{
- JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell);
- ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
-
- if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode()))
- return;
- Base::put(thisObject, exec, propertyName, value, slot);
-}
-
-bool JSGlobalObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
-{
- JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object);
- PropertySlot slot(thisObject);
- // silently ignore attempts to add accessors aliasing vars.
- if (descriptor.isAccessorDescriptor() && symbolTableGet(thisObject, propertyName, slot))
- return false;
- return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
-}
-
-JSGlobalObject::NewGlobalVar JSGlobalObject::addGlobalVar(const Identifier& ident, ConstantMode constantMode)
-{
- ConcurrentJITLocker locker(symbolTable()->m_lock);
- int index = symbolTable()->size(locker);
- SymbolTableEntry newEntry(index, (constantMode == IsConstant) ? ReadOnly : 0);
- if (constantMode == IsVariable)
- newEntry.prepareToWatch();
- SymbolTable::Map::AddResult result = symbolTable()->add(locker, ident.impl(), newEntry);
- if (result.isNewEntry)
- addRegisters(1);
- else
- index = result.iterator->value.getIndex();
- NewGlobalVar var;
- var.registerNumber = index;
- var.set = result.iterator->value.watchpointSet();
- return var;
-}
-
-void JSGlobalObject::addFunction(ExecState* exec, const Identifier& propertyName, JSValue value)
-{
- removeDirect(exec->vm(), propertyName); // Newly declared functions overwrite existing properties.
- NewGlobalVar var = addGlobalVar(propertyName, IsVariable);
- registerAt(var.registerNumber).set(exec->vm(), this, value);
- if (var.set)
- var.set->notifyWrite(value);
-}
-
-static inline JSObject* lastInPrototypeChain(JSObject* object)
-{
- JSObject* o = object;
- while (o->prototype().isObject())
- o = asObject(o->prototype());
- return o;
-}
-
-void JSGlobalObject::reset(JSValue prototype)
-{
ExecState* exec = JSGlobalObject::globalExec();
- VM& vm = exec->vm();
m_functionPrototype.set(vm, this, FunctionPrototype::create(vm, FunctionPrototype::createStructure(vm, this, jsNull()))); // The real prototype will be set once ObjectPrototype is created.
+ m_calleeStructure.set(vm, this, JSCallee::createStructure(vm, this, jsNull()));
+
+ m_globalLexicalEnvironment.set(vm, this, JSGlobalLexicalEnvironment::create(vm, JSGlobalLexicalEnvironment::createStructure(vm, this), this));
+ // Need to create the callee structure (above) before creating the callee.
+ m_globalCallee.set(vm, this, JSCallee::create(vm, this, globalScope()));
+ exec->setCallee(m_globalCallee.get());
+
m_functionStructure.set(vm, this, JSFunction::createStructure(vm, this, m_functionPrototype.get()));
+ m_boundSlotBaseFunctionStructure.set(vm, this, JSBoundSlotBaseFunction::createStructure(vm, this, m_functionPrototype.get()));
m_boundFunctionStructure.set(vm, this, JSBoundFunction::createStructure(vm, this, m_functionPrototype.get()));
- m_namedFunctionStructure.set(vm, this, Structure::addPropertyTransition(vm, m_functionStructure.get(), vm.propertyNames->name, DontDelete | ReadOnly | DontEnum, 0, m_functionNameOffset));
+ m_nativeStdFunctionStructure.set(vm, this, JSNativeStdFunction::createStructure(vm, this, m_functionPrototype.get()));
+ m_namedFunctionStructure.set(vm, this, Structure::addPropertyTransition(vm, m_functionStructure.get(), vm.propertyNames->name, DontDelete | ReadOnly | DontEnum, m_functionNameOffset));
m_internalFunctionStructure.set(vm, this, InternalFunction::createStructure(vm, this, m_functionPrototype.get()));
JSFunction* callFunction = 0;
JSFunction* applyFunction = 0;
- m_functionPrototype->addFunctionProperties(exec, this, &callFunction, &applyFunction);
+ JSFunction* hasInstanceSymbolFunction = 0;
+ m_functionPrototype->addFunctionProperties(exec, this, &callFunction, &applyFunction, &hasInstanceSymbolFunction);
m_callFunction.set(vm, this, callFunction);
m_applyFunction.set(vm, this, applyFunction);
+ m_arrayProtoValuesFunction.set(vm, this, JSFunction::create(vm, this, 0, vm.propertyNames->values.string(), arrayProtoFuncValues));
+ m_initializePromiseFunction.set(vm, this, JSFunction::createBuiltinFunction(vm, promiseOperationsInitializePromiseCodeGenerator(vm), this));
+ m_newPromiseCapabilityFunction.set(vm, this, JSFunction::createBuiltinFunction(vm, promiseOperationsNewPromiseCapabilityCodeGenerator(vm), this));
+ m_functionProtoHasInstanceSymbolFunction.set(vm, this, hasInstanceSymbolFunction);
+ m_nullGetterFunction.set(vm, this, NullGetterFunction::create(vm, NullGetterFunction::createStructure(vm, this, m_functionPrototype.get())));
+ m_nullSetterFunction.set(vm, this, NullSetterFunction::create(vm, NullSetterFunction::createStructure(vm, this, m_functionPrototype.get())));
m_objectPrototype.set(vm, this, ObjectPrototype::create(vm, this, ObjectPrototype::createStructure(vm, this, jsNull())));
- GetterSetter* protoAccessor = GetterSetter::create(vm);
- protoAccessor->setGetter(vm, JSFunction::create(vm, this, 0, String(), globalFuncProtoGetter));
- protoAccessor->setSetter(vm, JSFunction::create(vm, this, 0, String(), globalFuncProtoSetter));
+ GetterSetter* protoAccessor = GetterSetter::create(vm, this);
+ protoAccessor->setGetter(vm, this, JSFunction::create(vm, this, 0, String(), globalFuncProtoGetter));
+ protoAccessor->setSetter(vm, this, JSFunction::create(vm, this, 0, String(), globalFuncProtoSetter));
m_objectPrototype->putDirectNonIndexAccessor(vm, vm.propertyNames->underscoreProto, protoAccessor, Accessor | DontEnum);
m_functionPrototype->structure()->setPrototypeWithoutTransition(vm, m_objectPrototype.get());
-
- m_typedArrays[toIndex(TypeInt8)].prototype.set(vm, this, JSInt8ArrayPrototype::create(vm, this, JSInt8ArrayPrototype::createStructure(vm, this, m_objectPrototype.get())));
- m_typedArrays[toIndex(TypeInt16)].prototype.set(vm, this, JSInt16ArrayPrototype::create(vm, this, JSInt16ArrayPrototype::createStructure(vm, this, m_objectPrototype.get())));
- m_typedArrays[toIndex(TypeInt32)].prototype.set(vm, this, JSInt32ArrayPrototype::create(vm, this, JSInt32ArrayPrototype::createStructure(vm, this, m_objectPrototype.get())));
- m_typedArrays[toIndex(TypeUint8)].prototype.set(vm, this, JSUint8ArrayPrototype::create(vm, this, JSUint8ArrayPrototype::createStructure(vm, this, m_objectPrototype.get())));
- m_typedArrays[toIndex(TypeUint8Clamped)].prototype.set(vm, this, JSUint8ClampedArrayPrototype::create(vm, this, JSUint8ClampedArrayPrototype::createStructure(vm, this, m_objectPrototype.get())));
- m_typedArrays[toIndex(TypeUint16)].prototype.set(vm, this, JSUint16ArrayPrototype::create(vm, this, JSUint16ArrayPrototype::createStructure(vm, this, m_objectPrototype.get())));
- m_typedArrays[toIndex(TypeUint32)].prototype.set(vm, this, JSUint32ArrayPrototype::create(vm, this, JSUint32ArrayPrototype::createStructure(vm, this, m_objectPrototype.get())));
- m_typedArrays[toIndex(TypeFloat32)].prototype.set(vm, this, JSFloat32ArrayPrototype::create(vm, this, JSFloat32ArrayPrototype::createStructure(vm, this, m_objectPrototype.get())));
- m_typedArrays[toIndex(TypeFloat64)].prototype.set(vm, this, JSFloat64ArrayPrototype::create(vm, this, JSFloat64ArrayPrototype::createStructure(vm, this, m_objectPrototype.get())));
+
+ JSTypedArrayViewPrototype* typedArrayProto = JSTypedArrayViewPrototype::create(vm, this, JSTypedArrayViewPrototype::createStructure(vm, this, m_objectPrototype.get()));
+
+ m_typedArrays[toIndex(TypeInt8)].prototype.set(vm, this, JSInt8ArrayPrototype::create(vm, this, JSInt8ArrayPrototype::createStructure(vm, this, typedArrayProto)));
+ m_typedArrays[toIndex(TypeInt16)].prototype.set(vm, this, JSInt16ArrayPrototype::create(vm, this, JSInt16ArrayPrototype::createStructure(vm, this, typedArrayProto)));
+ m_typedArrays[toIndex(TypeInt32)].prototype.set(vm, this, JSInt32ArrayPrototype::create(vm, this, JSInt32ArrayPrototype::createStructure(vm, this, typedArrayProto)));
+ m_typedArrays[toIndex(TypeUint8)].prototype.set(vm, this, JSUint8ArrayPrototype::create(vm, this, JSUint8ArrayPrototype::createStructure(vm, this, typedArrayProto)));
+ m_typedArrays[toIndex(TypeUint8Clamped)].prototype.set(vm, this, JSUint8ClampedArrayPrototype::create(vm, this, JSUint8ClampedArrayPrototype::createStructure(vm, this, typedArrayProto)));
+ m_typedArrays[toIndex(TypeUint16)].prototype.set(vm, this, JSUint16ArrayPrototype::create(vm, this, JSUint16ArrayPrototype::createStructure(vm, this, typedArrayProto)));
+ m_typedArrays[toIndex(TypeUint32)].prototype.set(vm, this, JSUint32ArrayPrototype::create(vm, this, JSUint32ArrayPrototype::createStructure(vm, this, typedArrayProto)));
+ m_typedArrays[toIndex(TypeFloat32)].prototype.set(vm, this, JSFloat32ArrayPrototype::create(vm, this, JSFloat32ArrayPrototype::createStructure(vm, this, typedArrayProto)));
+ m_typedArrays[toIndex(TypeFloat64)].prototype.set(vm, this, JSFloat64ArrayPrototype::create(vm, this, JSFloat64ArrayPrototype::createStructure(vm, this, typedArrayProto)));
m_typedArrays[toIndex(TypeDataView)].prototype.set(vm, this, JSDataViewPrototype::create(vm, JSDataViewPrototype::createStructure(vm, this, m_objectPrototype.get())));
m_typedArrays[toIndex(TypeInt8)].structure.set(vm, this, JSInt8Array::createStructure(vm, this, m_typedArrays[toIndex(TypeInt8)].prototype.get()));
@@ -296,23 +328,27 @@ void JSGlobalObject::reset(JSValue prototype)
m_typedArrays[toIndex(TypeFloat32)].structure.set(vm, this, JSFloat32Array::createStructure(vm, this, m_typedArrays[toIndex(TypeFloat32)].prototype.get()));
m_typedArrays[toIndex(TypeFloat64)].structure.set(vm, this, JSFloat64Array::createStructure(vm, this, m_typedArrays[toIndex(TypeFloat64)].prototype.get()));
m_typedArrays[toIndex(TypeDataView)].structure.set(vm, this, JSDataView::createStructure(vm, this, m_typedArrays[toIndex(TypeDataView)].prototype.get()));
-
- m_nameScopeStructure.set(vm, this, JSNameScope::createStructure(vm, this, jsNull()));
- m_activationStructure.set(vm, this, JSActivation::createStructure(vm, this, jsNull()));
+
+ m_lexicalEnvironmentStructure.set(vm, this, JSLexicalEnvironment::createStructure(vm, this));
+ m_moduleEnvironmentStructure.set(vm, this, JSModuleEnvironment::createStructure(vm, this));
m_strictEvalActivationStructure.set(vm, this, StrictEvalActivation::createStructure(vm, this, jsNull()));
+ m_debuggerScopeStructure.set(m_vm, this, DebuggerScope::createStructure(m_vm, this));
m_withScopeStructure.set(vm, this, JSWithScope::createStructure(vm, this, jsNull()));
-
+
m_nullPrototypeObjectStructure.set(vm, this, JSFinalObject::createStructure(vm, this, jsNull(), JSFinalObject::defaultInlineCapacity()));
-
+
m_callbackFunctionStructure.set(vm, this, JSCallbackFunction::createStructure(vm, this, m_functionPrototype.get()));
- m_argumentsStructure.set(vm, this, Arguments::createStructure(vm, this, m_objectPrototype.get()));
+ m_directArgumentsStructure.set(vm, this, DirectArguments::createStructure(vm, this, m_objectPrototype.get()));
+ m_scopedArgumentsStructure.set(vm, this, ScopedArguments::createStructure(vm, this, m_objectPrototype.get()));
+ m_outOfBandArgumentsStructure.set(vm, this, ClonedArguments::createStructure(vm, this, m_objectPrototype.get()));
m_callbackConstructorStructure.set(vm, this, JSCallbackConstructor::createStructure(vm, this, m_objectPrototype.get()));
m_callbackObjectStructure.set(vm, this, JSCallbackObject<JSDestructibleObject>::createStructure(vm, this, m_objectPrototype.get()));
+
#if JSC_OBJC_API_ENABLED
m_objcCallbackFunctionStructure.set(vm, this, ObjCCallbackFunction::createStructure(vm, this, m_functionPrototype.get()));
m_objcWrapperObjectStructure.set(vm, this, JSCallbackObject<JSAPIWrapperObject>::createStructure(vm, this, m_objectPrototype.get()));
#endif
-
+
m_arrayPrototype.set(vm, this, ArrayPrototype::create(vm, this, ArrayPrototype::createStructure(vm, this, m_objectPrototype.get())));
m_originalArrayStructureForIndexingShape[UndecidedShape >> IndexingShapeShift].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithUndecided));
@@ -323,45 +359,72 @@ void JSGlobalObject::reset(JSValue prototype)
m_originalArrayStructureForIndexingShape[SlowPutArrayStorageShape >> IndexingShapeShift].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage));
for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
m_arrayStructureForIndexingShapeDuringAllocation[i] = m_originalArrayStructureForIndexingShape[i];
-
- m_regExpMatchesArrayStructure.set(vm, this, RegExpMatchesArray::createStructure(vm, this, m_arrayPrototype.get()));
RegExp* emptyRegex = RegExp::create(vm, "", NoFlags);
- m_regExpPrototype.set(vm, this, RegExpPrototype::create(vm, RegExpPrototype::createStructure(vm, this, m_objectPrototype.get()), emptyRegex));
+ m_regExpPrototype.set(vm, this, RegExpPrototype::create(vm, this, RegExpPrototype::createStructure(vm, this, m_objectPrototype.get()), emptyRegex));
m_regExpStructure.set(vm, this, RegExpObject::createStructure(vm, this, m_regExpPrototype.get()));
+ m_regExpMatchesArrayStructure.set(vm, this, createRegExpMatchesArrayStructure(vm, *this));
-#if ENABLE(PROMISES)
- m_promisePrototype.set(vm, this, JSPromisePrototype::create(exec, this, JSPromisePrototype::createStructure(vm, this, m_objectPrototype.get())));
- m_promiseStructure.set(vm, this, JSPromise::createStructure(vm, this, m_promisePrototype.get()));
-#endif // ENABLE(PROMISES)
+ m_moduleRecordStructure.set(vm, this, JSModuleRecord::createStructure(vm, this, m_objectPrototype.get()));
+ m_moduleNamespaceObjectStructure.set(vm, this, JSModuleNamespaceObject::createStructure(vm, this, jsNull()));
+ m_proxyObjectStructure.set(vm, this, ProxyObject::createStructure(vm, this, m_objectPrototype.get()));
+
+#if ENABLE(WEBASSEMBLY)
+ m_wasmModuleStructure.set(vm, this, JSWASMModule::createStructure(vm, this));
+#endif
-#define CREATE_PROTOTYPE_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName) \
- m_ ## lowerName ## Prototype.set(vm, this, capitalName##Prototype::create(vm, this, capitalName##Prototype::createStructure(vm, this, m_objectPrototype.get()))); \
- m_ ## properName ## Structure.set(vm, this, instanceType::createStructure(vm, this, m_ ## lowerName ## Prototype.get()));
+ m_parseIntFunction.set(vm, this, JSFunction::create(vm, this, 2, vm.propertyNames->parseInt.string(), globalFuncParseInt, NoIntrinsic));
+ putDirectWithoutTransition(vm, vm.propertyNames->parseInt, m_parseIntFunction.get(), DontEnum);
+#define CREATE_PROTOTYPE_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName) \
+m_ ## lowerName ## Prototype.set(vm, this, capitalName##Prototype::create(vm, this, capitalName##Prototype::createStructure(vm, this, m_objectPrototype.get()))); \
+m_ ## properName ## Structure.set(vm, this, instanceType::createStructure(vm, this, m_ ## lowerName ## Prototype.get()));
+
FOR_EACH_SIMPLE_BUILTIN_TYPE(CREATE_PROTOTYPE_FOR_SIMPLE_TYPE)
-
+
#undef CREATE_PROTOTYPE_FOR_SIMPLE_TYPE
+ m_iteratorPrototype.set(vm, this, IteratorPrototype::create(vm, this, IteratorPrototype::createStructure(vm, this, m_objectPrototype.get())));
+
+#define CREATE_PROTOTYPE_FOR_DERIVED_ITERATOR_TYPE(capitalName, lowerName, properName, instanceType, jsName) \
+m_ ## lowerName ## Prototype.set(vm, this, capitalName##Prototype::create(vm, this, capitalName##Prototype::createStructure(vm, this, m_iteratorPrototype.get()))); \
+m_ ## properName ## Structure.set(vm, this, instanceType::createStructure(vm, this, m_ ## lowerName ## Prototype.get()));
+
+ FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(CREATE_PROTOTYPE_FOR_DERIVED_ITERATOR_TYPE)
+ m_propertyNameIteratorStructure.set(vm, this, JSPropertyNameIterator::createStructure(vm, this, m_iteratorPrototype.get()));
+ m_generatorPrototype.set(vm, this, GeneratorPrototype::create(vm, this, GeneratorPrototype::createStructure(vm, this, m_iteratorPrototype.get())));
+
+#undef CREATE_PROTOTYPE_FOR_DERIVED_ITERATOR_TYPE
+
// Constructors
- JSCell* objectConstructor = ObjectConstructor::create(vm, ObjectConstructor::createStructure(vm, this, m_functionPrototype.get()), m_objectPrototype.get());
- JSCell* functionConstructor = FunctionConstructor::create(vm, FunctionConstructor::createStructure(vm, this, m_functionPrototype.get()), m_functionPrototype.get());
- JSCell* arrayConstructor = ArrayConstructor::create(vm, ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_arrayPrototype.get());
+ GetterSetter* speciesGetterSetter = GetterSetter::create(vm, this);
+ speciesGetterSetter->setGetter(vm, this, JSFunction::createBuiltinFunction(vm, globalObjectSpeciesGetterCodeGenerator(vm), this));
+
+ ObjectConstructor* objectConstructor = ObjectConstructor::create(vm, this, ObjectConstructor::createStructure(vm, this, m_functionPrototype.get()), m_objectPrototype.get());
+ m_objectConstructor.set(vm, this, objectConstructor);
- m_regExpConstructor.set(vm, this, RegExpConstructor::create(vm, RegExpConstructor::createStructure(vm, this, m_functionPrototype.get()), m_regExpPrototype.get()));
+ JSFunction* definePropertyFunction = m_objectConstructor->addDefineProperty(exec, this);
+ m_definePropertyFunction.set(vm, this, definePropertyFunction);
+ JSCell* functionConstructor = FunctionConstructor::create(vm, FunctionConstructor::createStructure(vm, this, m_functionPrototype.get()), m_functionPrototype.get());
+ JSObject* arrayConstructor = ArrayConstructor::create(vm, ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_arrayPrototype.get(), speciesGetterSetter);
+
+ m_regExpConstructor.set(vm, this, RegExpConstructor::create(vm, RegExpConstructor::createStructure(vm, this, m_functionPrototype.get()), m_regExpPrototype.get(), speciesGetterSetter));
+
#define CREATE_CONSTRUCTOR_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName) \
- capitalName ## Constructor* lowerName ## Constructor = capitalName ## Constructor::create(vm, capitalName ## Constructor::createStructure(vm, this, m_functionPrototype.get()), m_ ## lowerName ## Prototype.get()); \
- m_ ## lowerName ## Prototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, lowerName ## Constructor, DontEnum); \
+capitalName ## Constructor* lowerName ## Constructor = capitalName ## Constructor::create(vm, capitalName ## Constructor::createStructure(vm, this, m_functionPrototype.get()), m_ ## lowerName ## Prototype.get(), speciesGetterSetter); \
+m_ ## lowerName ## Prototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, lowerName ## Constructor, DontEnum); \
FOR_EACH_SIMPLE_BUILTIN_TYPE(CREATE_CONSTRUCTOR_FOR_SIMPLE_TYPE)
-
+
#undef CREATE_CONSTRUCTOR_FOR_SIMPLE_TYPE
-
+
m_errorConstructor.set(vm, this, errorConstructor);
-
+ m_promiseConstructor.set(vm, this, promiseConstructor);
+ m_internalPromiseConstructor.set(vm, this, internalPromiseConstructor);
+
Structure* nativeErrorPrototypeStructure = NativeErrorPrototype::createStructure(vm, this, m_errorPrototype.get());
Structure* nativeErrorStructure = NativeErrorConstructor::createStructure(vm, this, m_functionPrototype.get());
m_evalErrorConstructor.set(vm, this, NativeErrorConstructor::create(vm, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("EvalError")));
@@ -370,16 +433,20 @@ void JSGlobalObject::reset(JSValue prototype)
m_syntaxErrorConstructor.set(vm, this, NativeErrorConstructor::create(vm, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("SyntaxError")));
m_typeErrorConstructor.set(vm, this, NativeErrorConstructor::create(vm, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("TypeError")));
m_URIErrorConstructor.set(vm, this, NativeErrorConstructor::create(vm, this, nativeErrorStructure, nativeErrorPrototypeStructure, ASCIILiteral("URIError")));
- m_promiseConstructor.set(vm, this, JSPromiseConstructor::create(vm, JSPromiseConstructor::createStructure(vm, this, m_functionPrototype.get()), m_promisePrototype.get()));
+ m_generatorFunctionPrototype.set(vm, this, GeneratorFunctionPrototype::create(vm, GeneratorFunctionPrototype::createStructure(vm, this, m_functionPrototype.get())));
+ GeneratorFunctionConstructor* generatorFunctionConstructor = GeneratorFunctionConstructor::create(vm, GeneratorFunctionConstructor::createStructure(vm, this, functionConstructor), m_generatorFunctionPrototype.get());
+ m_generatorFunctionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, generatorFunctionConstructor, DontEnum);
+ m_generatorFunctionStructure.set(vm, this, JSGeneratorFunction::createStructure(vm, this, m_generatorFunctionPrototype.get()));
+
+ m_generatorPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, m_generatorFunctionPrototype.get(), DontEnum);
+ m_generatorFunctionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->prototype, m_generatorPrototype.get(), DontEnum);
+
m_objectPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, objectConstructor, DontEnum);
m_functionPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, functionConstructor, DontEnum);
- m_arrayPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, arrayConstructor, DontEnum);
+ m_arrayPrototype->setConstructor(vm, arrayConstructor, DontEnum);
m_regExpPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, m_regExpConstructor.get(), DontEnum);
-#if ENABLE(PROMISES)
- m_promisePrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, m_promiseConstructor.get(), DontEnum);
-#endif
-
+
putDirectWithoutTransition(vm, vm.propertyNames->Object, objectConstructor, DontEnum);
putDirectWithoutTransition(vm, vm.propertyNames->Function, functionConstructor, DontEnum);
putDirectWithoutTransition(vm, vm.propertyNames->Array, arrayConstructor, DontEnum);
@@ -390,49 +457,135 @@ void JSGlobalObject::reset(JSValue prototype)
putDirectWithoutTransition(vm, vm.propertyNames->SyntaxError, m_syntaxErrorConstructor.get(), DontEnum);
putDirectWithoutTransition(vm, vm.propertyNames->TypeError, m_typeErrorConstructor.get(), DontEnum);
putDirectWithoutTransition(vm, vm.propertyNames->URIError, m_URIErrorConstructor.get(), DontEnum);
- putDirectWithoutTransition(vm, vm.propertyNames->Promise, m_promiseConstructor.get(), DontEnum);
-
+ putDirectWithoutTransition(vm, vm.propertyNames->Proxy, ProxyConstructor::create(vm, ProxyConstructor::createStructure(vm, this, m_functionPrototype.get())), DontEnum);
+
+
#define PUT_CONSTRUCTOR_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName) \
- putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Constructor, DontEnum); \
+putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Constructor, DontEnum); \
- FOR_EACH_SIMPLE_BUILTIN_TYPE(PUT_CONSTRUCTOR_FOR_SIMPLE_TYPE)
+ FOR_EACH_SIMPLE_BUILTIN_TYPE_WITH_CONSTRUCTOR(PUT_CONSTRUCTOR_FOR_SIMPLE_TYPE)
#undef PUT_CONSTRUCTOR_FOR_SIMPLE_TYPE
- PrototypeMap& prototypeMap = vm.prototypeMap;
- Structure* iteratorResultStructure = prototypeMap.emptyObjectStructureForPrototype(m_objectPrototype.get(), JSFinalObject::defaultInlineCapacity());
- PropertyOffset offset;
- iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames->done, 0, 0, offset);
- iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames->value, 0, 0, offset);
- m_iteratorResultStructure.set(vm, this, iteratorResultStructure);
-
+ m_iteratorResultObjectStructure.set(vm, this, createIteratorResultObjectStructure(vm, *this));
+
m_evalFunction.set(vm, this, JSFunction::create(vm, this, 1, vm.propertyNames->eval.string(), globalFuncEval));
putDirectWithoutTransition(vm, vm.propertyNames->eval, m_evalFunction.get(), DontEnum);
-
+
+#if ENABLE(INTL)
+ IntlObject* intl = IntlObject::create(vm, this, IntlObject::createStructure(vm, this, m_objectPrototype.get()));
+ putDirectWithoutTransition(vm, vm.propertyNames->Intl, intl, DontEnum);
+#endif // ENABLE(INTL)
putDirectWithoutTransition(vm, vm.propertyNames->JSON, JSONObject::create(vm, JSONObject::createStructure(vm, this, m_objectPrototype.get())), DontEnum);
putDirectWithoutTransition(vm, vm.propertyNames->Math, MathObject::create(vm, this, MathObject::createStructure(vm, this, m_objectPrototype.get())), DontEnum);
-
- std::array<InternalFunction*, NUMBER_OF_TYPED_ARRAY_TYPES> typedArrayConstructors;
- typedArrayConstructors[toIndex(TypeInt8)] = JSInt8ArrayConstructor::create(vm, JSInt8ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeInt8)].prototype.get(), "Int8Array");
- typedArrayConstructors[toIndex(TypeInt16)] = JSInt16ArrayConstructor::create(vm, JSInt16ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeInt16)].prototype.get(), "Int16Array");
- typedArrayConstructors[toIndex(TypeInt32)] = JSInt32ArrayConstructor::create(vm, JSInt32ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeInt32)].prototype.get(), "Int32Array");
- typedArrayConstructors[toIndex(TypeUint8)] = JSUint8ArrayConstructor::create(vm, JSUint8ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeUint8)].prototype.get(), "Uint8Array");
- typedArrayConstructors[toIndex(TypeUint8Clamped)] = JSUint8ClampedArrayConstructor::create(vm, JSUint8ClampedArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeUint8Clamped)].prototype.get(), "Uint8ClampedArray");
- typedArrayConstructors[toIndex(TypeUint16)] = JSUint16ArrayConstructor::create(vm, JSUint16ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeUint16)].prototype.get(), "Uint16Array");
- typedArrayConstructors[toIndex(TypeUint32)] = JSUint32ArrayConstructor::create(vm, JSUint32ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeUint32)].prototype.get(), "Uint32Array");
- typedArrayConstructors[toIndex(TypeFloat32)] = JSFloat32ArrayConstructor::create(vm, JSFloat32ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeFloat32)].prototype.get(), "Float32Array");
- typedArrayConstructors[toIndex(TypeFloat64)] = JSFloat64ArrayConstructor::create(vm, JSFloat64ArrayConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeFloat64)].prototype.get(), "Float64Array");
- typedArrayConstructors[toIndex(TypeDataView)] = JSDataViewConstructor::create(vm, JSDataViewConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeDataView)].prototype.get(), "DataView");
+ putDirectWithoutTransition(vm, vm.propertyNames->Reflect, ReflectObject::create(vm, this, ReflectObject::createStructure(vm, this, m_objectPrototype.get())), DontEnum);
+
+ JSTypedArrayViewConstructor* typedArraySuperConstructor = JSTypedArrayViewConstructor::create(vm, this, JSTypedArrayViewConstructor::createStructure(vm, this, m_functionPrototype.get()), typedArrayProto, speciesGetterSetter);
+ typedArrayProto->putDirectWithoutTransition(vm, vm.propertyNames->constructor, typedArraySuperConstructor, DontEnum);
+ std::array<InternalFunction*, NUMBER_OF_TYPED_ARRAY_TYPES> typedArrayConstructors;
+ typedArrayConstructors[toIndex(TypeInt8)] = JSInt8ArrayConstructor::create(vm, this, JSInt8ArrayConstructor::createStructure(vm, this, typedArraySuperConstructor), m_typedArrays[toIndex(TypeInt8)].prototype.get(), ASCIILiteral("Int8Array"), typedArrayConstructorAllocateInt8ArrayCodeGenerator(vm));
+ typedArrayConstructors[toIndex(TypeInt16)] = JSInt16ArrayConstructor::create(vm, this, JSInt16ArrayConstructor::createStructure(vm, this, typedArraySuperConstructor), m_typedArrays[toIndex(TypeInt16)].prototype.get(), ASCIILiteral("Int16Array"), typedArrayConstructorAllocateInt16ArrayCodeGenerator(vm));
+ typedArrayConstructors[toIndex(TypeInt32)] = JSInt32ArrayConstructor::create(vm, this, JSInt32ArrayConstructor::createStructure(vm, this, typedArraySuperConstructor), m_typedArrays[toIndex(TypeInt32)].prototype.get(), ASCIILiteral("Int32Array"), typedArrayConstructorAllocateInt32ArrayCodeGenerator(vm));
+ typedArrayConstructors[toIndex(TypeUint8)] = JSUint8ArrayConstructor::create(vm, this, JSUint8ArrayConstructor::createStructure(vm, this, typedArraySuperConstructor), m_typedArrays[toIndex(TypeUint8)].prototype.get(), ASCIILiteral("Uint8Array"), typedArrayConstructorAllocateUint8ArrayCodeGenerator(vm));
+ typedArrayConstructors[toIndex(TypeUint8Clamped)] = JSUint8ClampedArrayConstructor::create(vm, this, JSUint8ClampedArrayConstructor::createStructure(vm, this, typedArraySuperConstructor), m_typedArrays[toIndex(TypeUint8Clamped)].prototype.get(), ASCIILiteral("Uint8ClampedArray"), typedArrayConstructorAllocateUint8ClampedArrayCodeGenerator(vm));
+ typedArrayConstructors[toIndex(TypeUint16)] = JSUint16ArrayConstructor::create(vm, this, JSUint16ArrayConstructor::createStructure(vm, this, typedArraySuperConstructor), m_typedArrays[toIndex(TypeUint16)].prototype.get(), ASCIILiteral("Uint16Array"), typedArrayConstructorAllocateUint16ArrayCodeGenerator(vm));
+ typedArrayConstructors[toIndex(TypeUint32)] = JSUint32ArrayConstructor::create(vm, this, JSUint32ArrayConstructor::createStructure(vm, this, typedArraySuperConstructor), m_typedArrays[toIndex(TypeUint32)].prototype.get(), ASCIILiteral("Uint32Array"), typedArrayConstructorAllocateUint32ArrayCodeGenerator(vm));
+ typedArrayConstructors[toIndex(TypeFloat32)] = JSFloat32ArrayConstructor::create(vm, this, JSFloat32ArrayConstructor::createStructure(vm, this, typedArraySuperConstructor), m_typedArrays[toIndex(TypeFloat32)].prototype.get(), ASCIILiteral("Float32Array"), typedArrayConstructorAllocateFloat32ArrayCodeGenerator(vm));
+ typedArrayConstructors[toIndex(TypeFloat64)] = JSFloat64ArrayConstructor::create(vm, this, JSFloat64ArrayConstructor::createStructure(vm, this, typedArraySuperConstructor), m_typedArrays[toIndex(TypeFloat64)].prototype.get(), ASCIILiteral("Float64Array"), typedArrayConstructorAllocateFloat64ArrayCodeGenerator(vm));
+ typedArrayConstructors[toIndex(TypeDataView)] = JSDataViewConstructor::create(vm, this, JSDataViewConstructor::createStructure(vm, this, m_functionPrototype.get()), m_typedArrays[toIndex(TypeDataView)].prototype.get(), ASCIILiteral("DataView"), nullptr);
+
for (unsigned typedArrayIndex = NUMBER_OF_TYPED_ARRAY_TYPES; typedArrayIndex--;) {
m_typedArrays[typedArrayIndex].prototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, typedArrayConstructors[typedArrayIndex], DontEnum);
- putDirectWithoutTransition(vm, Identifier(exec, typedArrayConstructors[typedArrayIndex]->name(exec)), typedArrayConstructors[typedArrayIndex], DontEnum);
+ putDirectWithoutTransition(vm, Identifier::fromString(exec, typedArrayConstructors[typedArrayIndex]->name(exec)), typedArrayConstructors[typedArrayIndex], DontEnum);
}
+ putDirectWithoutTransition(vm, vm.propertyNames->Int8ArrayPrivateName, typedArrayConstructors[toIndex(TypeInt8)], DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->Int16ArrayPrivateName, typedArrayConstructors[toIndex(TypeInt16)], DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->Int32ArrayPrivateName, typedArrayConstructors[toIndex(TypeInt32)], DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->Uint8ArrayPrivateName, typedArrayConstructors[toIndex(TypeUint8)], DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->Uint8ClampedArrayPrivateName, typedArrayConstructors[toIndex(TypeUint8Clamped)], DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->Uint16ArrayPrivateName, typedArrayConstructors[toIndex(TypeUint16)], DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->Uint32ArrayPrivateName, typedArrayConstructors[toIndex(TypeUint32)], DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->Float32ArrayPrivateName, typedArrayConstructors[toIndex(TypeFloat32)], DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->Float64ArrayPrivateName, typedArrayConstructors[toIndex(TypeFloat64)], DontEnum);
+
+ m_moduleLoader.set(vm, this, ModuleLoaderObject::create(vm, this, ModuleLoaderObject::createStructure(vm, this, m_objectPrototype.get())));
+ if (Options::exposeInternalModuleLoader())
+ putDirectWithoutTransition(vm, vm.propertyNames->Loader, m_moduleLoader.get(), DontEnum);
+
+ JSFunction* builtinLog = JSFunction::create(vm, this, 1, vm.propertyNames->emptyIdentifier.string(), globalFuncBuiltinLog);
+
+ JSFunction* privateFuncAbs = JSFunction::create(vm, this, 0, String(), mathProtoFuncAbs, AbsIntrinsic);
+ JSFunction* privateFuncFloor = JSFunction::create(vm, this, 0, String(), mathProtoFuncFloor, FloorIntrinsic);
+ JSFunction* privateFuncIsFinite = JSFunction::create(vm, this, 0, String(), globalFuncIsFinite);
+ JSFunction* privateFuncIsNaN = JSFunction::create(vm, this, 0, String(), globalFuncIsNaN);
+
+ JSFunction* privateFuncGetTemplateObject = JSFunction::create(vm, this, 0, String(), getTemplateObject);
+ JSFunction* privateFuncToLength = JSFunction::createBuiltinFunction(vm, globalObjectToLengthCodeGenerator(vm), this);
+ JSFunction* privateFuncToInteger = JSFunction::createBuiltinFunction(vm, globalObjectToIntegerCodeGenerator(vm), this);
+ JSFunction* privateFuncTypedArrayLength = JSFunction::create(vm, this, 0, String(), typedArrayViewPrivateFuncLength);
+ JSFunction* privateFuncTypedArraySort = JSFunction::create(vm, this, 0, String(), typedArrayViewPrivateFuncSort);
+ JSFunction* privateFuncIsBoundFunction = JSFunction::create(vm, this, 0, String(), isBoundFunction);
+ JSFunction* privateFuncHasInstanceBoundFunction = JSFunction::create(vm, this, 0, String(), hasInstanceBoundFunction);
+ JSFunction* privateFuncInstanceOf = JSFunction::create(vm, this, 0, String(), objectPrivateFuncInstanceOf);
+ JSFunction* privateFuncThisTimeValue = JSFunction::create(vm, this, 0, String(), dateProtoFuncGetTime);
+
GlobalPropertyInfo staticGlobals[] = {
GlobalPropertyInfo(vm.propertyNames->NaN, jsNaN(), DontEnum | DontDelete | ReadOnly),
GlobalPropertyInfo(vm.propertyNames->Infinity, jsNumber(std::numeric_limits<double>::infinity()), DontEnum | DontDelete | ReadOnly),
- GlobalPropertyInfo(vm.propertyNames->undefinedKeyword, jsUndefined(), DontEnum | DontDelete | ReadOnly)
+ GlobalPropertyInfo(vm.propertyNames->undefinedKeyword, jsUndefined(), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->ObjectPrivateName, objectConstructor, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->ownEnumerablePropertyKeysPrivateName, JSFunction::create(vm, this, 0, String(), ownEnumerablePropertyKeys), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->getTemplateObjectPrivateName, privateFuncGetTemplateObject, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->enqueueJobPrivateName, JSFunction::create(vm, this, 0, String(), enqueueJob), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->RangeErrorPrivateName, m_rangeErrorConstructor.get(), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->TypeErrorPrivateName, m_typeErrorConstructor.get(), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->typedArrayLengthPrivateName, privateFuncTypedArrayLength, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->typedArraySortPrivateName, privateFuncTypedArraySort, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->isBoundFunctionPrivateName, privateFuncIsBoundFunction, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->hasInstanceBoundFunctionPrivateName, privateFuncHasInstanceBoundFunction, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->instanceOfPrivateName, privateFuncInstanceOf, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->BuiltinLogPrivateName, builtinLog, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->ArrayPrivateName, arrayConstructor, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->NumberPrivateName, numberConstructor, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->RegExpPrivateName, m_regExpConstructor.get(), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->StringPrivateName, stringConstructor, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->absPrivateName, privateFuncAbs, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->floorPrivateName, privateFuncFloor, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->isFinitePrivateName, privateFuncIsFinite, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->isNaNPrivateName, privateFuncIsNaN, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->PromisePrivateName, promiseConstructor, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->InternalPromisePrivateName, internalPromiseConstructor, DontEnum | DontDelete | ReadOnly),
+
+ GlobalPropertyInfo(vm.propertyNames->isSetPrivateName, JSFunction::create(vm, this, 1, String(), privateFuncIsSet), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->SetIteratorPrivateName, JSFunction::create(vm, this, 1, String(), privateFuncSetIterator), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->setIteratorNextPrivateName, JSFunction::create(vm, this, 0, String(), privateFuncSetIteratorNext), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->isMapPrivateName, JSFunction::create(vm, this, 1, String(), privateFuncIsMap), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->MapIteratorPrivateName, JSFunction::create(vm, this, 1, String(), privateFuncMapIterator), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->mapIteratorNextPrivateName, JSFunction::create(vm, this, 0, String(), privateFuncMapIteratorNext), DontEnum | DontDelete | ReadOnly),
+
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().toLengthPrivateName(), privateFuncToLength, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().toIntegerPrivateName(), privateFuncToInteger, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().isDictionaryPrivateName(), JSFunction::createBuiltinFunction(vm, globalObjectIsDictionaryCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().isPromisePrivateName(), JSFunction::createBuiltinFunction(vm, promiseOperationsIsPromiseCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().newPromiseReactionPrivateName(), JSFunction::createBuiltinFunction(vm, promiseOperationsNewPromiseReactionCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().newPromiseCapabilityPrivateName(), m_newPromiseCapabilityFunction.get(), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().triggerPromiseReactionsPrivateName(), JSFunction::createBuiltinFunction(vm, promiseOperationsTriggerPromiseReactionsCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().rejectPromisePrivateName(), JSFunction::createBuiltinFunction(vm, promiseOperationsRejectPromiseCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().fulfillPromisePrivateName(), JSFunction::createBuiltinFunction(vm, promiseOperationsFulfillPromiseCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().createResolvingFunctionsPrivateName(), JSFunction::createBuiltinFunction(vm, promiseOperationsCreateResolvingFunctionsCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().promiseReactionJobPrivateName(), JSFunction::createBuiltinFunction(vm, promiseOperationsPromiseReactionJobCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().promiseResolveThenableJobPrivateName(), JSFunction::createBuiltinFunction(vm, promiseOperationsPromiseResolveThenableJobCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().InspectorInstrumentationPrivateName(), InspectorInstrumentationObject::create(vm, this, InspectorInstrumentationObject::createStructure(vm, this, m_objectPrototype.get())), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->MapPrivateName, mapConstructor, DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().generatorResumePrivateName(), JSFunction::createBuiltinFunction(vm, generatorPrototypeGeneratorResumeCodeGenerator(vm), this), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().thisTimeValuePrivateName(), privateFuncThisTimeValue, DontEnum | DontDelete | ReadOnly),
+#if ENABLE(INTL)
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().CollatorPrivateName(), intl->getDirect(vm, vm.propertyNames->Collator), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().DateTimeFormatPrivateName(), intl->getDirect(vm, vm.propertyNames->DateTimeFormat), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(vm.propertyNames->builtinNames().NumberFormatPrivateName(), intl->getDirect(vm, vm.propertyNames->NumberFormat), DontEnum | DontDelete | ReadOnly),
+#endif // ENABLE(INTL)
};
addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals));
@@ -441,16 +594,79 @@ void JSGlobalObject::reset(JSValue prototype)
m_specialPointers[Special::ObjectConstructor] = objectConstructor;
m_specialPointers[Special::ArrayConstructor] = arrayConstructor;
- if (m_experimentsEnabled) {
- NamePrototype* privateNamePrototype = NamePrototype::create(exec, NamePrototype::createStructure(vm, this, m_objectPrototype.get()));
- m_privateNameStructure.set(vm, this, NameInstance::createStructure(vm, this, privateNamePrototype));
+ m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::DefinePropertyFunction)] = m_definePropertyFunction.get();
+
+ ConsolePrototype* consolePrototype = ConsolePrototype::create(vm, this, ConsolePrototype::createStructure(vm, this, m_objectPrototype.get()));
+ m_consoleStructure.set(vm, this, JSConsole::createStructure(vm, this, consolePrototype));
+ JSConsole* consoleObject = JSConsole::create(vm, m_consoleStructure.get());
+ putDirectWithoutTransition(vm, Identifier::fromString(exec, "console"), consoleObject, DontEnum);
- JSCell* privateNameConstructor = NameConstructor::create(vm, NameConstructor::createStructure(vm, this, m_functionPrototype.get()), privateNamePrototype);
- privateNamePrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, privateNameConstructor, DontEnum);
- putDirectWithoutTransition(vm, Identifier(exec, "Name"), privateNameConstructor, DontEnum);
+ if (UNLIKELY(Options::useDollarVM())) {
+ JSDollarVMPrototype* dollarVMPrototype = JSDollarVMPrototype::create(vm, this, JSDollarVMPrototype::createStructure(vm, this, m_objectPrototype.get()));
+ m_dollarVMStructure.set(vm, this, JSDollarVM::createStructure(vm, this, dollarVMPrototype));
+ JSDollarVM* dollarVM = JSDollarVM::create(vm, m_dollarVMStructure.get());
+ putDirectWithoutTransition(vm, Identifier::fromString(exec, "$vm"), dollarVM, DontEnum);
}
- resetPrototype(vm, prototype);
+ resetPrototype(vm, prototype());
+}
+
+bool JSGlobalObject::hasLegacyProfiler() const
+{
+ return globalObjectMethodTable()->supportsLegacyProfiling(this);
+}
+
+void JSGlobalObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
+ JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell);
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
+
+ bool shouldThrowReadOnlyError = slot.isStrictMode();
+ bool ignoreReadOnlyErrors = false;
+ if (symbolTablePutTouchWatchpointSet(thisObject, exec, propertyName, value, shouldThrowReadOnlyError, ignoreReadOnlyErrors))
+ return;
+ Base::put(thisObject, exec, propertyName, value, slot);
+}
+
+bool JSGlobalObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
+{
+ JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object);
+ PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
+ // silently ignore attempts to add accessors aliasing vars.
+ if (descriptor.isAccessorDescriptor() && symbolTableGet(thisObject, propertyName, slot))
+ return false;
+ return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
+}
+
+void JSGlobalObject::addGlobalVar(const Identifier& ident)
+{
+ ConcurrentJITLocker locker(symbolTable()->m_lock);
+ SymbolTableEntry entry = symbolTable()->get(locker, ident.impl());
+ if (!entry.isNull())
+ return;
+
+ ScopeOffset offset = symbolTable()->takeNextScopeOffset(locker);
+ SymbolTableEntry newEntry(VarOffset(offset), 0);
+ newEntry.prepareToWatch();
+ symbolTable()->add(locker, ident.impl(), newEntry);
+
+ ScopeOffset offsetForAssert = addVariables(1, jsUndefined());
+ RELEASE_ASSERT(offsetForAssert == offset);
+}
+
+void JSGlobalObject::addFunction(ExecState* exec, const Identifier& propertyName)
+{
+ VM& vm = exec->vm();
+ removeDirect(vm, propertyName); // Newly declared functions overwrite existing properties.
+ addGlobalVar(propertyName);
+}
+
+static inline JSObject* lastInPrototypeChain(JSObject* object)
+{
+ JSObject* o = object;
+ while (o->prototype().isObject())
+ o = asObject(o->prototype());
+ return o;
}
// Private namespace for helpers for JSGlobalObject::haveABadTime()
@@ -459,9 +675,11 @@ namespace {
class ObjectsWithBrokenIndexingFinder : public MarkedBlock::VoidFunctor {
public:
ObjectsWithBrokenIndexingFinder(MarkedArgumentBuffer&, JSGlobalObject*);
- void operator()(JSCell*);
+ IterationStatus operator()(JSCell*);
private:
+ void visit(JSCell*);
+
MarkedArgumentBuffer& m_foundObjects;
JSGlobalObject* m_globalObject;
};
@@ -476,13 +694,13 @@ ObjectsWithBrokenIndexingFinder::ObjectsWithBrokenIndexingFinder(
inline bool hasBrokenIndexing(JSObject* object)
{
// This will change if we have more indexing types.
- IndexingType type = object->structure()->indexingType();
+ IndexingType type = object->indexingType();
// This could be made obviously more efficient, but isn't made so right now, because
// we expect this to be an unlikely slow path anyway.
- return hasUndecided(type) || hasInt32(type) || hasDouble(type) || hasContiguous(type) || hasFastArrayStorage(type);
+ return hasUndecided(type) || hasInt32(type) || hasDouble(type) || hasContiguous(type) || hasArrayStorage(type);
}
-void ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell)
+inline void ObjectsWithBrokenIndexingFinder::visit(JSCell* cell)
{
if (!cell->isObject())
return;
@@ -514,6 +732,12 @@ void ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell)
m_foundObjects.append(object);
}
+IterationStatus ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell)
+{
+ visit(cell);
+ return IterationStatus::Continue;
+}
+
} // end private namespace for helpers for JSGlobalObject::haveABadTime()
void JSGlobalObject::haveABadTime(VM& vm)
@@ -526,7 +750,7 @@ void JSGlobalObject::haveABadTime(VM& vm)
// Make sure that all allocations or indexed storage transitions that are inlining
// the assumption that it's safe to transition to a non-SlowPut array storage don't
// do so anymore.
- m_havingABadTimeWatchpoint->fireAll();
+ m_havingABadTimeWatchpoint->fireAll("Having a bad time");
ASSERT(isHavingABadTime()); // The watchpoint is what tells us that we're having a bad time.
// Make sure that all JSArray allocations that load the appropriate structure from
@@ -552,20 +776,20 @@ void JSGlobalObject::haveABadTime(VM& vm)
bool JSGlobalObject::objectPrototypeIsSane()
{
- return !hasIndexedProperties(m_objectPrototype->structure()->indexingType())
+ return !hasIndexedProperties(m_objectPrototype->indexingType())
&& m_objectPrototype->prototype().isNull();
}
bool JSGlobalObject::arrayPrototypeChainIsSane()
{
- return !hasIndexedProperties(m_arrayPrototype->structure()->indexingType())
+ return !hasIndexedProperties(m_arrayPrototype->indexingType())
&& m_arrayPrototype->prototype() == m_objectPrototype.get()
&& objectPrototypeIsSane();
}
bool JSGlobalObject::stringPrototypeChainIsSane()
{
- return !hasIndexedProperties(m_stringPrototype->structure()->indexingType())
+ return !hasIndexedProperties(m_stringPrototype->indexingType())
&& m_stringPrototype->prototype() == m_objectPrototype.get()
&& objectPrototypeIsSane();
}
@@ -573,9 +797,9 @@ bool JSGlobalObject::stringPrototypeChainIsSane()
void JSGlobalObject::createThrowTypeError(VM& vm)
{
JSFunction* thrower = JSFunction::create(vm, this, 0, String(), globalFuncThrowTypeError);
- GetterSetter* getterSetter = GetterSetter::create(vm);
- getterSetter->setGetter(vm, thrower);
- getterSetter->setSetter(vm, thrower);
+ GetterSetter* getterSetter = GetterSetter::create(vm, this);
+ getterSetter->setGetter(vm, this, thrower);
+ getterSetter->setSetter(vm, this, thrower);
m_throwTypeErrorGetterSetter.set(vm, this, getterSetter);
}
@@ -588,18 +812,21 @@ void JSGlobalObject::resetPrototype(VM& vm, JSValue prototype)
JSObject* objectPrototype = m_objectPrototype.get();
if (oldLastInPrototypeChain != objectPrototype)
oldLastInPrototypeChain->setPrototype(vm, objectPrototype);
+
+ // Whenever we change the prototype of the global object, we need to create a new JSProxy with the correct prototype.
+ setGlobalThis(vm, JSProxy::create(vm, JSProxy::createStructure(vm, this, prototype, PureForwardingProxyType), this));
}
void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
Base::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_globalThis);
+ visitor.append(&thisObject->m_globalLexicalEnvironment);
+ visitor.append(&thisObject->m_globalCallee);
visitor.append(&thisObject->m_regExpConstructor);
visitor.append(&thisObject->m_errorConstructor);
visitor.append(&thisObject->m_evalErrorConstructor);
@@ -608,26 +835,41 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitor.append(&thisObject->m_syntaxErrorConstructor);
visitor.append(&thisObject->m_typeErrorConstructor);
visitor.append(&thisObject->m_URIErrorConstructor);
+ visitor.append(&thisObject->m_objectConstructor);
visitor.append(&thisObject->m_promiseConstructor);
+ visitor.append(&thisObject->m_internalPromiseConstructor);
+
+ visitor.append(&thisObject->m_nullGetterFunction);
+ visitor.append(&thisObject->m_nullSetterFunction);
+ visitor.append(&thisObject->m_parseIntFunction);
visitor.append(&thisObject->m_evalFunction);
visitor.append(&thisObject->m_callFunction);
visitor.append(&thisObject->m_applyFunction);
+ visitor.append(&thisObject->m_definePropertyFunction);
+ visitor.append(&thisObject->m_arrayProtoValuesFunction);
+ visitor.append(&thisObject->m_initializePromiseFunction);
+ visitor.append(&thisObject->m_newPromiseCapabilityFunction);
+ visitor.append(&thisObject->m_functionProtoHasInstanceSymbolFunction);
visitor.append(&thisObject->m_throwTypeErrorGetterSetter);
+ visitor.append(&thisObject->m_moduleLoader);
visitor.append(&thisObject->m_objectPrototype);
visitor.append(&thisObject->m_functionPrototype);
visitor.append(&thisObject->m_arrayPrototype);
visitor.append(&thisObject->m_errorPrototype);
-#if ENABLE(PROMISES)
- visitor.append(&thisObject->m_promisePrototype);
-#endif
+ visitor.append(&thisObject->m_iteratorPrototype);
+ visitor.append(&thisObject->m_generatorFunctionPrototype);
+ visitor.append(&thisObject->m_generatorPrototype);
+ visitor.append(&thisObject->m_debuggerScopeStructure);
visitor.append(&thisObject->m_withScopeStructure);
visitor.append(&thisObject->m_strictEvalActivationStructure);
- visitor.append(&thisObject->m_activationStructure);
- visitor.append(&thisObject->m_nameScopeStructure);
- visitor.append(&thisObject->m_argumentsStructure);
+ visitor.append(&thisObject->m_lexicalEnvironmentStructure);
+ visitor.append(&thisObject->m_moduleEnvironmentStructure);
+ visitor.append(&thisObject->m_directArgumentsStructure);
+ visitor.append(&thisObject->m_scopedArgumentsStructure);
+ visitor.append(&thisObject->m_outOfBandArgumentsStructure);
for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
visitor.append(&thisObject->m_originalArrayStructureForIndexingShape[i]);
for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
@@ -636,29 +878,40 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitor.append(&thisObject->m_callbackConstructorStructure);
visitor.append(&thisObject->m_callbackFunctionStructure);
visitor.append(&thisObject->m_callbackObjectStructure);
+ visitor.append(&thisObject->m_propertyNameIteratorStructure);
#if JSC_OBJC_API_ENABLED
visitor.append(&thisObject->m_objcCallbackFunctionStructure);
visitor.append(&thisObject->m_objcWrapperObjectStructure);
#endif
visitor.append(&thisObject->m_nullPrototypeObjectStructure);
visitor.append(&thisObject->m_errorStructure);
+ visitor.append(&thisObject->m_calleeStructure);
visitor.append(&thisObject->m_functionStructure);
+ visitor.append(&thisObject->m_boundSlotBaseFunctionStructure);
visitor.append(&thisObject->m_boundFunctionStructure);
+ visitor.append(&thisObject->m_nativeStdFunctionStructure);
visitor.append(&thisObject->m_namedFunctionStructure);
- visitor.append(&thisObject->m_privateNameStructure);
- visitor.append(&thisObject->m_regExpMatchesArrayStructure);
+ visitor.append(&thisObject->m_symbolObjectStructure);
visitor.append(&thisObject->m_regExpStructure);
+ visitor.append(&thisObject->m_generatorFunctionStructure);
+ visitor.append(&thisObject->m_iteratorResultObjectStructure);
+ visitor.append(&thisObject->m_regExpMatchesArrayStructure);
+ visitor.append(&thisObject->m_moduleRecordStructure);
+ visitor.append(&thisObject->m_moduleNamespaceObjectStructure);
+ visitor.append(&thisObject->m_consoleStructure);
+ visitor.append(&thisObject->m_dollarVMStructure);
visitor.append(&thisObject->m_internalFunctionStructure);
-
-#if ENABLE(PROMISES)
- visitor.append(&thisObject->m_promiseStructure);
-#endif // ENABLE(PROMISES)
+ visitor.append(&thisObject->m_proxyObjectStructure);
+#if ENABLE(WEBASSEMBLY)
+ visitor.append(&thisObject->m_wasmModuleStructure);
+#endif
#define VISIT_SIMPLE_TYPE(CapitalName, lowerName, properName, instanceType, jsName) \
visitor.append(&thisObject->m_ ## lowerName ## Prototype); \
visitor.append(&thisObject->m_ ## properName ## Structure); \
FOR_EACH_SIMPLE_BUILTIN_TYPE(VISIT_SIMPLE_TYPE)
+ FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(VISIT_SIMPLE_TYPE)
#undef VISIT_SIMPLE_TYPE
@@ -682,30 +935,35 @@ ExecState* JSGlobalObject::globalExec()
void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
{
- addRegisters(count);
+ ScopeOffset startOffset = addVariables(count, jsUndefined());
for (int i = 0; i < count; ++i) {
GlobalPropertyInfo& global = globals[i];
ASSERT(global.attributes & DontDelete);
- int index = symbolTable()->size();
- SymbolTableEntry newEntry(index, global.attributes);
- symbolTable()->add(global.identifier.impl(), newEntry);
- registerAt(index).set(vm(), this, global.value);
+ ScopeOffset offset;
+ {
+ ConcurrentJITLocker locker(symbolTable()->m_lock);
+ offset = symbolTable()->takeNextScopeOffset(locker);
+ RELEASE_ASSERT(offset = startOffset + i);
+ SymbolTableEntry newEntry(VarOffset(offset), global.attributes);
+ symbolTable()->add(locker, global.identifier.impl(), newEntry);
+ }
+ variableAt(offset).set(vm(), this, global.value);
}
}
bool JSGlobalObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object);
- if (getStaticFunctionSlot<Base>(exec, ExecState::globalObjectTable(exec->vm()), thisObject, propertyName, slot))
+ if (getStaticFunctionSlot<Base>(exec, globalObjectTable, thisObject, propertyName, slot))
return true;
return symbolTableGet(thisObject, propertyName, slot);
}
void JSGlobalObject::clearRareData(JSCell* cell)
{
- jsCast<JSGlobalObject*>(cell)->m_rareData.clear();
+ jsCast<JSGlobalObject*>(cell)->m_rareData = nullptr;
}
void slowValidateCell(JSGlobalObject* globalObject)
@@ -717,36 +975,58 @@ void slowValidateCell(JSGlobalObject* globalObject)
UnlinkedProgramCodeBlock* JSGlobalObject::createProgramCodeBlock(CallFrame* callFrame, ProgramExecutable* executable, JSObject** exception)
{
ParserError error;
- JSParserStrictness strictness = executable->isStrictMode() ? JSParseStrict : JSParseNormal;
+ JSParserStrictMode strictMode = executable->isStrictMode() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict;
DebuggerMode debuggerMode = hasDebugger() ? DebuggerOn : DebuggerOff;
- ProfilerMode profilerMode = hasProfiler() ? ProfilerOn : ProfilerOff;
- UnlinkedProgramCodeBlock* unlinkedCodeBlock = vm().codeCache()->getProgramCodeBlock(vm(), executable, executable->source(), strictness, debuggerMode, profilerMode, error);
+ ProfilerMode profilerMode = hasLegacyProfiler() ? ProfilerOn : ProfilerOff;
+ UnlinkedProgramCodeBlock* unlinkedCodeBlock = vm().codeCache()->getProgramCodeBlock(
+ vm(), executable, executable->source(), JSParserBuiltinMode::NotBuiltin, strictMode,
+ debuggerMode, profilerMode, error);
if (hasDebugger())
- debugger()->sourceParsed(callFrame, executable->source().provider(), error.m_line, error.m_message);
+ debugger()->sourceParsed(callFrame, executable->source().provider(), error.line(), error.message());
- if (error.m_type != ParserError::ErrorNone) {
+ if (error.isValid()) {
*exception = error.toErrorObject(this, executable->source());
- return 0;
+ return nullptr;
}
return unlinkedCodeBlock;
}
-UnlinkedEvalCodeBlock* JSGlobalObject::createEvalCodeBlock(CallFrame* callFrame, EvalExecutable* executable)
+UnlinkedEvalCodeBlock* JSGlobalObject::createEvalCodeBlock(CallFrame* callFrame, EvalExecutable* executable, ThisTDZMode thisTDZMode, bool isArrowFunctionContext, const VariableEnvironment* variablesUnderTDZ)
+{
+ ParserError error;
+ JSParserStrictMode strictMode = executable->isStrictMode() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict;
+ DebuggerMode debuggerMode = hasDebugger() ? DebuggerOn : DebuggerOff;
+ ProfilerMode profilerMode = hasLegacyProfiler() ? ProfilerOn : ProfilerOff;
+ UnlinkedEvalCodeBlock* unlinkedCodeBlock = vm().codeCache()->getEvalCodeBlock(
+ vm(), executable, executable->source(), JSParserBuiltinMode::NotBuiltin, strictMode, thisTDZMode, isArrowFunctionContext, debuggerMode, profilerMode, error, variablesUnderTDZ);
+
+ if (hasDebugger())
+ debugger()->sourceParsed(callFrame, executable->source().provider(), error.line(), error.message());
+
+ if (error.isValid()) {
+ throwVMError(callFrame, error.toErrorObject(this, executable->source()));
+ return nullptr;
+ }
+
+ return unlinkedCodeBlock;
+}
+
+UnlinkedModuleProgramCodeBlock* JSGlobalObject::createModuleProgramCodeBlock(CallFrame* callFrame, ModuleProgramExecutable* executable)
{
ParserError error;
- JSParserStrictness strictness = executable->isStrictMode() ? JSParseStrict : JSParseNormal;
DebuggerMode debuggerMode = hasDebugger() ? DebuggerOn : DebuggerOff;
- ProfilerMode profilerMode = hasProfiler() ? ProfilerOn : ProfilerOff;
- UnlinkedEvalCodeBlock* unlinkedCodeBlock = vm().codeCache()->getEvalCodeBlock(vm(), executable, executable->source(), strictness, debuggerMode, profilerMode, error);
+ ProfilerMode profilerMode = hasLegacyProfiler() ? ProfilerOn : ProfilerOff;
+ UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock = vm().codeCache()->getModuleProgramCodeBlock(
+ vm(), executable, executable->source(), JSParserBuiltinMode::NotBuiltin, debuggerMode, profilerMode, error);
if (hasDebugger())
- debugger()->sourceParsed(callFrame, executable->source().provider(), error.m_line, error.m_message);
+ debugger()->sourceParsed(callFrame, executable->source().provider(), error.line(), error.message());
- if (error.m_type != ParserError::ErrorNone) {
+ if (error.isValid()) {
throwVMError(callFrame, error.toErrorObject(this, executable->source()));
- return 0;
+ return nullptr;
}
return unlinkedCodeBlock;
@@ -770,6 +1050,24 @@ bool JSGlobalObject::remoteDebuggingEnabled() const
#endif
}
+#if ENABLE(WEB_REPLAY)
+void JSGlobalObject::setInputCursor(PassRefPtr<InputCursor> prpCursor)
+{
+ m_inputCursor = prpCursor;
+ ASSERT(m_inputCursor);
+
+ InputCursor& cursor = inputCursor();
+ // Save or set the random seed. This performed here rather than the constructor
+ // to avoid threading the input cursor through all the abstraction layers.
+ if (cursor.isCapturing())
+ cursor.appendInput<SetRandomSeed>(m_weakRandom.seed());
+ else if (cursor.isReplaying()) {
+ if (SetRandomSeed* input = cursor.fetchInput<SetRandomSeed>())
+ m_weakRandom.setSeed(static_cast<unsigned>(input->randomSeed()));
+ }
+}
+#endif
+
void JSGlobalObject::setName(const String& name)
{
m_name = name;
@@ -779,12 +1077,55 @@ void JSGlobalObject::setName(const String& name)
#endif
}
+# if ENABLE(INTL)
+const HashSet<String>& JSGlobalObject::intlCollatorAvailableLocales()
+{
+ if (m_intlCollatorAvailableLocales.isEmpty()) {
+ int32_t count = ucol_countAvailable();
+ for (int32_t i = 0; i < count; ++i) {
+ String locale(ucol_getAvailable(i));
+ convertICULocaleToBCP47LanguageTag(locale);
+ m_intlCollatorAvailableLocales.add(locale);
+ }
+ }
+ return m_intlCollatorAvailableLocales;
+}
+
+const HashSet<String>& JSGlobalObject::intlDateTimeFormatAvailableLocales()
+{
+ if (m_intlDateTimeFormatAvailableLocales.isEmpty()) {
+ int32_t count = udat_countAvailable();
+ for (int32_t i = 0; i < count; ++i) {
+ String locale(udat_getAvailable(i));
+ convertICULocaleToBCP47LanguageTag(locale);
+ m_intlDateTimeFormatAvailableLocales.add(locale);
+ }
+ }
+ return m_intlDateTimeFormatAvailableLocales;
+}
+
+const HashSet<String>& JSGlobalObject::intlNumberFormatAvailableLocales()
+{
+ if (m_intlNumberFormatAvailableLocales.isEmpty()) {
+ int32_t count = unum_countAvailable();
+ for (int32_t i = 0; i < count; ++i) {
+ String locale(unum_getAvailable(i));
+ convertICULocaleToBCP47LanguageTag(locale);
+ m_intlNumberFormatAvailableLocales.add(locale);
+ }
+ }
+ return m_intlNumberFormatAvailableLocales;
+}
+#endif // ENABLE(INTL)
+
void JSGlobalObject::queueMicrotask(PassRefPtr<Microtask> task)
{
- if (globalObjectMethodTable()->queueTaskToEventLoop)
+ if (globalObjectMethodTable()->queueTaskToEventLoop) {
globalObjectMethodTable()->queueTaskToEventLoop(this, task);
- else
- WTFLogAlways("ERROR: Event loop not supported.");
+ return;
+ }
+
+ vm().queueMicrotask(this, task);
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h
index b0cad3dc5..37638fd78 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Eric Seidel <eric@webkit.org>
- * Copyright (C) 2007, 2008, 2009, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2014, 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 Library General Public
@@ -23,33 +23,39 @@
#define JSGlobalObject_h
#include "ArrayAllocationProfile.h"
-#include "ConstantMode.h"
+#include "InternalFunction.h"
#include "JSArray.h"
#include "JSArrayBufferPrototype.h"
#include "JSClassRef.h"
+#include "JSGlobalLexicalEnvironment.h"
+#include "JSProxy.h"
#include "JSSegmentedVariableObject.h"
#include "JSWeakObjectMapRefInternal.h"
#include "NumberPrototype.h"
+#include "RuntimeFlags.h"
#include "SpecialPointer.h"
#include "StringPrototype.h"
-#include "StructureChain.h"
-#include "StructureRareDataInlines.h"
+#include "SymbolPrototype.h"
+#include "TemplateRegistry.h"
#include "VM.h"
#include "Watchpoint.h"
#include <JavaScriptCore/JSBase.h>
#include <array>
#include <wtf/HashSet.h>
-#include <wtf/OwnPtr.h>
#include <wtf/PassRefPtr.h>
-#include <wtf/RandomNumber.h>
struct OpaqueJSClass;
struct OpaqueJSClassContextData;
+namespace Inspector {
+class JSGlobalObjectInspectorController;
+}
+
namespace JSC {
class ArrayPrototype;
class BooleanPrototype;
+class ConsoleClient;
class Debugger;
class ErrorConstructor;
class ErrorPrototype;
@@ -58,47 +64,74 @@ class EvalExecutable;
class FunctionCodeBlock;
class FunctionExecutable;
class FunctionPrototype;
+class GeneratorPrototype;
+class GeneratorFunctionPrototype;
class GetterSetter;
class GlobalCodeBlock;
+class InputCursor;
class JSGlobalObjectDebuggable;
+class JSInternalPromise;
+class JSPromise;
class JSPromiseConstructor;
class JSPromisePrototype;
class JSStack;
class LLIntOffsetsExtractor;
class Microtask;
+class ModuleLoaderObject;
+class ModuleProgramExecutable;
class NativeErrorConstructor;
+class NullGetterFunction;
+class NullSetterFunction;
+class ObjectConstructor;
class ProgramCodeBlock;
class ProgramExecutable;
class RegExpConstructor;
class RegExpPrototype;
class SourceCode;
+class UnlinkedModuleProgramCodeBlock;
+class VariableEnvironment;
+enum class ThisTDZMode;
struct ActivationStackNode;
struct HashTable;
#define DEFINE_STANDARD_BUILTIN(macro, upperName, lowerName) macro(upperName, lowerName, lowerName, JS ## upperName, upperName)
-
-#define FOR_EACH_SIMPLE_BUILTIN_TYPE(macro) \
+
+#define FOR_EACH_SIMPLE_BUILTIN_TYPE_WITH_CONSTRUCTOR(macro) \
macro(Set, set, set, JSSet, Set) \
macro(Map, map, map, JSMap, Map) \
macro(Date, date, date, DateInstance, Date) \
macro(String, string, stringObject, StringObject, String) \
+ macro(Symbol, symbol, symbolObject, SymbolObject, Symbol) \
macro(Boolean, boolean, booleanObject, BooleanObject, Boolean) \
macro(Number, number, numberObject, NumberObject, Number) \
macro(Error, error, error, ErrorInstance, Error) \
+ macro(JSPromise, promise, promise, JSPromise, Promise) \
macro(JSArrayBuffer, arrayBuffer, arrayBuffer, JSArrayBuffer, ArrayBuffer) \
DEFINE_STANDARD_BUILTIN(macro, WeakMap, weakMap) \
+ DEFINE_STANDARD_BUILTIN(macro, WeakSet, weakSet) \
+
+#define FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(macro) \
DEFINE_STANDARD_BUILTIN(macro, ArrayIterator, arrayIterator) \
- DEFINE_STANDARD_BUILTIN(macro, ArgumentsIterator, argumentsIterator) \
DEFINE_STANDARD_BUILTIN(macro, MapIterator, mapIterator) \
DEFINE_STANDARD_BUILTIN(macro, SetIterator, setIterator) \
+ DEFINE_STANDARD_BUILTIN(macro, StringIterator, stringIterator) \
+
+#define FOR_EACH_BUILTIN_ITERATOR_TYPE(macro) \
+ DEFINE_STANDARD_BUILTIN(macro, Iterator, iterator) \
+ FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(macro) \
+#define FOR_EACH_SIMPLE_BUILTIN_TYPE(macro) \
+ FOR_EACH_SIMPLE_BUILTIN_TYPE_WITH_CONSTRUCTOR(macro) \
+ macro(JSInternalPromise, internalPromise, internalPromise, JSInternalPromise, InternalPromise) \
#define DECLARE_SIMPLE_BUILTIN_TYPE(capitalName, lowerName, properName, instanceType, jsName) \
class JS ## capitalName; \
class capitalName ## Prototype; \
class capitalName ## Constructor;
+class IteratorPrototype;
FOR_EACH_SIMPLE_BUILTIN_TYPE(DECLARE_SIMPLE_BUILTIN_TYPE)
+FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(DECLARE_SIMPLE_BUILTIN_TYPE)
#undef DECLARE_SIMPLE_BUILTIN_TYPE
@@ -108,8 +141,8 @@ struct GlobalObjectMethodTable {
typedef bool (*AllowsAccessFromFunctionPtr)(const JSGlobalObject*, ExecState*);
AllowsAccessFromFunctionPtr allowsAccessFrom;
- typedef bool (*SupportsProfilingFunctionPtr)(const JSGlobalObject*);
- SupportsProfilingFunctionPtr supportsProfiling;
+ typedef bool (*SupportsLegacyProfilingFunctionPtr)(const JSGlobalObject*);
+ SupportsLegacyProfilingFunctionPtr supportsLegacyProfiling;
typedef bool (*SupportsRichSourceInfoFunctionPtr)(const JSGlobalObject*);
SupportsRichSourceInfoFunctionPtr supportsRichSourceInfo;
@@ -117,14 +150,29 @@ struct GlobalObjectMethodTable {
typedef bool (*ShouldInterruptScriptFunctionPtr)(const JSGlobalObject*);
ShouldInterruptScriptFunctionPtr shouldInterruptScript;
- typedef bool (*JavaScriptExperimentsEnabledFunctionPtr)(const JSGlobalObject*);
- JavaScriptExperimentsEnabledFunctionPtr javaScriptExperimentsEnabled;
+ typedef RuntimeFlags (*JavaScriptRuntimeFlagsFunctionPtr)(const JSGlobalObject*);
+ JavaScriptRuntimeFlagsFunctionPtr javaScriptRuntimeFlags;
typedef void (*QueueTaskToEventLoopFunctionPtr)(const JSGlobalObject*, PassRefPtr<Microtask>);
QueueTaskToEventLoopFunctionPtr queueTaskToEventLoop;
typedef bool (*ShouldInterruptScriptBeforeTimeoutPtr)(const JSGlobalObject*);
ShouldInterruptScriptBeforeTimeoutPtr shouldInterruptScriptBeforeTimeout;
+
+ typedef JSInternalPromise* (*ModuleLoaderResolvePtr)(JSGlobalObject*, ExecState*, JSValue, JSValue);
+ ModuleLoaderResolvePtr moduleLoaderResolve;
+
+ typedef JSInternalPromise* (*ModuleLoaderFetchPtr)(JSGlobalObject*, ExecState*, JSValue);
+ ModuleLoaderFetchPtr moduleLoaderFetch;
+
+ typedef JSInternalPromise* (*ModuleLoaderTranslatePtr)(JSGlobalObject*, ExecState*, JSValue, JSValue);
+ ModuleLoaderTranslatePtr moduleLoaderTranslate;
+
+ typedef JSInternalPromise* (*ModuleLoaderInstantiatePtr)(JSGlobalObject*, ExecState*, JSValue, JSValue);
+ ModuleLoaderInstantiatePtr moduleLoaderInstantiate;
+
+ typedef JSValue (*ModuleLoaderEvaluatePtr)(JSGlobalObject*, ExecState*, JSValue, JSValue);
+ ModuleLoaderEvaluatePtr moduleLoaderEvaluate;
};
class JSGlobalObject : public JSSegmentedVariableObject {
@@ -133,6 +181,8 @@ private:
typedef HashMap<OpaqueJSClass*, std::unique_ptr<OpaqueJSClassContextData>> OpaqueJSClassDataMap;
struct JSGlobalObjectRareData {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
JSGlobalObjectRareData()
: profileGroup(0)
{
@@ -149,6 +199,8 @@ protected:
WriteBarrier<JSObject> m_globalThis;
+ WriteBarrier<JSGlobalLexicalEnvironment> m_globalLexicalEnvironment;
+ WriteBarrier<JSObject> m_globalCallee;
WriteBarrier<RegExpConstructor> m_regExpConstructor;
WriteBarrier<ErrorConstructor> m_errorConstructor;
WriteBarrier<NativeErrorConstructor> m_evalErrorConstructor;
@@ -157,58 +209,87 @@ protected:
WriteBarrier<NativeErrorConstructor> m_syntaxErrorConstructor;
WriteBarrier<NativeErrorConstructor> m_typeErrorConstructor;
WriteBarrier<NativeErrorConstructor> m_URIErrorConstructor;
+ WriteBarrier<ObjectConstructor> m_objectConstructor;
WriteBarrier<JSPromiseConstructor> m_promiseConstructor;
+ WriteBarrier<JSInternalPromiseConstructor> m_internalPromiseConstructor;
+
+ WriteBarrier<NullGetterFunction> m_nullGetterFunction;
+ WriteBarrier<NullSetterFunction> m_nullSetterFunction;
+
+ WriteBarrier<JSFunction> m_parseIntFunction;
WriteBarrier<JSFunction> m_evalFunction;
WriteBarrier<JSFunction> m_callFunction;
WriteBarrier<JSFunction> m_applyFunction;
+ WriteBarrier<JSFunction> m_definePropertyFunction;
+ WriteBarrier<JSFunction> m_arrayProtoValuesFunction;
+ WriteBarrier<JSFunction> m_initializePromiseFunction;
+ WriteBarrier<JSFunction> m_newPromiseCapabilityFunction;
+ WriteBarrier<JSFunction> m_functionProtoHasInstanceSymbolFunction;
WriteBarrier<GetterSetter> m_throwTypeErrorGetterSetter;
+ WriteBarrier<ModuleLoaderObject> m_moduleLoader;
+
WriteBarrier<ObjectPrototype> m_objectPrototype;
WriteBarrier<FunctionPrototype> m_functionPrototype;
WriteBarrier<ArrayPrototype> m_arrayPrototype;
WriteBarrier<RegExpPrototype> m_regExpPrototype;
- WriteBarrier<JSPromisePrototype> m_promisePrototype;
+ WriteBarrier<IteratorPrototype> m_iteratorPrototype;
+ WriteBarrier<GeneratorFunctionPrototype> m_generatorFunctionPrototype;
+ WriteBarrier<GeneratorPrototype> m_generatorPrototype;
+ WriteBarrier<Structure> m_debuggerScopeStructure;
WriteBarrier<Structure> m_withScopeStructure;
WriteBarrier<Structure> m_strictEvalActivationStructure;
- WriteBarrier<Structure> m_activationStructure;
- WriteBarrier<Structure> m_nameScopeStructure;
- WriteBarrier<Structure> m_argumentsStructure;
+ WriteBarrier<Structure> m_lexicalEnvironmentStructure;
+ WriteBarrier<Structure> m_moduleEnvironmentStructure;
+ WriteBarrier<Structure> m_directArgumentsStructure;
+ WriteBarrier<Structure> m_scopedArgumentsStructure;
+ WriteBarrier<Structure> m_outOfBandArgumentsStructure;
// Lists the actual structures used for having these particular indexing shapes.
WriteBarrier<Structure> m_originalArrayStructureForIndexingShape[NumberOfIndexingShapes];
// Lists the structures we should use during allocation for these particular indexing shapes.
+ // These structures will differ from the originals list above when we are having a bad time.
WriteBarrier<Structure> m_arrayStructureForIndexingShapeDuringAllocation[NumberOfIndexingShapes];
WriteBarrier<Structure> m_callbackConstructorStructure;
WriteBarrier<Structure> m_callbackFunctionStructure;
WriteBarrier<Structure> m_callbackObjectStructure;
+ WriteBarrier<Structure> m_propertyNameIteratorStructure;
#if JSC_OBJC_API_ENABLED
WriteBarrier<Structure> m_objcCallbackFunctionStructure;
WriteBarrier<Structure> m_objcWrapperObjectStructure;
#endif
WriteBarrier<Structure> m_nullPrototypeObjectStructure;
+ WriteBarrier<Structure> m_calleeStructure;
WriteBarrier<Structure> m_functionStructure;
WriteBarrier<Structure> m_boundFunctionStructure;
+ WriteBarrier<Structure> m_boundSlotBaseFunctionStructure;
+ WriteBarrier<Structure> m_nativeStdFunctionStructure;
WriteBarrier<Structure> m_namedFunctionStructure;
PropertyOffset m_functionNameOffset;
WriteBarrier<Structure> m_privateNameStructure;
- WriteBarrier<Structure> m_regExpMatchesArrayStructure;
WriteBarrier<Structure> m_regExpStructure;
+ WriteBarrier<Structure> m_generatorFunctionStructure;
+ WriteBarrier<Structure> m_consoleStructure;
+ WriteBarrier<Structure> m_dollarVMStructure;
WriteBarrier<Structure> m_internalFunctionStructure;
-
- WriteBarrier<Structure> m_iteratorResultStructure;
-
-#if ENABLE(PROMISES)
- WriteBarrier<Structure> m_promiseStructure;
-#endif // ENABLE(PROMISES)
+ WriteBarrier<Structure> m_iteratorResultObjectStructure;
+ WriteBarrier<Structure> m_regExpMatchesArrayStructure;
+ WriteBarrier<Structure> m_moduleRecordStructure;
+ WriteBarrier<Structure> m_moduleNamespaceObjectStructure;
+ WriteBarrier<Structure> m_proxyObjectStructure;
+#if ENABLE(WEBASSEMBLY)
+ WriteBarrier<Structure> m_wasmModuleStructure;
+#endif
#define DEFINE_STORAGE_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName) \
WriteBarrier<capitalName ## Prototype> m_ ## lowerName ## Prototype; \
WriteBarrier<Structure> m_ ## properName ## Structure;
FOR_EACH_SIMPLE_BUILTIN_TYPE(DEFINE_STORAGE_FOR_SIMPLE_TYPE)
+ FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(DEFINE_STORAGE_FOR_SIMPLE_TYPE)
#undef DEFINE_STORAGE_FOR_SIMPLE_TYPE
@@ -218,28 +299,45 @@ protected:
};
std::array<TypedArrayData, NUMBER_OF_TYPED_ARRAY_TYPES> m_typedArrays;
-
- void* m_specialPointers[Special::TableSize]; // Special pointers used by the LLInt and JIT.
+
+ JSCell* m_specialPointers[Special::TableSize]; // Special pointers used by the LLInt and JIT.
+ JSCell* m_linkTimeConstants[LinkTimeConstantCount];
String m_name;
Debugger* m_debugger;
+ VM& m_vm;
+
+#if ENABLE(WEB_REPLAY)
+ RefPtr<InputCursor> m_inputCursor;
+#endif
+
#if ENABLE(REMOTE_INSPECTOR)
+ std::unique_ptr<Inspector::JSGlobalObjectInspectorController> m_inspectorController;
std::unique_ptr<JSGlobalObjectDebuggable> m_inspectorDebuggable;
#endif
+#if ENABLE(INTL)
+ HashSet<String> m_intlCollatorAvailableLocales;
+ HashSet<String> m_intlDateTimeFormatAvailableLocales;
+ HashSet<String> m_intlNumberFormatAvailableLocales;
+#endif // ENABLE(INTL)
+
RefPtr<WatchpointSet> m_masqueradesAsUndefinedWatchpoint;
RefPtr<WatchpointSet> m_havingABadTimeWatchpoint;
RefPtr<WatchpointSet> m_varInjectionWatchpoint;
- OwnPtr<JSGlobalObjectRareData> m_rareData;
+ std::unique_ptr<JSGlobalObjectRareData> m_rareData;
WeakRandom m_weakRandom;
+ TemplateRegistry m_templateRegistry;
+
bool m_evalEnabled;
String m_evalDisabledErrorMessage;
- bool m_experimentsEnabled;
+ RuntimeFlags m_runtimeFlags;
+ ConsoleClient* m_consoleClient;
static JS_EXPORTDATA const GlobalObjectMethodTable s_globalObjectMethodTable;
const GlobalObjectMethodTable* m_globalObjectMethodTable;
@@ -248,11 +346,12 @@ protected:
{
if (m_rareData)
return;
- m_rareData = adoptPtr(new JSGlobalObjectRareData);
+ m_rareData = std::make_unique<JSGlobalObjectRareData>();
}
public:
typedef JSSegmentedVariableObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames;
static JSGlobalObject* create(VM& vm, Structure* structure)
{
@@ -265,7 +364,8 @@ public:
DECLARE_EXPORT_INFO;
bool hasDebugger() const { return m_debugger; }
- bool hasProfiler() const { return globalObjectMethodTable()->supportsProfiling(this); }
+ bool hasLegacyProfiler() const;
+ const RuntimeFlags& runtimeFlags() const { return m_runtimeFlags; }
protected:
JS_EXPORT_PRIVATE explicit JSGlobalObject(VM&, Structure*, const GlobalObjectMethodTable* = 0);
@@ -274,23 +374,21 @@ protected:
{
Base::finishCreation(vm);
structure()->setGlobalObject(vm, this);
- m_experimentsEnabled = m_globalObjectMethodTable->javaScriptExperimentsEnabled(this);
- init(this);
+ m_runtimeFlags = m_globalObjectMethodTable->javaScriptRuntimeFlags(this);
+ init(vm);
+ setGlobalThis(vm, JSProxy::create(vm, JSProxy::createStructure(vm, this, prototype(), PureForwardingProxyType), this));
}
void finishCreation(VM& vm, JSObject* thisValue)
{
Base::finishCreation(vm);
structure()->setGlobalObject(vm, this);
- m_experimentsEnabled = m_globalObjectMethodTable->javaScriptExperimentsEnabled(this);
- init(thisValue);
+ m_runtimeFlags = m_globalObjectMethodTable->javaScriptRuntimeFlags(this);
+ init(vm);
+ setGlobalThis(vm, thisValue);
}
- struct NewGlobalVar {
- int registerNumber;
- VariableWatchpointSet* set;
- };
- NewGlobalVar addGlobalVar(const Identifier&, ConstantMode);
+ void addGlobalVar(const Identifier&);
public:
JS_EXPORT_PRIVATE ~JSGlobalObject();
@@ -301,28 +399,21 @@ public:
JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- bool hasOwnPropertyForWrite(ExecState*, PropertyName);
JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
JS_EXPORT_PRIVATE static void defineGetter(JSObject*, ExecState*, PropertyName, JSObject* getterFunc, unsigned attributes);
JS_EXPORT_PRIVATE static void defineSetter(JSObject*, ExecState*, PropertyName, JSObject* setterFunc, unsigned attributes);
JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
- // We use this in the code generator as we perform symbol table
- // lookups prior to initializing the properties
- bool symbolTableHasProperty(PropertyName);
-
void addVar(ExecState* exec, const Identifier& propertyName)
{
if (!hasProperty(exec, propertyName))
- addGlobalVar(propertyName, IsVariable);
+ addGlobalVar(propertyName);
}
- void addConst(ExecState* exec, const Identifier& propertyName)
- {
- if (!hasProperty(exec, propertyName))
- addGlobalVar(propertyName, IsConstant);
- }
- void addFunction(ExecState*, const Identifier&, JSValue);
+ void addFunction(ExecState*, const Identifier&);
+
+ JSScope* globalScope() { return m_globalLexicalEnvironment.get(); }
+ JSGlobalLexicalEnvironment* globalLexicalEnvironment() { return m_globalLexicalEnvironment.get(); }
// The following accessors return pristine values, even if a script
// replaces the global object's associated property.
@@ -330,17 +421,29 @@ public:
RegExpConstructor* regExpConstructor() const { return m_regExpConstructor.get(); }
ErrorConstructor* errorConstructor() const { return m_errorConstructor.get(); }
+ ObjectConstructor* objectConstructor() const { return m_objectConstructor.get(); }
+ JSPromiseConstructor* promiseConstructor() const { return m_promiseConstructor.get(); }
+ JSInternalPromiseConstructor* internalPromiseConstructor() const { return m_internalPromiseConstructor.get(); }
NativeErrorConstructor* evalErrorConstructor() const { return m_evalErrorConstructor.get(); }
NativeErrorConstructor* rangeErrorConstructor() const { return m_rangeErrorConstructor.get(); }
NativeErrorConstructor* referenceErrorConstructor() const { return m_referenceErrorConstructor.get(); }
NativeErrorConstructor* syntaxErrorConstructor() const { return m_syntaxErrorConstructor.get(); }
NativeErrorConstructor* typeErrorConstructor() const { return m_typeErrorConstructor.get(); }
NativeErrorConstructor* URIErrorConstructor() const { return m_URIErrorConstructor.get(); }
- JSPromiseConstructor* promiseConstructor() const { return m_promiseConstructor.get(); }
+
+ NullGetterFunction* nullGetterFunction() const { return m_nullGetterFunction.get(); }
+ NullSetterFunction* nullSetterFunction() const { return m_nullSetterFunction.get(); }
+
+ JSFunction* parseIntFunction() const { return m_parseIntFunction.get(); }
JSFunction* evalFunction() const { return m_evalFunction.get(); }
JSFunction* callFunction() const { return m_callFunction.get(); }
JSFunction* applyFunction() const { return m_applyFunction.get(); }
+ JSFunction* definePropertyFunction() const { return m_definePropertyFunction.get(); }
+ JSFunction* arrayProtoValuesFunction() const { return m_arrayProtoValuesFunction.get(); }
+ JSFunction* initializePromiseFunction() const { return m_initializePromiseFunction.get(); }
+ JSFunction* newPromiseCapabilityFunction() const { return m_newPromiseCapabilityFunction.get(); }
+ JSFunction* functionProtoHasInstanceSymbolFunction() const { return m_functionProtoHasInstanceSymbolFunction.get(); }
GetterSetter* throwTypeErrorGetterSetter(VM& vm)
{
if (!m_throwTypeErrorGetterSetter)
@@ -348,22 +451,30 @@ public:
return m_throwTypeErrorGetterSetter.get();
}
+ ModuleLoaderObject* moduleLoader() const { return m_moduleLoader.get(); }
+
ObjectPrototype* objectPrototype() const { return m_objectPrototype.get(); }
FunctionPrototype* functionPrototype() const { return m_functionPrototype.get(); }
ArrayPrototype* arrayPrototype() const { return m_arrayPrototype.get(); }
BooleanPrototype* booleanPrototype() const { return m_booleanPrototype.get(); }
StringPrototype* stringPrototype() const { return m_stringPrototype.get(); }
+ SymbolPrototype* symbolPrototype() const { return m_symbolPrototype.get(); }
NumberPrototype* numberPrototype() const { return m_numberPrototype.get(); }
DatePrototype* datePrototype() const { return m_datePrototype.get(); }
RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); }
ErrorPrototype* errorPrototype() const { return m_errorPrototype.get(); }
- JSPromisePrototype* promisePrototype() const { return m_promisePrototype.get(); }
+ IteratorPrototype* iteratorPrototype() const { return m_iteratorPrototype.get(); }
+ GeneratorFunctionPrototype* generatorFunctionPrototype() const { return m_generatorFunctionPrototype.get(); }
+ GeneratorPrototype* generatorPrototype() const { return m_generatorPrototype.get(); }
+ Structure* debuggerScopeStructure() const { return m_debuggerScopeStructure.get(); }
Structure* withScopeStructure() const { return m_withScopeStructure.get(); }
Structure* strictEvalActivationStructure() const { return m_strictEvalActivationStructure.get(); }
- Structure* activationStructure() const { return m_activationStructure.get(); }
- Structure* nameScopeStructure() const { return m_nameScopeStructure.get(); }
- Structure* argumentsStructure() const { return m_argumentsStructure.get(); }
+ Structure* activationStructure() const { return m_lexicalEnvironmentStructure.get(); }
+ Structure* moduleEnvironmentStructure() const { return m_moduleEnvironmentStructure.get(); }
+ Structure* directArgumentsStructure() const { return m_directArgumentsStructure.get(); }
+ Structure* scopedArgumentsStructure() const { return m_scopedArgumentsStructure.get(); }
+ Structure* outOfBandArgumentsStructure() const { return m_outOfBandArgumentsStructure.get(); }
Structure* originalArrayStructureForIndexingType(IndexingType indexingType) const
{
ASSERT(indexingType & IsArray);
@@ -374,9 +485,13 @@ public:
ASSERT(indexingType & IsArray);
return m_arrayStructureForIndexingShapeDuringAllocation[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get();
}
- Structure* arrayStructureForProfileDuringAllocation(ArrayAllocationProfile* profile) const
+ Structure* arrayStructureForIndexingTypeDuringAllocation(ExecState* exec, IndexingType indexingType, JSValue newTarget) const
{
- return arrayStructureForIndexingTypeDuringAllocation(ArrayAllocationProfile::selectIndexingTypeFor(profile));
+ return InternalFunction::createSubclassStructure(exec, newTarget, arrayStructureForIndexingTypeDuringAllocation(indexingType));
+ }
+ Structure* arrayStructureForProfileDuringAllocation(ExecState* exec, ArrayAllocationProfile* profile, JSValue newTarget) const
+ {
+ return arrayStructureForIndexingTypeDuringAllocation(exec, ArrayAllocationProfile::selectIndexingTypeFor(profile), newTarget);
}
bool isOriginalArrayStructure(Structure* structure)
@@ -388,6 +503,7 @@ public:
Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); }
Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
Structure* callbackObjectStructure() const { return m_callbackObjectStructure.get(); }
+ Structure* propertyNameIteratorStructure() const { return m_propertyNameIteratorStructure.get(); }
#if JSC_OBJC_API_ENABLED
Structure* objcCallbackFunctionStructure() const { return m_objcCallbackFunctionStructure.get(); }
Structure* objcWrapperObjectStructure() const { return m_objcWrapperObjectStructure.get(); }
@@ -395,28 +511,53 @@ public:
Structure* dateStructure() const { return m_dateStructure.get(); }
Structure* nullPrototypeObjectStructure() const { return m_nullPrototypeObjectStructure.get(); }
Structure* errorStructure() const { return m_errorStructure.get(); }
+ Structure* calleeStructure() const { return m_calleeStructure.get(); }
Structure* functionStructure() const { return m_functionStructure.get(); }
Structure* boundFunctionStructure() const { return m_boundFunctionStructure.get(); }
+ Structure* boundSlotBaseFunctionStructure() const { return m_boundSlotBaseFunctionStructure.get(); }
+ Structure* nativeStdFunctionStructure() const { return m_nativeStdFunctionStructure.get(); }
Structure* namedFunctionStructure() const { return m_namedFunctionStructure.get(); }
PropertyOffset functionNameOffset() const { return m_functionNameOffset; }
Structure* numberObjectStructure() const { return m_numberObjectStructure.get(); }
Structure* privateNameStructure() const { return m_privateNameStructure.get(); }
Structure* internalFunctionStructure() const { return m_internalFunctionStructure.get(); }
Structure* mapStructure() const { return m_mapStructure.get(); }
- Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); }
Structure* regExpStructure() const { return m_regExpStructure.get(); }
+ Structure* generatorFunctionStructure() const { return m_generatorFunctionStructure.get(); }
Structure* setStructure() const { return m_setStructure.get(); }
Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); }
- Structure* iteratorResultStructure() const { return m_iteratorResultStructure.get(); }
- static ptrdiff_t iteratorResultStructureOffset() { return OBJECT_OFFSETOF(JSGlobalObject, m_iteratorResultStructure); }
-
-#if ENABLE(PROMISES)
- Structure* promiseStructure() const { return m_promiseStructure.get(); }
-#endif // ENABLE(PROMISES)
+ Structure* symbolObjectStructure() const { return m_symbolObjectStructure.get(); }
+ Structure* iteratorResultObjectStructure() const { return m_iteratorResultObjectStructure.get(); }
+ Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); }
+ Structure* moduleRecordStructure() const { return m_moduleRecordStructure.get(); }
+ Structure* moduleNamespaceObjectStructure() const { return m_moduleNamespaceObjectStructure.get(); }
+ Structure* proxyObjectStructure() const { return m_proxyObjectStructure.get(); }
+#if ENABLE(WEBASSEMBLY)
+ Structure* wasmModuleStructure() const { return m_wasmModuleStructure.get(); }
+#endif
JS_EXPORT_PRIVATE void setRemoteDebuggingEnabled(bool);
JS_EXPORT_PRIVATE bool remoteDebuggingEnabled() const;
+#if ENABLE(WEB_REPLAY)
+ JS_EXPORT_PRIVATE void setInputCursor(PassRefPtr<InputCursor>);
+ InputCursor& inputCursor() const { return *m_inputCursor; }
+#endif
+
+#if ENABLE(REMOTE_INSPECTOR)
+ Inspector::JSGlobalObjectInspectorController& inspectorController() const { return *m_inspectorController.get(); }
+ JSGlobalObjectDebuggable& inspectorDebuggable() { return *m_inspectorDebuggable.get(); }
+#endif
+
+#if ENABLE(INTL)
+ const HashSet<String>& intlCollatorAvailableLocales();
+ const HashSet<String>& intlDateTimeFormatAvailableLocales();
+ const HashSet<String>& intlNumberFormatAvailableLocales();
+#endif // ENABLE(INTL)
+
+ void setConsoleClient(ConsoleClient* consoleClient) { m_consoleClient = consoleClient; }
+ ConsoleClient* consoleClient() const { return m_consoleClient; }
+
void setName(const String&);
const String& name() const { return m_name; }
@@ -426,6 +567,7 @@ public:
Structure* properName ## Structure() { return m_ ## properName ## Structure.get(); }
FOR_EACH_SIMPLE_BUILTIN_TYPE(DEFINE_ACCESSORS_FOR_SIMPLE_TYPE)
+ FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(DEFINE_ACCESSORS_FOR_SIMPLE_TYPE)
#undef DEFINE_ACCESSORS_FOR_SIMPLE_TYPE
@@ -441,11 +583,17 @@ public:
return typedArrayStructure(type) == structure;
}
- void* actualPointerFor(Special::Pointer pointer)
+ JSCell* actualPointerFor(Special::Pointer pointer)
{
ASSERT(pointer < Special::TableSize);
return m_specialPointers[pointer];
}
+ JSCell* jsCellForLinkTimeConstant(LinkTimeConstant type)
+ {
+ unsigned index = static_cast<unsigned>(type);
+ ASSERT(index < LinkTimeConstantCount);
+ return m_linkTimeConstants[index];
+ }
WatchpointSet* masqueradesAsUndefinedWatchpoint() { return m_masqueradesAsUndefinedWatchpoint.get(); }
WatchpointSet* havingABadTimeWatchpoint() { return m_havingABadTimeWatchpoint.get(); }
@@ -476,14 +624,14 @@ public:
const GlobalObjectMethodTable* globalObjectMethodTable() const { return m_globalObjectMethodTable; }
static bool allowsAccessFrom(const JSGlobalObject*, ExecState*) { return true; }
- static bool supportsProfiling(const JSGlobalObject*) { return false; }
+ static bool supportsLegacyProfiling(const JSGlobalObject*) { return false; }
static bool supportsRichSourceInfo(const JSGlobalObject*) { return true; }
JS_EXPORT_PRIVATE ExecState* globalExec();
static bool shouldInterruptScript(const JSGlobalObject*) { return true; }
static bool shouldInterruptScriptBeforeTimeout(const JSGlobalObject*) { return false; }
- static bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return false; }
+ static RuntimeFlags javaScriptRuntimeFlags(const JSGlobalObject*) { return RuntimeFlags(); }
void queueMicrotask(PassRefPtr<Microtask>);
@@ -497,13 +645,14 @@ public:
void resetPrototype(VM&, JSValue prototype);
- VM& vm() const { return *Heap::heap(this)->vm(); }
+ VM& vm() const { return m_vm; }
JSObject* globalThis() const;
- JS_EXPORT_PRIVATE void setGlobalThis(VM&, JSObject* globalThis);
static Structure* createStructure(VM& vm, JSValue prototype)
{
- return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
+ Structure* result = Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
+ result->setTransitionWatchpointIsLikelyToBeFired(true);
+ return result;
}
void registerWeakMap(OpaqueJSWeakObjectMap* map)
@@ -524,16 +673,17 @@ public:
return m_rareData->opaqueJSClassData;
}
+ TemplateRegistry& templateRegistry() { return m_templateRegistry; }
+
+ static ptrdiff_t weakRandomOffset() { return OBJECT_OFFSETOF(JSGlobalObject, m_weakRandom); }
double weakRandomNumber() { return m_weakRandom.get(); }
unsigned weakRandomInteger() { return m_weakRandom.getUint32(); }
UnlinkedProgramCodeBlock* createProgramCodeBlock(CallFrame*, ProgramExecutable*, JSObject** exception);
- UnlinkedEvalCodeBlock* createEvalCodeBlock(CallFrame*, EvalExecutable*);
+ UnlinkedEvalCodeBlock* createEvalCodeBlock(CallFrame*, EvalExecutable*, ThisTDZMode, bool isArrowFunctionContext, const VariableEnvironment*);
+ UnlinkedModuleProgramCodeBlock* createModuleProgramCodeBlock(CallFrame*, ModuleProgramExecutable*);
protected:
-
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags;
-
struct GlobalPropertyInfo {
GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a)
: identifier(i)
@@ -552,10 +702,10 @@ protected:
private:
friend class LLIntOffsetsExtractor;
-
- // FIXME: Fold reset into init.
- JS_EXPORT_PRIVATE void init(JSObject* thisValue);
- void reset(JSValue prototype);
+
+ JS_EXPORT_PRIVATE void setGlobalThis(VM&, JSObject* globalThis);
+
+ JS_EXPORT_PRIVATE void init(VM&);
void createThrowTypeError(VM&);
@@ -570,59 +720,55 @@ inline JSGlobalObject* asGlobalObject(JSValue value)
return jsCast<JSGlobalObject*>(asObject(value));
}
-inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, PropertyName propertyName)
+inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0, JSValue newTarget = JSValue())
{
- PropertySlot slot(this);
- if (Base::getOwnPropertySlot(this, exec, propertyName, slot))
- return true;
- bool slotIsWriteable;
- return symbolTableGet(this, propertyName, slot, slotIsWriteable);
-}
+ Structure* structure;
+ if (initialLength >= MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)
+ structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(exec, ArrayWithArrayStorage, newTarget);
+ else
+ structure = globalObject->arrayStructureForProfileDuringAllocation(exec, profile, newTarget);
-inline bool JSGlobalObject::symbolTableHasProperty(PropertyName propertyName)
-{
- SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.publicName());
- return !entry.isNull();
+ return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(exec->vm(), structure, initialLength));
}
-inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0)
+inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, unsigned initialLength = 0, JSValue newTarget = JSValue())
{
- return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(exec->vm(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage) : globalObject->arrayStructureForProfileDuringAllocation(profile), initialLength));
+ return constructEmptyArray(exec, profile, exec->lexicalGlobalObject(), initialLength, newTarget);
}
-
-inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, unsigned initialLength = 0)
+
+inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const ArgList& values, JSValue newTarget = JSValue())
{
- return constructEmptyArray(exec, profile, exec->lexicalGlobalObject(), initialLength);
+ return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(exec, profile, newTarget), values));
}
-
-inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const ArgList& values)
+
+inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const ArgList& values, JSValue newTarget = JSValue())
{
- return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values));
+ return constructArray(exec, profile, exec->lexicalGlobalObject(), values, newTarget);
}
-inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const ArgList& values)
+inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length, JSValue newTarget = JSValue())
{
- return constructArray(exec, profile, exec->lexicalGlobalObject(), values);
+ return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(exec, profile, newTarget), values, length));
}
-inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length)
+inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length, JSValue newTarget = JSValue())
{
- return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values, length));
+ return constructArray(exec, profile, exec->lexicalGlobalObject(), values, length, newTarget);
}
-inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length)
+inline JSArray* constructArrayNegativeIndexed(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length, JSValue newTarget = JSValue())
{
- return constructArray(exec, profile, exec->lexicalGlobalObject(), values, length);
+ return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArrayNegativeIndexed(exec, globalObject->arrayStructureForProfileDuringAllocation(exec, profile, newTarget), values, length));
}
-inline JSArray* constructArrayNegativeIndexed(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length)
+inline JSArray* constructArrayNegativeIndexed(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length, JSValue newTarget = JSValue())
{
- return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArrayNegativeIndexed(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values, length));
+ return constructArrayNegativeIndexed(exec, profile, exec->lexicalGlobalObject(), values, length, newTarget);
}
-inline JSArray* constructArrayNegativeIndexed(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length)
+inline JSObject* ExecState::globalThisValue() const
{
- return constructArrayNegativeIndexed(exec, profile, exec->lexicalGlobalObject(), values, length);
+ return lexicalGlobalObject()->globalThis();
}
inline JSObject* JSScope::globalThis()
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.cpp
new file mode 100644
index 000000000..94b964d78
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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 "JSGlobalObjectDebuggable.h"
+
+#if ENABLE(REMOTE_INSPECTOR)
+
+#include "InspectorAgentBase.h"
+#include "InspectorFrontendChannel.h"
+#include "JSGlobalObject.h"
+#include "JSLock.h"
+#include "RemoteInspector.h"
+
+using namespace Inspector;
+
+namespace JSC {
+
+JSGlobalObjectDebuggable::JSGlobalObjectDebuggable(JSGlobalObject& globalObject)
+ : m_globalObject(globalObject)
+{
+}
+
+String JSGlobalObjectDebuggable::name() const
+{
+ String name = m_globalObject.name();
+ return name.isEmpty() ? ASCIILiteral("JSContext") : name;
+}
+
+void JSGlobalObjectDebuggable::connect(FrontendChannel* frontendChannel, bool automaticInspection)
+{
+ JSLockHolder locker(&m_globalObject.vm());
+
+ m_globalObject.inspectorController().connectFrontend(frontendChannel, automaticInspection);
+}
+
+void JSGlobalObjectDebuggable::disconnect(FrontendChannel* frontendChannel)
+{
+ JSLockHolder locker(&m_globalObject.vm());
+
+ m_globalObject.inspectorController().disconnectFrontend(frontendChannel);
+}
+
+void JSGlobalObjectDebuggable::pause()
+{
+ JSLockHolder locker(&m_globalObject.vm());
+
+ m_globalObject.inspectorController().pause();
+}
+
+void JSGlobalObjectDebuggable::dispatchMessageFromRemote(const String& message)
+{
+ JSLockHolder locker(&m_globalObject.vm());
+
+ m_globalObject.inspectorController().dispatchMessageFromFrontend(message);
+}
+
+void JSGlobalObjectDebuggable::pauseWaitingForAutomaticInspection()
+{
+ JSC::JSLock::DropAllLocks dropAllLocks(&m_globalObject.vm());
+ RemoteInspectionTarget::pauseWaitingForAutomaticInspection();
+}
+
+} // namespace JSC
+
+#endif // ENABLE(REMOTE_INSPECTOR)
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.h b/Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.h
new file mode 100644
index 000000000..ea39dc8ff
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGlobalObjectDebuggable.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013, 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.
+ */
+
+#ifndef JSGlobalObjectDebuggable_h
+#define JSGlobalObjectDebuggable_h
+
+#if ENABLE(REMOTE_INSPECTOR)
+
+#include "JSGlobalObjectInspectorController.h"
+#include "RemoteInspectionTarget.h"
+#include <wtf/Noncopyable.h>
+
+namespace Inspector {
+class FrontendChannel;
+enum class DisconnectReason;
+}
+
+namespace JSC {
+
+class JSGlobalObject;
+
+class JSGlobalObjectDebuggable final : public Inspector::RemoteInspectionTarget {
+ WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_NONCOPYABLE(JSGlobalObjectDebuggable);
+public:
+ JSGlobalObjectDebuggable(JSGlobalObject&);
+ ~JSGlobalObjectDebuggable() { }
+
+ virtual Inspector::RemoteControllableTarget::Type type() const override { return Inspector::RemoteControllableTarget::Type::JavaScript; }
+
+ virtual String name() const override;
+ virtual bool hasLocalDebugger() const override { return false; }
+
+ virtual void connect(Inspector::FrontendChannel*, bool automaticInspection) override;
+ virtual void disconnect(Inspector::FrontendChannel*) override;
+ virtual void dispatchMessageFromRemote(const String& message) override;
+ virtual void pause() override;
+
+ virtual bool automaticInspectionAllowed() const override { return true; }
+ virtual void pauseWaitingForAutomaticInspection() override;
+
+private:
+ JSGlobalObject& m_globalObject;
+};
+
+} // namespace JSC
+
+SPECIALIZE_TYPE_TRAITS_CONTROLLABLE_TARGET(JSC::JSGlobalObjectDebuggable, JavaScript);
+
+#endif // ENABLE(REMOTE_INSPECTOR)
+
+#endif // !defined(JSGlobalObjectDebuggable_h)
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
index faecd7e85..ca5e4b31b 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
@@ -26,7 +26,6 @@
#include "JSGlobalObjectFunctions.h"
#include "CallFrame.h"
-#include "CallFrameInlines.h"
#include "Interpreter.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
@@ -35,7 +34,7 @@
#include "Lexer.h"
#include "LiteralParser.h"
#include "Nodes.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "Parser.h"
#include "StackVisitor.h"
#include <wtf/dtoa.h>
@@ -43,6 +42,7 @@
#include <stdlib.h>
#include <wtf/ASCIICType.h>
#include <wtf/Assertions.h>
+#include <wtf/HexNumber.h>
#include <wtf/MathExtras.h>
#include <wtf/StringExtras.h>
#include <wtf/text/StringBuilder.h>
@@ -53,9 +53,18 @@ using namespace Unicode;
namespace JSC {
-static JSValue encode(ExecState* exec, const char* doNotEscape)
+template<unsigned charactersCount>
+static Bitmap<256> makeCharacterBitmap(const char (&characters)[charactersCount])
{
- CString cstr = exec->argument(0).toString(exec)->value(exec).utf8(StrictConversion);
+ Bitmap<256> bitmap;
+ for (unsigned i = 0; i < charactersCount; ++i)
+ bitmap.set(characters[i]);
+ return bitmap;
+}
+
+static JSValue encode(ExecState* exec, const Bitmap<256>& doNotEscape)
+{
+ CString cstr = exec->argument(0).toString(exec)->view(exec).get().utf8(StrictConversion);
if (!cstr.data())
return exec->vm().throwException(exec, createURIError(exec, ASCIILiteral("String contained an illegal UTF-16 sequence.")));
@@ -63,12 +72,11 @@ static JSValue encode(ExecState* exec, const char* doNotEscape)
const char* p = cstr.data();
for (size_t k = 0; k < cstr.length(); k++, p++) {
char c = *p;
- if (c && strchr(doNotEscape, c))
- builder.append(c);
+ if (c && doNotEscape.get(static_cast<LChar>(c)))
+ builder.append(static_cast<LChar>(c));
else {
- char tmp[4];
- snprintf(tmp, sizeof(tmp), "%%%02X", static_cast<unsigned char>(c));
- builder.append(tmp);
+ builder.append(static_cast<LChar>('%'));
+ appendByteAsHex(c, builder);
}
}
return builder.build(exec);
@@ -76,7 +84,7 @@ static JSValue encode(ExecState* exec, const char* doNotEscape)
template <typename CharType>
ALWAYS_INLINE
-static JSValue decode(ExecState* exec, const CharType* characters, int length, const char* doNotUnescape, bool strict)
+static JSValue decode(ExecState* exec, const CharType* characters, int length, const Bitmap<256>& doNotUnescape, bool strict)
{
JSStringBuilder builder;
int k = 0;
@@ -128,11 +136,8 @@ static JSValue decode(ExecState* exec, const CharType* characters, int length, c
u = Lexer<UChar>::convertUnicode(p[2], p[3], p[4], p[5]);
}
}
- if (charLen && (u == 0 || u >= 128 || !strchr(doNotUnescape, u))) {
- if (u < 256)
- builder.append(static_cast<LChar>(u));
- else
- builder.append(u);
+ if (charLen && (u == 0 || u >= 128 || !doNotUnescape.get(static_cast<LChar>(u)))) {
+ builder.append(u);
k += charLen;
continue;
}
@@ -143,10 +148,9 @@ static JSValue decode(ExecState* exec, const CharType* characters, int length, c
return builder.build(exec);
}
-static JSValue decode(ExecState* exec, const char* doNotUnescape, bool strict)
+static JSValue decode(ExecState* exec, const Bitmap<256>& doNotUnescape, bool strict)
{
- JSStringBuilder builder;
- String str = exec->argument(0).toString(exec)->value(exec);
+ JSString::SafeView str = exec->argument(0).toString(exec)->view(exec);
if (str.is8Bit())
return decode(exec, str.characters8(), str.length(), doNotUnescape, strict);
@@ -190,7 +194,7 @@ static int parseDigit(unsigned short c, int radix)
return digit;
}
-double parseIntOverflow(const LChar* s, int length, int radix)
+double parseIntOverflow(const LChar* s, unsigned length, int radix)
{
double number = 0.0;
double radixMultiplier = 1.0;
@@ -212,7 +216,7 @@ double parseIntOverflow(const LChar* s, int length, int radix)
return number;
}
-double parseIntOverflow(const UChar* s, int length, int radix)
+static double parseIntOverflow(const UChar* s, unsigned length, int radix)
{
double number = 0.0;
double radixMultiplier = 1.0;
@@ -234,10 +238,17 @@ double parseIntOverflow(const UChar* s, int length, int radix)
return number;
}
+static double parseIntOverflow(StringView string, int radix)
+{
+ if (string.is8Bit())
+ return parseIntOverflow(string.characters8(), string.length(), radix);
+ return parseIntOverflow(string.characters16(), string.length(), radix);
+}
+
// ES5.1 15.1.2.2
template <typename CharType>
ALWAYS_INLINE
-static double parseInt(const String& s, const CharType* data, int radix)
+static double parseInt(StringView s, const CharType* data, int radix)
{
// 1. Let inputString be ToString(string).
// 2. Let S be a newly created substring of inputString consisting of the first character that is not a
@@ -280,7 +291,7 @@ static double parseInt(const String& s, const CharType* data, int radix)
// 8.a If R < 2 or R > 36, then return NaN.
if (radix < 2 || radix > 36)
- return QNaN;
+ return PNaN;
// 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, using the letters
// A-Z and a-z for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant
@@ -303,22 +314,22 @@ static double parseInt(const String& s, const CharType* data, int radix)
// 12. If Z is empty, return NaN.
if (!sawDigit)
- return QNaN;
+ return PNaN;
// Alternate code path for certain large numbers.
if (number >= mantissaOverflowLowerBound) {
if (radix == 10) {
size_t parsedLength;
- number = parseDouble(s.deprecatedCharacters() + firstDigitPosition, p - firstDigitPosition, parsedLength);
+ number = parseDouble(s.substring(firstDigitPosition, p - firstDigitPosition), parsedLength);
} else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
- number = parseIntOverflow(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), p - firstDigitPosition, radix);
+ number = parseIntOverflow(s.substring(firstDigitPosition, p - firstDigitPosition), radix);
}
// 15. Return sign x number.
return sign * number;
}
-static double parseInt(const String& s, int radix)
+static double parseInt(StringView s, int radix)
{
if (s.is8Bit())
return parseInt(s, s.characters8(), radix);
@@ -341,7 +352,51 @@ static bool isInfinity(const CharType* data, const CharType* end)
&& data[7] == 'y';
}
-// See ecma-262 9.3.1
+// See ecma-262 6th 11.8.3
+template <typename CharType>
+static double jsBinaryIntegerLiteral(const CharType*& data, const CharType* end)
+{
+ // Binary number.
+ data += 2;
+ const CharType* firstDigitPosition = data;
+ double number = 0;
+ while (true) {
+ number = number * 2 + (*data - '0');
+ ++data;
+ if (data == end)
+ break;
+ if (!isASCIIBinaryDigit(*data))
+ break;
+ }
+ if (number >= mantissaOverflowLowerBound)
+ number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 2);
+
+ return number;
+}
+
+// See ecma-262 6th 11.8.3
+template <typename CharType>
+static double jsOctalIntegerLiteral(const CharType*& data, const CharType* end)
+{
+ // Octal number.
+ data += 2;
+ const CharType* firstDigitPosition = data;
+ double number = 0;
+ while (true) {
+ number = number * 8 + (*data - '0');
+ ++data;
+ if (data == end)
+ break;
+ if (!isASCIIOctalDigit(*data))
+ break;
+ }
+ if (number >= mantissaOverflowLowerBound)
+ number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 8);
+
+ return number;
+}
+
+// See ecma-262 6th 11.8.3
template <typename CharType>
static double jsHexIntegerLiteral(const CharType*& data, const CharType* end)
{
@@ -363,7 +418,7 @@ static double jsHexIntegerLiteral(const CharType*& data, const CharType* end)
return number;
}
-// See ecma-262 9.3.1
+// See ecma-262 6th 11.8.3
template <typename CharType>
static double jsStrDecimalLiteral(const CharType*& data, const CharType* end)
{
@@ -401,7 +456,7 @@ static double jsStrDecimalLiteral(const CharType*& data, const CharType* end)
}
// Not a number.
- return QNaN;
+ return PNaN;
}
template <typename CharType>
@@ -420,9 +475,16 @@ static double toDouble(const CharType* characters, unsigned size)
return 0.0;
double number;
- if (characters[0] == '0' && characters + 2 < endCharacters && (characters[1] | 0x20) == 'x' && isASCIIHexDigit(characters[2]))
- number = jsHexIntegerLiteral(characters, endCharacters);
- else
+ if (characters[0] == '0' && characters + 2 < endCharacters) {
+ if ((characters[1] | 0x20) == 'x' && isASCIIHexDigit(characters[2]))
+ number = jsHexIntegerLiteral(characters, endCharacters);
+ else if ((characters[1] | 0x20) == 'o' && isASCIIOctalDigit(characters[2]))
+ number = jsOctalIntegerLiteral(characters, endCharacters);
+ else if ((characters[1] | 0x20) == 'b' && isASCIIBinaryDigit(characters[2]))
+ number = jsBinaryIntegerLiteral(characters, endCharacters);
+ else
+ number = jsStrDecimalLiteral(characters, endCharacters);
+ } else
number = jsStrDecimalLiteral(characters, endCharacters);
// Allow trailing white space.
@@ -431,13 +493,13 @@ static double toDouble(const CharType* characters, unsigned size)
break;
}
if (characters != endCharacters)
- return QNaN;
+ return PNaN;
return number;
}
-// See ecma-262 9.3.1
-double jsToNumber(const String& s)
+// See ecma-262 6th 11.8.3
+double jsToNumber(StringView s)
{
unsigned size = s.length();
@@ -447,7 +509,7 @@ double jsToNumber(const String& s)
return c - '0';
if (isStrWhiteSpace(c))
return 0;
- return QNaN;
+ return PNaN;
}
if (s.is8Bit())
@@ -455,7 +517,7 @@ double jsToNumber(const String& s)
return toDouble(s.characters16(), size);
}
-static double parseFloat(const String& s)
+static double parseFloat(StringView s)
{
unsigned size = s.length();
@@ -463,7 +525,7 @@ static double parseFloat(const String& s)
UChar c = s[0];
if (isASCIIDigit(c))
return c - '0';
- return QNaN;
+ return PNaN;
}
if (s.is8Bit()) {
@@ -478,7 +540,7 @@ static double parseFloat(const String& s)
// Empty string.
if (data == end)
- return QNaN;
+ return PNaN;
return jsStrDecimalLiteral(data, end);
}
@@ -494,7 +556,7 @@ static double parseFloat(const String& s)
// Empty string.
if (data == end)
- return QNaN;
+ return PNaN;
return jsStrDecimalLiteral(data, end);
}
@@ -505,7 +567,15 @@ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
if (!x.isString())
return JSValue::encode(x);
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ if (!globalObject->evalEnabled()) {
+ exec->vm().throwException(exec, createEvalError(exec, globalObject->evalDisabledErrorMessage()));
+ return JSValue::encode(jsUndefined());
+ }
+
String s = x.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
if (s.is8Bit()) {
LiteralParser<LChar> preparser(exec, s.characters8(), s.length(), NonStrictJSON);
@@ -518,11 +588,12 @@ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
}
JSGlobalObject* calleeGlobalObject = exec->callee()->globalObject();
- EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false);
+ VariableEnvironment emptyTDZVariables; // Indirect eval does not have access to the lexical scope.
+ EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false, ThisTDZMode::CheckIfNeeded, DerivedContextType::None, false, &emptyTDZVariables);
if (!eval)
return JSValue::encode(jsUndefined());
- return JSValue::encode(exec->interpreter()->execute(eval, exec, calleeGlobalObject->globalThis(), calleeGlobalObject));
+ return JSValue::encode(exec->interpreter()->execute(eval, exec, calleeGlobalObject->globalThis(), calleeGlobalObject->globalScope()));
}
EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec)
@@ -548,16 +619,16 @@ EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec)
}
// If ToString throws, we shouldn't call ToInt32.
- String s = value.toString(exec)->value(exec);
+ JSString::SafeView s = value.toString(exec)->view(exec);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- return JSValue::encode(jsNumber(parseInt(s, radixValue.toInt32(exec))));
+ return JSValue::encode(jsNumber(parseInt(s.get(), radixValue.toInt32(exec))));
}
EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec)
{
- return JSValue::encode(jsNumber(parseFloat(exec->argument(0).toString(exec)->value(exec))));
+ return JSValue::encode(jsNumber(parseFloat(exec->argument(0).toString(exec)->view(exec).get())));
}
EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState* exec)
@@ -573,59 +644,63 @@ EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState* exec)
EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec)
{
- static const char do_not_unescape_when_decoding_URI[] =
- "#$&+,/:;=?@";
+ static Bitmap<256> doNotUnescapeWhenDecodingURI = makeCharacterBitmap(
+ "#$&+,/:;=?@"
+ );
- return JSValue::encode(decode(exec, do_not_unescape_when_decoding_URI, true));
+ return JSValue::encode(decode(exec, doNotUnescapeWhenDecodingURI, true));
}
EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState* exec)
{
- return JSValue::encode(decode(exec, "", true));
+ static Bitmap<256> emptyBitmap;
+ return JSValue::encode(decode(exec, emptyBitmap, true));
}
EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState* exec)
{
- static const char do_not_escape_when_encoding_URI[] =
+ static Bitmap<256> doNotEscapeWhenEncodingURI = makeCharacterBitmap(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
- "!#$&'()*+,-./:;=?@_~";
+ "!#$&'()*+,-./:;=?@_~"
+ );
- return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI));
+ return JSValue::encode(encode(exec, doNotEscapeWhenEncodingURI));
}
EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState* exec)
{
- static const char do_not_escape_when_encoding_URI_component[] =
+ static Bitmap<256> doNotEscapeWhenEncodingURIComponent = makeCharacterBitmap(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
- "!'()*-._~";
+ "!'()*-._~"
+ );
- return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI_component));
+ return JSValue::encode(encode(exec, doNotEscapeWhenEncodingURIComponent));
}
EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec)
{
- static const char do_not_escape[] =
+ static Bitmap<256> doNotEscape = makeCharacterBitmap(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
- "*+-./@_";
+ "*+-./@_"
+ );
JSStringBuilder builder;
- String str = exec->argument(0).toString(exec)->value(exec);
+ JSString::SafeView str = exec->argument(0).toString(exec)->view(exec);
if (str.is8Bit()) {
const LChar* c = str.characters8();
for (unsigned k = 0; k < str.length(); k++, c++) {
int u = c[0];
- if (u && strchr(do_not_escape, static_cast<char>(u)))
- builder.append(c, 1);
+ if (u && doNotEscape.get(static_cast<LChar>(u)))
+ builder.append(*c);
else {
- char tmp[4];
- snprintf(tmp, sizeof(tmp), "%%%02X", u);
- builder.append(tmp);
+ builder.append(static_cast<LChar>('%'));
+ appendByteAsHex(static_cast<LChar>(u), builder);
}
}
@@ -636,15 +711,15 @@ EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec)
for (unsigned k = 0; k < str.length(); k++, c++) {
int u = c[0];
if (u > 255) {
- char tmp[7];
- snprintf(tmp, sizeof(tmp), "%%u%04X", u);
- builder.append(tmp);
- } else if (u != 0 && strchr(do_not_escape, static_cast<char>(u)))
- builder.append(c, 1);
+ builder.append(static_cast<LChar>('%'));
+ builder.append(static_cast<LChar>('u'));
+ appendByteAsHex(u >> 8, builder);
+ appendByteAsHex(u & 0xFF, builder);
+ } else if (u != 0 && doNotEscape.get(static_cast<LChar>(u)))
+ builder.append(*c);
else {
- char tmp[4];
- snprintf(tmp, sizeof(tmp), "%%%02X", u);
- builder.append(tmp);
+ builder.append(static_cast<LChar>('%'));
+ appendByteAsHex(u, builder);
}
}
@@ -654,7 +729,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec)
EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec)
{
StringBuilder builder;
- String str = exec->argument(0).toString(exec)->value(exec);
+ JSString::SafeView str = exec->argument(0).toString(exec)->view(exec);
int k = 0;
int len = str.length();
@@ -739,6 +814,9 @@ private:
EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState* exec)
{
+ if (exec->thisValue().isUndefinedOrNull())
+ return throwVMError(exec, createTypeError(exec, "Can't convert undefined or null to object"));
+
JSObject* thisObject = jsDynamicCast<JSObject*>(exec->thisValue().toThis(exec, NotStrictMode));
if (!thisObject)
@@ -777,8 +855,18 @@ private:
JSObject* m_thisObject;
};
+bool checkProtoSetterAccessAllowed(ExecState* exec, JSObject* object)
+{
+ GlobalFuncProtoSetterFunctor functor(object);
+ exec->iterate(functor);
+ return functor.allowsAccess();
+}
+
EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState* exec)
{
+ if (exec->thisValue().isUndefinedOrNull())
+ return throwVMError(exec, createTypeError(exec, "Can't convert undefined or null to object"));
+
JSValue value = exec->argument(0);
JSObject* thisObject = jsDynamicCast<JSObject*>(exec->thisValue().toThis(exec, NotStrictMode));
@@ -787,20 +875,27 @@ EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState* exec)
if (!thisObject)
return JSValue::encode(jsUndefined());
- GlobalFuncProtoSetterFunctor functor(thisObject);
- exec->iterate(functor);
- if (!functor.allowsAccess())
+ if (!checkProtoSetterAccessAllowed(exec, thisObject))
return JSValue::encode(jsUndefined());
// Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
if (!value.isObject() && !value.isNull())
return JSValue::encode(jsUndefined());
+ if (thisObject->prototype() == value)
+ return JSValue::encode(jsUndefined());
+
if (!thisObject->isExtensible())
return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
if (!thisObject->setPrototypeWithCycleCheck(exec, value))
- exec->vm().throwException(exec, createError(exec, "cyclic __proto__ value"));
+ exec->vm().throwException(exec, createError(exec, ASCIILiteral("cyclic __proto__ value")));
+ return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL globalFuncBuiltinLog(ExecState* exec)
+{
+ dataLog(exec->argument(0).toWTFString(exec), "\n");
return JSValue::encode(jsUndefined());
}
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h
index f4512e405..b929f5143 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h
@@ -25,7 +25,8 @@
#define JSGlobalObjectFunctions_h
#include "JSCJSValue.h"
-#include <wtf/unicode/Unicode.h>
+#include <unicode/uchar.h>
+#include <wtf/text/LChar.h>
namespace JSC {
@@ -50,13 +51,14 @@ EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState*);
EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeError(ExecState*);
EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState*);
EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState*);
+EncodedJSValue JSC_HOST_CALL globalFuncBuiltinLog(ExecState*);
+
+bool checkProtoSetterAccessAllowed(ExecState*, JSObject*);
static const double mantissaOverflowLowerBound = 9007199254740992.0;
-double parseIntOverflow(const LChar*, int length, int radix);
-ALWAYS_INLINE double parseIntOverflow(const char* s, int length, int radix) { return parseIntOverflow(reinterpret_cast<const LChar*>(s), length, radix); }
-double parseIntOverflow(const UChar*, int length, int radix);
+double parseIntOverflow(const LChar*, unsigned length, int radix);
bool isStrWhiteSpace(UChar);
-double jsToNumber(const WTF::String&);
+double jsToNumber(StringView);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSInternalPromise.cpp b/Source/JavaScriptCore/runtime/JSInternalPromise.cpp
new file mode 100644
index 000000000..093596bad
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSInternalPromise.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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. 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 "JSInternalPromise.h"
+
+#include "BuiltinNames.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+const ClassInfo JSInternalPromise::s_info = { "InternalPromise", &Base::s_info, nullptr, CREATE_METHOD_TABLE(JSInternalPromise) };
+
+JSInternalPromise* JSInternalPromise::create(VM& vm, Structure* structure)
+{
+ JSInternalPromise* promise = new (NotNull, allocateCell<JSInternalPromise>(vm.heap)) JSInternalPromise(vm, structure);
+ promise->finishCreation(vm);
+ return promise;
+}
+
+Structure* JSInternalPromise::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+JSInternalPromise::JSInternalPromise(VM& vm, Structure* structure)
+ : Base(vm, structure)
+{
+}
+
+JSInternalPromise* JSInternalPromise::then(ExecState* exec, JSFunction* onFulfilled, JSFunction* onRejected)
+{
+ JSObject* function = jsCast<JSObject*>(get(exec, exec->propertyNames().builtinNames().thenPublicName()));
+ CallData callData;
+ CallType callType = JSC::getCallData(function, callData);
+ ASSERT(callType != CallTypeNone);
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(onFulfilled ? onFulfilled : jsUndefined());
+ arguments.append(onRejected ? onRejected : jsUndefined());
+
+ return jsCast<JSInternalPromise*>(call(exec, function, callType, callData, this, arguments));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSInternalPromise.h b/Source/JavaScriptCore/runtime/JSInternalPromise.h
new file mode 100644
index 000000000..97cf02e8b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSInternalPromise.h
@@ -0,0 +1,60 @@
+/*
+ * 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. 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.
+ */
+
+#ifndef JSInternalPromise_h
+#define JSInternalPromise_h
+
+#include "JSPromise.h"
+
+namespace JSC {
+
+class JSFunction;
+
+// JSInternalPromise is completely separated instance from the JSPromise.
+// Since its prototype and constructor are different from the exposed Promises' ones,
+// all the user modification onto the exposed Promise does not have effect on JSInternalPromise.
+//
+// e.g.
+// Replacing Promise.prototype.then with the user-customized one does not effect on JSInternalPromise.
+//
+// CAUTION: Must not leak the JSInternalPromise to the user space to keep its integrity.
+class JSInternalPromise : public JSPromise {
+public:
+ typedef JSPromise Base;
+
+ static JSInternalPromise* create(VM&, Structure*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_EXPORT_INFO;
+
+ JS_EXPORT_PRIVATE JSInternalPromise* then(ExecState*, JSFunction* = nullptr, JSFunction* = nullptr);
+
+private:
+ JSInternalPromise(VM&, Structure*);
+};
+
+} // namespace JSC
+
+#endif // JSInternalPromise_h
diff --git a/Source/JavaScriptCore/runtime/JSInternalPromiseConstructor.cpp b/Source/JavaScriptCore/runtime/JSInternalPromiseConstructor.cpp
new file mode 100644
index 000000000..b8c2984b2
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSInternalPromiseConstructor.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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. 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 "JSInternalPromiseConstructor.h"
+
+#include "JSCBuiltins.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSInternalPromise.h"
+#include "JSInternalPromisePrototype.h"
+#include "StructureInlines.h"
+
+#include "JSInternalPromiseConstructor.lut.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSInternalPromiseConstructor);
+
+const ClassInfo JSInternalPromiseConstructor::s_info = { "Function", &Base::s_info, &internalPromiseConstructorTable, CREATE_METHOD_TABLE(JSInternalPromiseConstructor) };
+
+/* Source for JSInternalPromiseConstructor.lut.h
+@begin internalPromiseConstructorTable
+ internalAll JSBuiltin DontEnum|Function 1
+@end
+*/
+
+JSInternalPromiseConstructor* JSInternalPromiseConstructor::create(VM& vm, Structure* structure, JSInternalPromisePrototype* promisePrototype, GetterSetter* speciesSymbol)
+{
+ JSInternalPromiseConstructor* constructor = new (NotNull, allocateCell<JSInternalPromiseConstructor>(vm.heap)) JSInternalPromiseConstructor(vm, structure);
+ constructor->finishCreation(vm, promisePrototype, speciesSymbol);
+ return constructor;
+}
+
+Structure* JSInternalPromiseConstructor::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+JSInternalPromiseConstructor::JSInternalPromiseConstructor(VM& vm, Structure* structure)
+ : Base(vm, structure)
+{
+}
+
+static EncodedJSValue JSC_HOST_CALL constructPromise(ExecState* exec)
+{
+ JSGlobalObject* globalObject = exec->callee()->globalObject();
+ VM& vm = exec->vm();
+ JSInternalPromise* promise = JSInternalPromise::create(vm, globalObject->internalPromiseStructure());
+ promise->initialize(exec, globalObject, exec->argument(0));
+ return JSValue::encode(promise);
+}
+
+ConstructType JSInternalPromiseConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructPromise;
+ return ConstructTypeHost;
+}
+
+CallType JSInternalPromiseConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = constructPromise;
+ return CallTypeHost;
+}
+
+bool JSInternalPromiseConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<Base>(exec, internalPromiseConstructorTable, jsCast<JSInternalPromiseConstructor*>(object), propertyName, slot);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSInternalPromiseConstructor.h b/Source/JavaScriptCore/runtime/JSInternalPromiseConstructor.h
new file mode 100644
index 000000000..db871bee0
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSInternalPromiseConstructor.h
@@ -0,0 +1,55 @@
+/*
+ * 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. 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.
+ */
+
+#ifndef JSInternalPromiseConstructor_h
+#define JSInternalPromiseConstructor_h
+
+#include "JSPromiseConstructor.h"
+
+namespace JSC {
+
+class JSInternalPromise;
+class JSInternalPromisePrototype;
+
+class JSInternalPromiseConstructor : public JSPromiseConstructor {
+public:
+ typedef JSPromiseConstructor Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static JSInternalPromiseConstructor* create(VM&, Structure*, JSInternalPromisePrototype*, GetterSetter*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+private:
+ JSInternalPromiseConstructor(VM&, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+};
+
+} // namespace JSC
+
+#endif // JSInternalPromiseConstructor_h
diff --git a/Source/JavaScriptCore/runtime/JSInternalPromiseDeferred.cpp b/Source/JavaScriptCore/runtime/JSInternalPromiseDeferred.cpp
new file mode 100644
index 000000000..fefdecdf0
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSInternalPromiseDeferred.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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. 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 "JSInternalPromiseDeferred.h"
+
+#include "BuiltinNames.h"
+#include "Error.h"
+#include "Exception.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSInternalPromise.h"
+#include "JSInternalPromiseConstructor.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+const ClassInfo JSInternalPromiseDeferred::s_info = { "JSInternalPromiseDeferred", &Base::s_info, nullptr, CREATE_METHOD_TABLE(JSInternalPromiseDeferred) };
+
+JSInternalPromiseDeferred* JSInternalPromiseDeferred::create(ExecState* exec, JSGlobalObject* globalObject)
+{
+ VM& vm = exec->vm();
+
+ JSValue deferred = newPromiseCapability(exec, globalObject, globalObject->internalPromiseConstructor());
+
+ JSValue promise = deferred.get(exec, vm.propertyNames->promisePrivateName);
+ ASSERT(promise.inherits(JSInternalPromise::info()));
+ JSValue resolve = deferred.get(exec, vm.propertyNames->builtinNames().resolvePrivateName());
+ JSValue reject = deferred.get(exec, vm.propertyNames->builtinNames().rejectPrivateName());
+
+ JSInternalPromiseDeferred* result = new (NotNull, allocateCell<JSInternalPromiseDeferred>(vm.heap)) JSInternalPromiseDeferred(vm);
+ result->finishCreation(vm, jsCast<JSObject*>(promise), resolve, reject);
+ return result;
+}
+
+JSInternalPromiseDeferred::JSInternalPromiseDeferred(VM& vm)
+ : Base(vm, vm.internalPromiseDeferredStructure.get())
+{
+}
+
+JSInternalPromise* JSInternalPromiseDeferred::promise() const
+{
+ return jsCast<JSInternalPromise*>(Base::promise());
+}
+
+JSInternalPromise* JSInternalPromiseDeferred::resolve(ExecState* exec, JSValue value)
+{
+ Base::resolve(exec, value);
+ return promise();
+}
+
+JSInternalPromise* JSInternalPromiseDeferred::reject(ExecState* exec, JSValue reason)
+{
+ Base::reject(exec, reason);
+ return promise();
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSPromiseReaction.h b/Source/JavaScriptCore/runtime/JSInternalPromiseDeferred.h
index fc7146c50..662a27740 100644
--- a/Source/JavaScriptCore/runtime/JSPromiseReaction.h
+++ b/Source/JavaScriptCore/runtime/JSInternalPromiseDeferred.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * 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
@@ -23,46 +23,37 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef JSPromiseReaction_h
-#define JSPromiseReaction_h
+#ifndef JSInternalPromiseDeferred_h
+#define JSInternalPromiseDeferred_h
-#include "JSCell.h"
-#include "Structure.h"
+#include "JSPromiseDeferred.h"
namespace JSC {
-class JSPromiseDeferred;
-class Microtask;
+class JSInternalPromise;
-class JSPromiseReaction : public JSCell {
+class JSInternalPromiseDeferred final : public JSPromiseDeferred {
public:
- typedef JSCell Base;
+ typedef JSPromiseDeferred Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+ JS_EXPORT_PRIVATE static JSInternalPromiseDeferred* create(ExecState*, JSGlobalObject*);
- static JSPromiseReaction* create(VM&, JSPromiseDeferred*, JSValue);
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), info());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
}
- static const bool hasImmortalStructure = true;
-
- DECLARE_INFO;
+ DECLARE_EXPORT_INFO;
- JSPromiseDeferred* deferred() const { return m_deferred.get(); }
- JSValue handler() const { return m_handler.get(); }
+ JS_EXPORT_PRIVATE JSInternalPromise* promise() const;
+ JS_EXPORT_PRIVATE JSInternalPromise* resolve(ExecState*, JSValue);
+ JS_EXPORT_PRIVATE JSInternalPromise* reject(ExecState*, JSValue);
private:
- JSPromiseReaction(VM&);
- void finishCreation(VM&, JSPromiseDeferred*, JSValue);
- static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
- static void visitChildren(JSCell*, SlotVisitor&);
-
- WriteBarrier<JSPromiseDeferred> m_deferred;
- WriteBarrier<Unknown> m_handler;
+ JSInternalPromiseDeferred(VM&);
};
-PassRefPtr<Microtask> createExecutePromiseReactionMicrotask(VM&, JSPromiseReaction*, JSValue);
-
} // namespace JSC
-#endif // JSPromiseReaction_h
+#endif // JSInternalPromiseDeferred_h
diff --git a/Source/JavaScriptCore/runtime/JSInternalPromisePrototype.cpp b/Source/JavaScriptCore/runtime/JSInternalPromisePrototype.cpp
new file mode 100644
index 000000000..ecedfaff3
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSInternalPromisePrototype.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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. 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 "JSInternalPromisePrototype.h"
+
+#include "Error.h"
+#include "JSCBuiltins.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSGlobalObject.h"
+#include "JSInternalPromise.h"
+#include "Microtask.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSInternalPromisePrototype);
+
+const ClassInfo JSInternalPromisePrototype::s_info = { "InternalPromisePrototype", &Base::s_info, nullptr, CREATE_METHOD_TABLE(JSInternalPromisePrototype) };
+
+JSInternalPromisePrototype* JSInternalPromisePrototype::create(VM& vm, JSGlobalObject*, Structure* structure)
+{
+ JSInternalPromisePrototype* object = new (NotNull, allocateCell<JSInternalPromisePrototype>(vm.heap)) JSInternalPromisePrototype(vm, structure);
+ object->finishCreation(vm, structure);
+ return object;
+}
+
+Structure* JSInternalPromisePrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+JSInternalPromisePrototype::JSInternalPromisePrototype(VM& vm, Structure* structure)
+ : Base(vm, structure)
+{
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSInternalPromisePrototype.h b/Source/JavaScriptCore/runtime/JSInternalPromisePrototype.h
new file mode 100644
index 000000000..5d36e9e85
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSInternalPromisePrototype.h
@@ -0,0 +1,49 @@
+/*
+ * 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. 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.
+ */
+
+#ifndef JSInternalPromisePrototype_h
+#define JSInternalPromisePrototype_h
+
+#include "JSPromisePrototype.h"
+
+namespace JSC {
+
+class JSInternalPromisePrototype : public JSPromisePrototype {
+public:
+ typedef JSPromisePrototype Base;
+ static const unsigned StructureFlags = Base::StructureFlags;
+
+ static JSInternalPromisePrototype* create(VM&, JSGlobalObject*, Structure*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ DECLARE_INFO;
+
+private:
+ JSInternalPromisePrototype(VM&, Structure*);
+};
+
+} // namespace JSC
+
+#endif // JSInternalPromisePrototype_h
diff --git a/Source/JavaScriptCore/runtime/JSJob.cpp b/Source/JavaScriptCore/runtime/JSJob.cpp
new file mode 100644
index 000000000..8827acfa7
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSJob.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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. 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 "JSJob.h"
+
+#include "Error.h"
+#include "Exception.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSGlobalObject.h"
+#include "Microtask.h"
+#include "SlotVisitorInlines.h"
+#include "StrongInlines.h"
+
+namespace JSC {
+
+class JSJobMicrotask final : public Microtask {
+public:
+ JSJobMicrotask(VM& vm, JSValue job, JSArray* arguments)
+ {
+ m_job.set(vm, job);
+ m_arguments.set(vm, arguments);
+ }
+
+ virtual ~JSJobMicrotask()
+ {
+ }
+
+private:
+ virtual void run(ExecState*) override;
+
+ Strong<Unknown> m_job;
+ Strong<JSArray> m_arguments;
+};
+
+Ref<Microtask> createJSJob(VM& vm, JSValue job, JSArray* arguments)
+{
+ return adoptRef(*new JSJobMicrotask(vm, job, arguments));
+}
+
+void JSJobMicrotask::run(ExecState* exec)
+{
+ CallData handlerCallData;
+ CallType handlerCallType = getCallData(m_job.get(), handlerCallData);
+ ASSERT(handlerCallType != CallTypeNone);
+
+ MarkedArgumentBuffer handlerArguments;
+ for (unsigned index = 0, length = m_arguments->length(); index < length; ++index)
+ handlerArguments.append(m_arguments->JSArray::get(exec, index));
+ profiledCall(exec, ProfilingReason::Microtask, m_job.get(), handlerCallType, handlerCallData, jsUndefined(), handlerArguments);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSPromiseFunctions.h b/Source/JavaScriptCore/runtime/JSJob.h
index 802121905..0147c836e 100644
--- a/Source/JavaScriptCore/runtime/JSPromiseFunctions.h
+++ b/Source/JavaScriptCore/runtime/JSJob.h
@@ -23,25 +23,19 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef JSPromiseFunctions_h
-#define JSPromiseFunctions_h
+#ifndef JSJob_h
+#define JSJob_h
-#if ENABLE(PROMISES)
-
-#include "JSFunction.h"
+#include "JSCell.h"
+#include "Structure.h"
namespace JSC {
-JSFunction* createDeferredConstructionFunction(VM&, JSGlobalObject*);
-JSFunction* createIdentifyFunction(VM&, JSGlobalObject*);
-JSFunction* createPromiseAllCountdownFunction(VM&, JSGlobalObject*);
-JSFunction* createPromiseResolutionHandlerFunction(VM&, JSGlobalObject*);
-JSFunction* createRejectPromiseFunction(VM&, JSGlobalObject*);
-JSFunction* createResolvePromiseFunction(VM&, JSGlobalObject*);
-JSFunction* createThrowerFunction(VM&, JSGlobalObject*);
+class Microtask;
+class JSArray;
-} // namespace JSC
+Ref<Microtask> createJSJob(VM&, JSValue job, JSArray* arguments);
-#endif // ENABLE(PROMISES)
+} // namespace JSC
-#endif // JSPromiseFunctions_h
+#endif // JSJob_h
diff --git a/Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp b/Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp
new file mode 100644
index 000000000..e99bbba89
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSLexicalEnvironment.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2008, 2009, 2014, 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.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "JSLexicalEnvironment.h"
+
+#include "Interpreter.h"
+#include "JSFunction.h"
+#include "JSCInlines.h"
+
+using namespace std;
+
+namespace JSC {
+
+const ClassInfo JSLexicalEnvironment::s_info = { "JSLexicalEnvironment", &Base::s_info, 0, CREATE_METHOD_TABLE(JSLexicalEnvironment) };
+
+void JSLexicalEnvironment::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ JSLexicalEnvironment* thisObject = jsCast<JSLexicalEnvironment*>(object);
+
+ {
+ ConcurrentJITLocker locker(thisObject->symbolTable()->m_lock);
+ SymbolTable::Map::iterator end = thisObject->symbolTable()->end(locker);
+ for (SymbolTable::Map::iterator it = thisObject->symbolTable()->begin(locker); it != end; ++it) {
+ if (it->value.getAttributes() & DontEnum && !mode.includeDontEnumProperties())
+ continue;
+ if (!thisObject->isValidScopeOffset(it->value.scopeOffset()))
+ continue;
+ if (it->key->isSymbol() && !propertyNames.includeSymbolProperties())
+ continue;
+ propertyNames.add(Identifier::fromUid(exec, it->key.get()));
+ }
+ }
+ // Skip the JSEnvironmentRecord implementation of getOwnNonIndexPropertyNames
+ JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode);
+}
+
+bool JSLexicalEnvironment::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ JSLexicalEnvironment* thisObject = jsCast<JSLexicalEnvironment*>(object);
+
+ if (symbolTableGet(thisObject, propertyName, slot))
+ return true;
+
+ unsigned attributes;
+ if (JSValue value = thisObject->getDirect(exec->vm(), propertyName, attributes)) {
+ slot.setValue(thisObject, attributes, value);
+ return true;
+ }
+
+ // We don't call through to JSObject because there's no way to give a
+ // lexical environment object getter properties or a prototype.
+ ASSERT(!thisObject->hasGetterSetterProperties());
+ ASSERT(thisObject->prototype().isNull());
+ return false;
+}
+
+void JSLexicalEnvironment::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
+ JSLexicalEnvironment* thisObject = jsCast<JSLexicalEnvironment*>(cell);
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
+
+ bool shouldThrowReadOnlyError = slot.isStrictMode() || thisObject->isLexicalScope();
+ bool ignoreReadOnlyErrors = false;
+ if (symbolTablePutInvalidateWatchpointSet(thisObject, exec, propertyName, value, shouldThrowReadOnlyError, ignoreReadOnlyErrors))
+ return;
+
+ // We don't call through to JSObject because __proto__ and getter/setter
+ // properties are non-standard extensions that other implementations do not
+ // expose in the lexicalEnvironment object.
+ ASSERT(!thisObject->hasGetterSetterProperties());
+ thisObject->putOwnDataProperty(exec->vm(), propertyName, value, slot);
+}
+
+bool JSLexicalEnvironment::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
+{
+ if (propertyName == exec->propertyNames().arguments)
+ return false;
+
+ return Base::deleteProperty(cell, exec, propertyName);
+}
+
+JSValue JSLexicalEnvironment::toThis(JSCell*, ExecState* exec, ECMAMode ecmaMode)
+{
+ if (ecmaMode == StrictMode)
+ return jsUndefined();
+ return exec->globalThisValue();
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSLexicalEnvironment.h b/Source/JavaScriptCore/runtime/JSLexicalEnvironment.h
new file mode 100644
index 000000000..c40ae8739
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSLexicalEnvironment.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2008, 2009, 2013-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.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ */
+
+#ifndef JSLexicalEnvironment_h
+#define JSLexicalEnvironment_h
+
+#include "CodeBlock.h"
+#include "CopiedSpaceInlines.h"
+#include "JSEnvironmentRecord.h"
+#include "SymbolTable.h"
+
+namespace JSC {
+
+class Register;
+
+class JSLexicalEnvironment : public JSEnvironmentRecord {
+protected:
+ JSLexicalEnvironment(VM&, Structure*, JSScope*, SymbolTable*);
+
+public:
+ typedef JSEnvironmentRecord Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames;
+
+ static JSLexicalEnvironment* create(
+ VM& vm, Structure* structure, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue)
+ {
+ JSLexicalEnvironment* result =
+ new (
+ NotNull,
+ allocateCell<JSLexicalEnvironment>(vm.heap, allocationSize(symbolTable)))
+ JSLexicalEnvironment(vm, structure, currentScope, symbolTable);
+ result->finishCreation(vm, initialValue);
+ return result;
+ }
+
+ static JSLexicalEnvironment* create(VM& vm, JSGlobalObject* globalObject, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue)
+ {
+ Structure* structure = globalObject->activationStructure();
+ return create(vm, structure, currentScope, symbolTable, initialValue);
+ }
+
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+
+ static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+
+ static bool deleteProperty(JSCell*, ExecState*, PropertyName);
+
+ static JSValue toThis(JSCell*, ExecState*, ECMAMode);
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject) { return Structure::create(vm, globalObject, jsNull(), TypeInfo(ClosureObjectType, StructureFlags), info()); }
+};
+
+inline JSLexicalEnvironment::JSLexicalEnvironment(VM& vm, Structure* structure, JSScope* currentScope, SymbolTable* symbolTable)
+ : Base(vm, structure, currentScope, symbolTable)
+{
+}
+
+inline JSLexicalEnvironment* asActivation(JSValue value)
+{
+ ASSERT(asObject(value)->inherits(JSLexicalEnvironment::info()));
+ return jsCast<JSLexicalEnvironment*>(asObject(value));
+}
+
+} // namespace JSC
+
+#endif // JSLexicalEnvironment_h
diff --git a/Source/JavaScriptCore/runtime/JSLock.cpp b/Source/JavaScriptCore/runtime/JSLock.cpp
index 7604075f8..a2eff3c29 100644
--- a/Source/JavaScriptCore/runtime/JSLock.cpp
+++ b/Source/JavaScriptCore/runtime/JSLock.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005, 2008, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2008, 2012, 2014 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
@@ -25,33 +25,26 @@
#include "CallFrame.h"
#include "JSGlobalObject.h"
#include "JSObject.h"
-#include "Operations.h"
-
-#if USE(PTHREADS)
-#include <pthread.h>
-#endif
+#include "JSCInlines.h"
+#include "SamplingProfiler.h"
+#include <thread>
namespace JSC {
-Mutex* GlobalJSLock::s_sharedInstanceLock = 0;
+StaticLock GlobalJSLock::s_sharedInstanceMutex;
GlobalJSLock::GlobalJSLock()
{
- s_sharedInstanceLock->lock();
+ s_sharedInstanceMutex.lock();
}
GlobalJSLock::~GlobalJSLock()
{
- s_sharedInstanceLock->unlock();
-}
-
-void GlobalJSLock::initialize()
-{
- s_sharedInstanceLock = new Mutex();
+ s_sharedInstanceMutex.unlock();
}
JSLockHolder::JSLockHolder(ExecState* exec)
- : m_vm(exec ? &exec->vm() : 0)
+ : m_vm(&exec->vm())
{
init();
}
@@ -70,27 +63,24 @@ JSLockHolder::JSLockHolder(VM& vm)
void JSLockHolder::init()
{
- if (m_vm)
- m_vm->apiLock().lock();
+ m_vm->apiLock().lock();
}
JSLockHolder::~JSLockHolder()
{
- if (!m_vm)
- return;
-
RefPtr<JSLock> apiLock(&m_vm->apiLock());
- m_vm.clear();
+ m_vm = nullptr;
apiLock->unlock();
}
JSLock::JSLock(VM* vm)
- : m_ownerThread(0)
+ : m_ownerThreadID(std::thread::id())
, m_lockCount(0)
, m_lockDropDepth(0)
+ , m_hasExclusiveThread(false)
, m_vm(vm)
+ , m_entryAtomicStringTable(nullptr)
{
- m_spinLock.Init();
}
JSLock::~JSLock()
@@ -100,39 +90,104 @@ JSLock::~JSLock()
void JSLock::willDestroyVM(VM* vm)
{
ASSERT_UNUSED(vm, m_vm == vm);
- m_vm = 0;
+ m_vm = nullptr;
+}
+
+void JSLock::setExclusiveThread(std::thread::id threadId)
+{
+ RELEASE_ASSERT(!m_lockCount && m_ownerThreadID == std::thread::id());
+ m_hasExclusiveThread = (threadId != std::thread::id());
+ m_ownerThreadID = threadId;
}
void JSLock::lock()
{
- ThreadIdentifier currentThread = WTF::currentThread();
- {
- SpinLockHolder holder(&m_spinLock);
- if (m_ownerThread == currentThread && m_lockCount) {
- m_lockCount++;
- return;
- }
- }
+ lock(1);
+}
- m_lock.lock();
+void JSLock::lock(intptr_t lockCount)
+{
+ ASSERT(lockCount > 0);
+ if (currentThreadIsHoldingLock()) {
+ m_lockCount += lockCount;
+ return;
+ }
- {
- SpinLockHolder holder(&m_spinLock);
- m_ownerThread = currentThread;
- ASSERT(!m_lockCount);
- m_lockCount = 1;
+ if (!m_hasExclusiveThread) {
+ m_lock.lock();
+ m_ownerThreadID = std::this_thread::get_id();
}
+ ASSERT(!m_lockCount);
+ m_lockCount = lockCount;
+
+ didAcquireLock();
+}
+
+void JSLock::didAcquireLock()
+{
+ // FIXME: What should happen to the per-thread identifier table if we don't have a VM?
+ if (!m_vm)
+ return;
+
+ RELEASE_ASSERT(!m_vm->stackPointerAtVMEntry());
+ void* p = &p; // A proxy for the current stack pointer.
+ m_vm->setStackPointerAtVMEntry(p);
+
+ WTFThreadData& threadData = wtfThreadData();
+ m_vm->setLastStackTop(threadData.savedLastStackTop());
+
+ ASSERT(!m_entryAtomicStringTable);
+ m_entryAtomicStringTable = threadData.setCurrentAtomicStringTable(m_vm->atomicStringTable());
+ ASSERT(m_entryAtomicStringTable);
+
+ m_vm->heap.machineThreads().addCurrentThread();
+
+#if ENABLE(SAMPLING_PROFILER)
+ // Note: this must come after addCurrentThread().
+ if (SamplingProfiler* samplingProfiler = m_vm->samplingProfiler())
+ samplingProfiler->noticeJSLockAcquisition();
+#endif
}
void JSLock::unlock()
{
- SpinLockHolder holder(&m_spinLock);
- ASSERT(currentThreadIsHoldingLock());
+ unlock(1);
+}
+
+void JSLock::unlock(intptr_t unlockCount)
+{
+ RELEASE_ASSERT(currentThreadIsHoldingLock());
+ ASSERT(m_lockCount >= unlockCount);
+
+ // Maintain m_lockCount while calling willReleaseLock() so that its callees know that
+ // they still have the lock.
+ if (unlockCount == m_lockCount)
+ willReleaseLock();
+
+ m_lockCount -= unlockCount;
+
+ if (!m_lockCount) {
+
+ if (!m_hasExclusiveThread) {
+ m_ownerThreadID = std::thread::id();
+ m_lock.unlock();
+ }
+ }
+}
+
+void JSLock::willReleaseLock()
+{
+ if (m_vm) {
+ m_vm->drainMicrotasks();
- m_lockCount--;
+ m_vm->heap.releaseDelayedReleasedObjects();
+ m_vm->setStackPointerAtVMEntry(nullptr);
+ }
- if (!m_lockCount)
- m_lock.unlock();
+ if (m_entryAtomicStringTable) {
+ wtfThreadData().setCurrentAtomicStringTable(m_entryAtomicStringTable);
+ m_entryAtomicStringTable = nullptr;
+ }
}
void JSLock::lock(ExecState* exec)
@@ -147,180 +202,91 @@ void JSLock::unlock(ExecState* exec)
bool JSLock::currentThreadIsHoldingLock()
{
- return m_lockCount && m_ownerThread == WTF::currentThread();
+ ASSERT(!m_hasExclusiveThread || (exclusiveThread() == std::this_thread::get_id()));
+ if (m_hasExclusiveThread)
+ return !!m_lockCount;
+ return m_ownerThreadID == std::this_thread::get_id();
}
-// This is fairly nasty. We allow multiple threads to run on the same
-// context, and we do not require any locking semantics in doing so -
-// clients of the API may simply use the context from multiple threads
-// concurently, and assume this will work. In order to make this work,
-// We lock the context when a thread enters, and unlock it when it leaves.
-// However we do not only unlock when the thread returns from its
-// entry point (evaluate script or call function), we also unlock the
-// context if the thread leaves JSC by making a call out to an external
-// function through a callback.
-//
-// All threads using the context share the same JS stack (the JSStack).
-// Whenever a thread calls into JSC it starts using the JSStack from the
-// previous 'high water mark' - the maximum point the stack has ever grown to
-// (returned by JSStack::end()). So if a first thread calls out to a
-// callback, and a second thread enters JSC, then also exits by calling out
-// to a callback, we can be left with stackframes from both threads in the
-// JSStack. As such, a problem may occur should the first thread's
-// callback complete first, and attempt to return to JSC. Were we to allow
-// this to happen, and were its stack to grow further, then it may potentially
-// write over the second thread's call frames.
-//
-// To avoid JS stack corruption we enforce a policy of only ever allowing two
-// threads to use a JS context concurrently, and only allowing the second of
-// these threads to execute until it has completed and fully returned from its
-// outermost call into JSC. We enforce this policy using 'lockDropDepth'. The
-// first time a thread exits it will call DropAllLocks - which will do as expected
-// and drop locks allowing another thread to enter. Should another thread, or the
-// same thread again, enter JSC (through evaluate script or call function), and exit
-// again through a callback, then the locks will not be dropped when DropAllLocks
-// is called (since lockDropDepth is non-zero). Since this thread is still holding
-// the locks, only it will be able to re-enter JSC (either be returning from the
-// callback, or by re-entering through another call to evaulate script or call
-// function).
-//
-// This policy is slightly more restricive than it needs to be for correctness -
-// we could validly allow futher entries into JSC from other threads, we only
-// need ensure that callbacks return in the reverse chronological order of the
-// order in which they were made - though implementing the less restrictive policy
-// would likely increase complexity and overhead.
-//
-
// This function returns the number of locks that were dropped.
-unsigned JSLock::dropAllLocks(SpinLock& spinLock)
+unsigned JSLock::dropAllLocks(DropAllLocks* dropper)
{
-#if PLATFORM(IOS)
- ASSERT_UNUSED(spinLock, spinLock.IsHeld());
- // Check if this thread is currently holding the lock.
- // FIXME: Maybe we want to require this, guard with an ASSERT?
- unsigned lockCount = m_lockCount;
- if (!lockCount || m_ownerThread != WTF::currentThread())
+ if (m_hasExclusiveThread) {
+ ASSERT(exclusiveThread() == std::this_thread::get_id());
return 0;
+ }
- // Don't drop the locks if they've already been dropped once.
- // (If the prior drop came from another thread, and it resumed first,
- // it could trash our register file).
- if (m_lockDropDepth)
+ if (!currentThreadIsHoldingLock())
return 0;
- // m_lockDropDepth is only incremented if any locks were dropped.
++m_lockDropDepth;
- m_lockCount = 0;
- m_lock.unlock();
- return lockCount;
-#else
- if (m_lockDropDepth++)
- return 0;
- return dropAllLocksUnconditionally(spinLock);
-#endif
-}
+ dropper->setDropDepth(m_lockDropDepth);
-unsigned JSLock::dropAllLocksUnconditionally(SpinLock& spinLock)
-{
-#if PLATFORM(IOS)
- ASSERT_UNUSED(spinLock, spinLock.IsHeld());
- // Check if this thread is currently holding the lock.
- // FIXME: Maybe we want to require this, guard with an ASSERT?
- unsigned lockCount = m_lockCount;
- if (!lockCount || m_ownerThread != WTF::currentThread())
- return 0;
+ WTFThreadData& threadData = wtfThreadData();
+ threadData.setSavedStackPointerAtVMEntry(m_vm->stackPointerAtVMEntry());
+ threadData.setSavedLastStackTop(m_vm->lastStackTop());
- // m_lockDropDepth is only incremented if any locks were dropped.
- ++m_lockDropDepth;
- m_lockCount = 0;
- m_lock.unlock();
- return lockCount;
-#else
- UNUSED_PARAM(spinLock);
- unsigned lockCount = m_lockCount;
- for (unsigned i = 0; i < lockCount; ++i)
- unlock();
-
- return lockCount;
-#endif
+ unsigned droppedLockCount = m_lockCount;
+ unlock(droppedLockCount);
+
+ return droppedLockCount;
}
-void JSLock::grabAllLocks(unsigned lockCount, SpinLock& spinLock)
+void JSLock::grabAllLocks(DropAllLocks* dropper, unsigned droppedLockCount)
{
-#if PLATFORM(IOS)
- ASSERT(spinLock.IsHeld());
+ ASSERT(!m_hasExclusiveThread || !droppedLockCount);
+
// If no locks were dropped, nothing to do!
- if (!lockCount)
+ if (!droppedLockCount)
return;
- ThreadIdentifier currentThread = WTF::currentThread();
- // Check if this thread is currently holding the lock.
- // FIXME: Maybe we want to prohibit this, guard against with an ASSERT?
- if (m_ownerThread == currentThread && m_lockCount) {
- m_lockCount += lockCount;
- --m_lockDropDepth;
- return;
- }
+ ASSERT(!currentThreadIsHoldingLock());
+ lock(droppedLockCount);
- spinLock.Unlock();
- m_lock.lock();
- spinLock.Lock();
+ while (dropper->dropDepth() != m_lockDropDepth) {
+ unlock(droppedLockCount);
+ std::this_thread::yield();
+ lock(droppedLockCount);
+ }
- m_ownerThread = currentThread;
- ASSERT(!m_lockCount);
- m_lockCount = lockCount;
--m_lockDropDepth;
-#else
- UNUSED_PARAM(spinLock);
- for (unsigned i = 0; i < lockCount; ++i)
- lock();
- --m_lockDropDepth;
-#endif
+ WTFThreadData& threadData = wtfThreadData();
+ m_vm->setStackPointerAtVMEntry(threadData.savedStackPointerAtVMEntry());
+ m_vm->setLastStackTop(threadData.savedLastStackTop());
}
-JSLock::DropAllLocks::DropAllLocks(ExecState* exec, AlwaysDropLocksTag alwaysDropLocks)
- : m_lockCount(0)
- , m_vm(exec ? &exec->vm() : nullptr)
+JSLock::DropAllLocks::DropAllLocks(VM* vm)
+ : m_droppedLockCount(0)
+ // If the VM is in the middle of being destroyed then we don't want to resurrect it
+ // by allowing DropAllLocks to ref it. By this point the JSLock has already been
+ // released anyways, so it doesn't matter that DropAllLocks is a no-op.
+ , m_vm(vm->refCount() ? vm : nullptr)
{
if (!m_vm)
return;
- SpinLock& spinLock = m_vm->apiLock().m_spinLock;
-#if PLATFORM(IOS)
- SpinLockHolder holder(&spinLock);
-#endif
- if (alwaysDropLocks)
- m_lockCount = m_vm->apiLock().dropAllLocksUnconditionally(spinLock);
- else
- m_lockCount = m_vm->apiLock().dropAllLocks(spinLock);
+ wtfThreadData().resetCurrentAtomicStringTable();
+ RELEASE_ASSERT(!m_vm->apiLock().currentThreadIsHoldingLock() || !m_vm->isCollectorBusy());
+ m_droppedLockCount = m_vm->apiLock().dropAllLocks(this);
}
-JSLock::DropAllLocks::DropAllLocks(VM* vm, AlwaysDropLocksTag alwaysDropLocks)
- : m_lockCount(0)
- , m_vm(vm)
+JSLock::DropAllLocks::DropAllLocks(ExecState* exec)
+ : DropAllLocks(exec ? &exec->vm() : nullptr)
+{
+}
+
+JSLock::DropAllLocks::DropAllLocks(VM& vm)
+ : DropAllLocks(&vm)
{
- if (!m_vm)
- return;
- SpinLock& spinLock = m_vm->apiLock().m_spinLock;
-#if PLATFORM(IOS)
- SpinLockHolder holder(&spinLock);
-#endif
- if (alwaysDropLocks)
- m_lockCount = m_vm->apiLock().dropAllLocksUnconditionally(spinLock);
- else
- m_lockCount = m_vm->apiLock().dropAllLocks(spinLock);
}
JSLock::DropAllLocks::~DropAllLocks()
{
if (!m_vm)
return;
- SpinLock& spinLock = m_vm->apiLock().m_spinLock;
-#if PLATFORM(IOS)
- SpinLockHolder holder(&spinLock);
-#endif
- m_vm->apiLock().grabAllLocks(m_lockCount, spinLock);
+ m_vm->apiLock().grabAllLocks(this, m_droppedLockCount);
+ wtfThreadData().setCurrentAtomicStringTable(m_vm->atomicStringTable());
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSLock.h b/Source/JavaScriptCore/runtime/JSLock.h
index 3002add64..4d0d17420 100644
--- a/Source/JavaScriptCore/runtime/JSLock.h
+++ b/Source/JavaScriptCore/runtime/JSLock.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2008, 2009, 2014 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,109 +21,125 @@
#ifndef JSLock_h
#define JSLock_h
+#include <mutex>
+#include <thread>
#include <wtf/Assertions.h>
+#include <wtf/Lock.h>
#include <wtf/Noncopyable.h>
#include <wtf/RefPtr.h>
-#include <wtf/TCSpinLock.h>
-#include <wtf/Threading.h>
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/WTFThreadData.h>
namespace JSC {
- // To make it safe to use JavaScript on multiple threads, it is
- // important to lock before doing anything that allocates a
- // JavaScript data structure or that interacts with shared state
- // such as the protect count hash table. The simplest way to lock
- // is to create a local JSLockHolder object in the scope where the lock
- // must be held and pass it the context that requires protection.
- // The lock is recursive so nesting is ok. The JSLock
- // object also acts as a convenience short-hand for running important
- // initialization routines.
-
- // To avoid deadlock, sometimes it is necessary to temporarily
- // release the lock. Since it is recursive you actually have to
- // release all locks held by your thread. This is safe to do if
- // you are executing code that doesn't require the lock, and you
- // reacquire the right number of locks at the end. You can do this
- // by constructing a locally scoped JSLock::DropAllLocks object. The
- // DropAllLocks object takes care to release the JSLock only if your
- // thread acquired it to begin with.
-
- class ExecState;
- class VM;
-
- // This class is used to protect the initialization of the legacy single
- // shared VM.
- class GlobalJSLock {
- WTF_MAKE_NONCOPYABLE(GlobalJSLock);
+// To make it safe to use JavaScript on multiple threads, it is
+// important to lock before doing anything that allocates a
+// JavaScript data structure or that interacts with shared state
+// such as the protect count hash table. The simplest way to lock
+// is to create a local JSLockHolder object in the scope where the lock
+// must be held and pass it the context that requires protection.
+// The lock is recursive so nesting is ok. The JSLock
+// object also acts as a convenience short-hand for running important
+// initialization routines.
+
+// To avoid deadlock, sometimes it is necessary to temporarily
+// release the lock. Since it is recursive you actually have to
+// release all locks held by your thread. This is safe to do if
+// you are executing code that doesn't require the lock, and you
+// reacquire the right number of locks at the end. You can do this
+// by constructing a locally scoped JSLock::DropAllLocks object. The
+// DropAllLocks object takes care to release the JSLock only if your
+// thread acquired it to begin with.
+
+class ExecState;
+class VM;
+
+// This class is used to protect the initialization of the legacy single
+// shared VM.
+class GlobalJSLock {
+ WTF_MAKE_NONCOPYABLE(GlobalJSLock);
+public:
+ JS_EXPORT_PRIVATE GlobalJSLock();
+ JS_EXPORT_PRIVATE ~GlobalJSLock();
+private:
+ static StaticLock s_sharedInstanceMutex;
+};
+
+class JSLockHolder {
+public:
+ JS_EXPORT_PRIVATE JSLockHolder(VM*);
+ JS_EXPORT_PRIVATE JSLockHolder(VM&);
+ JS_EXPORT_PRIVATE JSLockHolder(ExecState*);
+
+ JS_EXPORT_PRIVATE ~JSLockHolder();
+private:
+ void init();
+
+ RefPtr<VM> m_vm;
+};
+
+class JSLock : public ThreadSafeRefCounted<JSLock> {
+ WTF_MAKE_NONCOPYABLE(JSLock);
+public:
+ JSLock(VM*);
+ JS_EXPORT_PRIVATE ~JSLock();
+
+ JS_EXPORT_PRIVATE void lock();
+ JS_EXPORT_PRIVATE void unlock();
+
+ static void lock(ExecState*);
+ static void unlock(ExecState*);
+ static void lock(VM&);
+ static void unlock(VM&);
+
+ VM* vm() { return m_vm; }
+
+ bool hasExclusiveThread() const { return m_hasExclusiveThread; }
+ std::thread::id exclusiveThread() const
+ {
+ ASSERT(m_hasExclusiveThread);
+ return m_ownerThreadID;
+ }
+ JS_EXPORT_PRIVATE void setExclusiveThread(std::thread::id);
+ JS_EXPORT_PRIVATE bool currentThreadIsHoldingLock();
+
+ void willDestroyVM(VM*);
+
+ class DropAllLocks {
+ WTF_MAKE_NONCOPYABLE(DropAllLocks);
public:
- JS_EXPORT_PRIVATE GlobalJSLock();
- JS_EXPORT_PRIVATE ~GlobalJSLock();
+ JS_EXPORT_PRIVATE DropAllLocks(ExecState*);
+ JS_EXPORT_PRIVATE DropAllLocks(VM*);
+ JS_EXPORT_PRIVATE DropAllLocks(VM&);
+ JS_EXPORT_PRIVATE ~DropAllLocks();
- static void initialize();
- private:
- static Mutex* s_sharedInstanceLock;
- };
+ void setDropDepth(unsigned depth) { m_dropDepth = depth; }
+ unsigned dropDepth() const { return m_dropDepth; }
- class JSLockHolder {
- public:
- JS_EXPORT_PRIVATE JSLockHolder(VM*);
- JS_EXPORT_PRIVATE JSLockHolder(VM&);
- JS_EXPORT_PRIVATE JSLockHolder(ExecState*);
-
- JS_EXPORT_PRIVATE ~JSLockHolder();
private:
- void init();
-
+ intptr_t m_droppedLockCount;
RefPtr<VM> m_vm;
+ unsigned m_dropDepth;
};
- class JSLock : public ThreadSafeRefCounted<JSLock> {
- WTF_MAKE_NONCOPYABLE(JSLock);
- public:
- JSLock(VM*);
- JS_EXPORT_PRIVATE ~JSLock();
-
- JS_EXPORT_PRIVATE void lock();
- JS_EXPORT_PRIVATE void unlock();
-
- static void lock(ExecState*);
- static void unlock(ExecState*);
- static void lock(VM&);
- static void unlock(VM&);
-
- VM* vm() { return m_vm; }
-
- JS_EXPORT_PRIVATE bool currentThreadIsHoldingLock();
-
- unsigned dropAllLocks(SpinLock&);
- unsigned dropAllLocksUnconditionally(SpinLock&);
- void grabAllLocks(unsigned lockCount, SpinLock&);
-
- void willDestroyVM(VM*);
-
- class DropAllLocks {
- WTF_MAKE_NONCOPYABLE(DropAllLocks);
- public:
- // By default, we release all locks conditionally. Some clients, such as Mobile Safari,
- // may require that we release all locks unconditionally.
- enum AlwaysDropLocksTag { DontAlwaysDropLocks = 0, AlwaysDropLocks };
- JS_EXPORT_PRIVATE DropAllLocks(ExecState*, AlwaysDropLocksTag = DontAlwaysDropLocks);
- JS_EXPORT_PRIVATE DropAllLocks(VM*, AlwaysDropLocksTag = DontAlwaysDropLocks);
- JS_EXPORT_PRIVATE ~DropAllLocks();
-
- private:
- intptr_t m_lockCount;
- RefPtr<VM> m_vm;
- };
+private:
+ void lock(intptr_t lockCount);
+ void unlock(intptr_t unlockCount);
- private:
- SpinLock m_spinLock;
- Mutex m_lock;
- ThreadIdentifier m_ownerThread;
- intptr_t m_lockCount;
- unsigned m_lockDropDepth;
- VM* m_vm;
- };
+ void didAcquireLock();
+ void willReleaseLock();
+
+ unsigned dropAllLocks(DropAllLocks*);
+ void grabAllLocks(DropAllLocks*, unsigned lockCount);
+
+ Lock m_lock;
+ std::thread::id m_ownerThreadID;
+ intptr_t m_lockCount;
+ unsigned m_lockDropDepth;
+ bool m_hasExclusiveThread;
+ VM* m_vm;
+ AtomicStringTable* m_entryAtomicStringTable;
+};
} // namespace
diff --git a/Source/JavaScriptCore/runtime/JSMap.cpp b/Source/JavaScriptCore/runtime/JSMap.cpp
index 048641441..0f4e69941 100644
--- a/Source/JavaScriptCore/runtime/JSMap.cpp
+++ b/Source/JavaScriptCore/runtime/JSMap.cpp
@@ -26,26 +26,73 @@
#include "config.h"
#include "JSMap.h"
+#include "CopiedBlockInlines.h"
#include "JSCJSValueInlines.h"
-#include "MapData.h"
+#include "JSMapIterator.h"
+#include "MapDataInlines.h"
#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
namespace JSC {
-
-const ClassInfo JSMap::s_info = { "Map", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSMap) };
+
+const ClassInfo JSMap::s_info = { "Map", &Base::s_info, 0, CREATE_METHOD_TABLE(JSMap) };
+
+void JSMap::destroy(JSCell* cell)
+{
+ JSMap* thisObject = jsCast<JSMap*>(cell);
+ thisObject->JSMap::~JSMap();
+}
+
+size_t JSMap::estimatedSize(JSCell* cell)
+{
+ JSMap* thisObject = jsCast<JSMap*>(cell);
+ size_t mapDataSize = thisObject->m_mapData.capacityInBytes();
+ return Base::estimatedSize(cell) + mapDataSize;
+}
void JSMap::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
Base::visitChildren(cell, visitor);
- JSMap* thisObject = jsCast<JSMap*>(cell);
- visitor.append(&thisObject->m_mapData);
+ jsCast<JSMap*>(cell)->m_mapData.visitChildren(cell, visitor);
}
-void JSMap::finishCreation(VM& vm)
+void JSMap::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token)
{
- Base::finishCreation(vm);
- m_mapData.set(vm, this, MapData::create(vm));
+ Base::copyBackingStore(cell, visitor, token);
+ jsCast<JSMap*>(cell)->m_mapData.copyBackingStore(visitor, token);
}
+bool JSMap::has(ExecState* exec, JSValue key)
+{
+ return m_mapData.contains(exec, key);
+}
+
+size_t JSMap::size(ExecState* exec)
+{
+ return m_mapData.size(exec);
+}
+
+JSValue JSMap::get(ExecState* exec, JSValue key)
+{
+ JSValue result = m_mapData.get(exec, key);
+ if (!result)
+ return jsUndefined();
+ return result;
+}
+
+void JSMap::set(ExecState* exec, JSValue key, JSValue value)
+{
+ m_mapData.set(exec, this, key, value);
+}
+
+void JSMap::clear(ExecState*)
+{
+ m_mapData.clear();
+}
+
+bool JSMap::remove(ExecState* exec, JSValue key)
+{
+ return m_mapData.remove(exec, key);
+}
}
diff --git a/Source/JavaScriptCore/runtime/JSMap.h b/Source/JavaScriptCore/runtime/JSMap.h
index 29aa18243..b88b125df 100644
--- a/Source/JavaScriptCore/runtime/JSMap.h
+++ b/Source/JavaScriptCore/runtime/JSMap.h
@@ -26,15 +26,67 @@
#ifndef JSMap_h
#define JSMap_h
+#include "JSDestructibleObject.h"
#include "JSObject.h"
+#include "MapData.h"
namespace JSC {
-class MapData;
+class JSMapIterator;
-class JSMap : public JSNonFinalObject {
+class JSMap : public JSDestructibleObject {
public:
- typedef JSNonFinalObject Base;
+ typedef JSDestructibleObject Base;
+
+ friend class JSMapIterator;
+
+ // Our marking functions expect Entry to maintain this layout, and have all
+ // fields be WriteBarrier<Unknown>
+ class Entry {
+ private:
+ WriteBarrier<Unknown> m_key;
+ WriteBarrier<Unknown> m_value;
+
+ public:
+ const WriteBarrier<Unknown>& key() const
+ {
+ return m_key;
+ }
+
+ const WriteBarrier<Unknown>& value() const
+ {
+ return m_value;
+ }
+
+ void visitChildren(SlotVisitor& visitor)
+ {
+ visitor.append(&m_key);
+ visitor.append(&m_value);
+ }
+
+ void setKey(VM& vm, const JSCell* owner, JSValue key)
+ {
+ m_key.set(vm, owner, key);
+ }
+
+ void setKeyWithoutWriteBarrier(JSValue key)
+ {
+ m_key.setWithoutWriteBarrier(key);
+ }
+
+ void setValue(VM& vm, const JSCell* owner, JSValue value)
+ {
+ m_value.set(vm, owner, value);
+ }
+
+ void clear()
+ {
+ m_key.clear();
+ m_value.clear();
+ }
+ };
+
+ typedef MapDataImpl<Entry, JSMapIterator> MapData;
DECLARE_EXPORT_INFO;
@@ -55,21 +107,26 @@ public:
return create(exec->vm(), structure);
}
- MapData* mapData() { return m_mapData.get(); }
+ bool has(ExecState*, JSValue);
+ size_t size(ExecState*);
+ JSValue get(ExecState*, JSValue);
+ JS_EXPORT_PRIVATE void set(ExecState*, JSValue key, JSValue value);
+ void clear(ExecState*);
+ bool remove(ExecState*, JSValue);
private:
- static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
-
JSMap(VM& vm, Structure* structure)
: Base(vm, structure)
+ , m_mapData(vm, this)
{
}
- JS_EXPORT_PRIVATE void finishCreation(VM&);
-
+ static void destroy(JSCell*);
+ static size_t estimatedSize(JSCell*);
static void visitChildren(JSCell*, SlotVisitor&);
+ static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
- WriteBarrier<MapData> m_mapData;
+ MapData m_mapData;
};
}
diff --git a/Source/JavaScriptCore/runtime/JSMapIterator.cpp b/Source/JavaScriptCore/runtime/JSMapIterator.cpp
index 091d90b52..f13ea5f7f 100644
--- a/Source/JavaScriptCore/runtime/JSMapIterator.cpp
+++ b/Source/JavaScriptCore/runtime/JSMapIterator.cpp
@@ -29,27 +29,26 @@
#include "JSCJSValueInlines.h"
#include "JSCellInlines.h"
#include "JSMap.h"
+#include "MapDataInlines.h"
#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
namespace JSC {
-const ClassInfo JSMapIterator::s_info = { "Map Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSMapIterator) };
+const ClassInfo JSMapIterator::s_info = { "Map Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(JSMapIterator) };
void JSMapIterator::finishCreation(VM& vm, JSMap* iteratedObject)
{
Base::finishCreation(vm);
- m_iteratedObjectData.set(vm, this, iteratedObject->mapData());
+ m_map.set(vm, this, iteratedObject);
}
void JSMapIterator::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSMapIterator* thisObject = jsCast<JSMapIterator*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
Base::visitChildren(thisObject, visitor);
- visitor.append(&thisObject->m_iteratedObjectData);
+ visitor.append(&thisObject->m_map);
}
JSValue JSMapIterator::createPair(CallFrame* callFrame, JSValue key, JSValue value)
@@ -61,4 +60,11 @@ JSValue JSMapIterator::createPair(CallFrame* callFrame, JSValue key, JSValue val
return constructArray(callFrame, 0, globalObject, args);
}
+JSMapIterator* JSMapIterator::clone(ExecState* exec)
+{
+ auto clone = JSMapIterator::create(exec->vm(), exec->callee()->globalObject()->mapIteratorStructure(), m_map.get(), m_kind);
+ clone->m_iterator = m_iterator;
+ return clone;
+}
+
}
diff --git a/Source/JavaScriptCore/runtime/JSMapIterator.h b/Source/JavaScriptCore/runtime/JSMapIterator.h
index 5fc965ebc..377d656c8 100644
--- a/Source/JavaScriptCore/runtime/JSMapIterator.h
+++ b/Source/JavaScriptCore/runtime/JSMapIterator.h
@@ -26,8 +26,8 @@
#ifndef JSMapIterator_h
#define JSMapIterator_h
-#include "JSDestructibleObject.h"
#include "JSMap.h"
+#include "JSObject.h"
#include "MapData.h"
namespace JSC {
@@ -37,9 +37,9 @@ enum MapIterationKind : uint32_t {
MapIterateKeyValue,
};
-class JSMapIterator : public JSDestructibleObject {
+class JSMapIterator : public JSNonFinalObject {
public:
- typedef JSDestructibleObject Base;
+ typedef JSNonFinalObject Base;
DECLARE_EXPORT_INFO;
@@ -57,16 +57,27 @@ public:
bool next(CallFrame* callFrame, JSValue& value)
{
- if (!m_iterator.ensureSlot())
+ WTF::KeyValuePair<JSValue, JSValue> pair;
+ if (!m_iterator.next(pair))
return false;
if (m_kind == MapIterateValue)
- value = m_iterator.value();
+ value = pair.value;
else if (m_kind == MapIterateKey)
- value = m_iterator.key();
+ value = pair.key;
else
- value = createPair(callFrame, m_iterator.key(), m_iterator.value());
- ++m_iterator;
+ value = createPair(callFrame, pair.key, pair.value);
+ return true;
+ }
+
+ bool nextKeyValue(JSValue& key, JSValue& value)
+ {
+ WTF::KeyValuePair<JSValue, JSValue> pair;
+ if (!m_iterator.next(pair))
+ return false;
+
+ key = pair.key;
+ value = pair.value;
return true;
}
@@ -75,25 +86,32 @@ public:
m_iterator.finish();
}
-private:
+ MapIterationKind kind() const { return m_kind; }
+ JSValue iteratedValue() const { return m_map.get(); }
+ JSMapIterator* clone(ExecState*);
- static const unsigned StructureFlags = Base::StructureFlags | OverridesVisitChildren;
+ JSMap::MapData::IteratorData* iteratorData()
+ {
+ return &m_iterator;
+ }
+private:
JSMapIterator(VM& vm, Structure* structure, JSMap* iteratedObject, MapIterationKind kind)
: Base(vm, structure)
- , m_iterator(iteratedObject->mapData()->begin())
+ , m_iterator(iteratedObject->m_mapData.createIteratorData(this))
, m_kind(kind)
{
}
- void finishCreation(VM&, JSMap*);
+ JS_EXPORT_PRIVATE void finishCreation(VM&, JSMap*);
JSValue createPair(CallFrame*, JSValue, JSValue);
static void visitChildren(JSCell*, SlotVisitor&);
- WriteBarrier<MapData> m_iteratedObjectData;
- MapData::const_iterator m_iterator;
+ WriteBarrier<JSMap> m_map;
+ JSMap::MapData::IteratorData m_iterator;
MapIterationKind m_kind;
};
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSMapIterator);
}
diff --git a/Source/JavaScriptCore/runtime/JSModuleEnvironment.cpp b/Source/JavaScriptCore/runtime/JSModuleEnvironment.cpp
new file mode 100644
index 000000000..f08fe3d02
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSModuleEnvironment.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "JSModuleEnvironment.h"
+
+#include "Interpreter.h"
+#include "JSCInlines.h"
+#include "JSFunction.h"
+
+using namespace std;
+
+namespace JSC {
+
+const ClassInfo JSModuleEnvironment::s_info = { "JSModuleEnvironment", &Base::s_info, 0, CREATE_METHOD_TABLE(JSModuleEnvironment) };
+
+JSModuleEnvironment* JSModuleEnvironment::create(
+ VM& vm, Structure* structure, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue, JSModuleRecord* moduleRecord)
+{
+ // JSLexicalEnvironment (precisely, JSEnvironmentRecord) has the storage to store the variable slots after the its class storage.
+ // Because the offset of the variable slots are fixed in the JSEnvironmentRecord, inheritting these class and adding new member field is not allowed,
+ // the new member will overlap the variable slots.
+ // To keep the JSModuleEnvironment compatible to the JSLexicalEnvironment but add the new member to store the JSModuleRecord, we additionally allocate
+ // the storage after the variable slots.
+ //
+ // JSLexicalEnvironment:
+ // [ JSLexicalEnvironment ][ variable slots ]
+ //
+ // JSModuleEnvironment:
+ // [ JSLexicalEnvironment ][ variable slots ][ additional slots for JSModuleEnvironment ]
+ JSModuleEnvironment* result =
+ new (
+ NotNull,
+ allocateCell<JSModuleEnvironment>(vm.heap, JSModuleEnvironment::allocationSize(symbolTable)))
+ JSModuleEnvironment(vm, structure, currentScope, symbolTable);
+ result->finishCreation(vm, initialValue, moduleRecord);
+ return result;
+}
+
+void JSModuleEnvironment::finishCreation(VM& vm, JSValue initialValue, JSModuleRecord* moduleRecord)
+{
+ Base::finishCreation(vm, initialValue);
+ this->moduleRecordSlot().set(vm, this, moduleRecord);
+}
+
+void JSModuleEnvironment::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell);
+ Base::visitChildren(thisObject, visitor);
+ visitor.appendValues(thisObject->variables(), thisObject->symbolTable()->scopeSize());
+ visitor.append(&thisObject->moduleRecordSlot());
+}
+
+bool JSModuleEnvironment::getOwnPropertySlot(JSObject* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell);
+ JSModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(exec, Identifier::fromUid(exec, propertyName.uid()));
+ if (resolution.type == JSModuleRecord::Resolution::Type::Resolved) {
+ // When resolveImport resolves the resolution, the imported module environment must have the binding.
+ JSModuleEnvironment* importedModuleEnvironment = resolution.moduleRecord->moduleEnvironment();
+ PropertySlot redirectSlot(importedModuleEnvironment, PropertySlot::InternalMethodType::Get);
+ bool result = importedModuleEnvironment->methodTable(exec->vm())->getOwnPropertySlot(importedModuleEnvironment, exec, resolution.localName, redirectSlot);
+ ASSERT_UNUSED(result, result);
+ ASSERT(redirectSlot.isValue());
+ JSValue value = redirectSlot.getValue(exec, resolution.localName);
+ ASSERT(!exec->hadException());
+ slot.setValue(thisObject, redirectSlot.attributes(), value);
+ return true;
+ }
+ return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+}
+
+void JSModuleEnvironment::getOwnNonIndexPropertyNames(JSObject* cell, ExecState* exec, PropertyNameArray& propertyNamesArray, EnumerationMode mode)
+{
+ JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell);
+ if (propertyNamesArray.includeStringProperties()) {
+ for (const auto& pair : thisObject->moduleRecord()->importEntries()) {
+ const JSModuleRecord::ImportEntry& importEntry = pair.value;
+ if (!importEntry.isNamespace(exec->vm()))
+ propertyNamesArray.add(importEntry.localName);
+ }
+ }
+ return Base::getOwnNonIndexPropertyNames(thisObject, exec, propertyNamesArray, mode);
+}
+
+void JSModuleEnvironment::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
+ JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell);
+ // All imported bindings are immutable.
+ JSModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(exec, Identifier::fromUid(exec, propertyName.uid()));
+ if (resolution.type == JSModuleRecord::Resolution::Type::Resolved) {
+ throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
+ return;
+ }
+ return Base::put(thisObject, exec, propertyName, value, slot);
+}
+
+bool JSModuleEnvironment::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
+{
+ JSModuleEnvironment* thisObject = jsCast<JSModuleEnvironment*>(cell);
+ // All imported bindings are immutable.
+ JSModuleRecord::Resolution resolution = thisObject->moduleRecord()->resolveImport(exec, Identifier::fromUid(exec, propertyName.uid()));
+ if (resolution.type == JSModuleRecord::Resolution::Type::Resolved)
+ return false;
+ return Base::deleteProperty(thisObject, exec, propertyName);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSModuleEnvironment.h b/Source/JavaScriptCore/runtime/JSModuleEnvironment.h
new file mode 100644
index 000000000..f7efa6263
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSModuleEnvironment.h
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ */
+
+#ifndef JSModuleEnvironment_h
+#define JSModuleEnvironment_h
+
+#include "JSLexicalEnvironment.h"
+#include "JSModuleRecord.h"
+
+namespace JSC {
+
+class Register;
+
+class JSModuleEnvironment : public JSLexicalEnvironment {
+ friend class JIT;
+ friend class LLIntOffsetsExtractor;
+public:
+ typedef JSLexicalEnvironment Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames;
+
+ static JSModuleEnvironment* create(VM&, Structure*, JSScope*, SymbolTable*, JSValue initialValue, JSModuleRecord*);
+
+ static JSModuleEnvironment* create(VM& vm, JSGlobalObject* globalObject, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue, JSModuleRecord* moduleRecord)
+ {
+ Structure* structure = globalObject->moduleEnvironmentStructure();
+ return create(vm, structure, currentScope, symbolTable, initialValue, moduleRecord);
+ }
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject)
+ {
+ return Structure::create(vm, globalObject, jsNull(), TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ static size_t offsetOfModuleRecord(SymbolTable* symbolTable)
+ {
+ size_t offset = Base::allocationSize(symbolTable);
+ ASSERT(WTF::roundUpToMultipleOf<sizeof(WriteBarrier<JSModuleRecord>)>(offset) == offset);
+ return offset;
+ }
+
+ static size_t allocationSize(SymbolTable* symbolTable)
+ {
+ return offsetOfModuleRecord(symbolTable) + sizeof(WriteBarrier<JSModuleRecord>);
+ }
+
+ JSModuleRecord* moduleRecord()
+ {
+ return moduleRecordSlot().get();
+ }
+
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+ static bool deleteProperty(JSCell*, ExecState*, PropertyName);
+
+private:
+ JSModuleEnvironment(VM&, Structure*, JSScope*, SymbolTable*);
+
+ void finishCreation(VM&, JSValue initialValue, JSModuleRecord*);
+
+ WriteBarrierBase<JSModuleRecord>& moduleRecordSlot()
+ {
+ return *bitwise_cast<WriteBarrierBase<JSModuleRecord>*>(bitwise_cast<char*>(this) + offsetOfModuleRecord(symbolTable()));
+ }
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+};
+
+inline JSModuleEnvironment::JSModuleEnvironment(VM& vm, Structure* structure, JSScope* currentScope, SymbolTable* symbolTable)
+ : Base(vm, structure, currentScope, symbolTable)
+{
+}
+
+} // namespace JSC
+
+#endif // JSModuleEnvironment_h
diff --git a/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp b/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp
new file mode 100644
index 000000000..b53a273df
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "JSModuleNamespaceObject.h"
+
+#include "Error.h"
+#include "IdentifierInlines.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSModuleEnvironment.h"
+#include "JSModuleRecord.h"
+#include "JSPropertyNameIterator.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL moduleNamespaceObjectSymbolIterator(ExecState*);
+
+const ClassInfo JSModuleNamespaceObject::s_info = { "ModuleNamespaceObject", &Base::s_info, nullptr, CREATE_METHOD_TABLE(JSModuleNamespaceObject) };
+
+
+JSModuleNamespaceObject::JSModuleNamespaceObject(VM& vm, Structure* structure)
+ : Base(vm, structure)
+ , m_exports()
+{
+}
+
+void JSModuleNamespaceObject::finishCreation(VM& vm, JSGlobalObject* globalObject, JSModuleRecord* moduleRecord, const IdentifierSet& exports)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects
+ // Quoted from the spec:
+ // A List containing the String values of the exported names exposed as own properties of this object.
+ // The list is ordered as if an Array of those String values had been sorted using Array.prototype.sort using SortCompare as comparefn.
+ //
+ // Sort the exported names by the code point order.
+ Vector<UniquedStringImpl*> temporaryVector(exports.size(), nullptr);
+ std::transform(exports.begin(), exports.end(), temporaryVector.begin(), [](const RefPtr<WTF::UniquedStringImpl>& ref) {
+ return ref.get();
+ });
+ std::sort(temporaryVector.begin(), temporaryVector.end(), [] (UniquedStringImpl* lhs, UniquedStringImpl* rhs) {
+ return codePointCompare(lhs, rhs) < 0;
+ });
+ for (auto* identifier : temporaryVector)
+ m_exports.add(identifier);
+
+ m_moduleRecord.set(vm, this, moduleRecord);
+ JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorSymbol, moduleNamespaceObjectSymbolIterator, DontEnum, 0);
+ putDirect(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Module"), DontEnum | ReadOnly);
+
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-getprototypeof
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-setprototypeof-v
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-isextensible
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-preventextensions
+ preventExtensions(vm);
+}
+
+void JSModuleNamespaceObject::destroy(JSCell* cell)
+{
+ JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
+ thisObject->JSModuleNamespaceObject::~JSModuleNamespaceObject();
+}
+
+void JSModuleNamespaceObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+ visitor.append(&thisObject->m_moduleRecord);
+}
+
+static EncodedJSValue callbackGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName propertyName)
+{
+ JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(JSValue::decode(thisValue));
+ JSModuleRecord* moduleRecord = thisObject->moduleRecord();
+
+ JSModuleRecord::Resolution resolution = moduleRecord->resolveExport(exec, Identifier::fromUid(exec, propertyName.uid()));
+ ASSERT(resolution.type != JSModuleRecord::Resolution::Type::NotFound && resolution.type != JSModuleRecord::Resolution::Type::Ambiguous);
+
+ JSModuleRecord* targetModule = resolution.moduleRecord;
+ JSModuleEnvironment* targetEnvironment = targetModule->moduleEnvironment();
+
+ PropertySlot trampolineSlot(targetEnvironment, PropertySlot::InternalMethodType::Get);
+ if (!targetEnvironment->methodTable(exec->vm())->getOwnPropertySlot(targetEnvironment, exec, resolution.localName, trampolineSlot))
+ return JSValue::encode(jsUndefined());
+
+ JSValue value = trampolineSlot.getValue(exec, propertyName);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ // If the value is filled with TDZ value, throw a reference error.
+ if (!value)
+ return throwVMError(exec, createTDZError(exec));
+ return JSValue::encode(value);
+}
+
+bool JSModuleNamespaceObject::getOwnPropertySlot(JSObject* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-getownproperty-p
+
+ JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
+
+ // step 1.
+ // If the property name is a symbol, we don't look into the imported bindings.
+ // It may return the descriptor with writable: true, but namespace objects does not allow it in [[Set]] / [[DefineOwnProperty]] side.
+ if (propertyName.isSymbol())
+ return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+
+ if (!thisObject->m_exports.contains(propertyName.uid()))
+ return false;
+
+ // https://esdiscuss.org/topic/march-24-meeting-notes
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-getownproperty-p
+ // section 9.4.6.5, step 6.
+ // This property will be seen as writable: true, enumerable:true, configurable: false.
+ // But this does not mean that this property is writable by users.
+ //
+ // In JSC, getOwnPropertySlot is not designed to throw any errors. But looking up the value from the module
+ // environment may throw error if the loaded variable is the TDZ value. To workaround, we set the custom
+ // getter function. When it is called, it looks up the variable and throws an error if the variable is not
+ // initialized.
+ slot.setCustom(thisObject, DontDelete, callbackGetter);
+ return true;
+}
+
+void JSModuleNamespaceObject::put(JSCell*, ExecState* exec, PropertyName, JSValue, PutPropertySlot& slot)
+{
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-set-p-v-receiver
+ if (slot.isStrictMode())
+ throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
+}
+
+void JSModuleNamespaceObject::putByIndex(JSCell*, ExecState* exec, unsigned, JSValue, bool shouldThrow)
+{
+ if (shouldThrow)
+ throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
+}
+
+bool JSModuleNamespaceObject::deleteProperty(JSCell* cell, ExecState*, PropertyName propertyName)
+{
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-delete-p
+ JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
+ return !thisObject->m_exports.contains(propertyName.uid());
+}
+
+void JSModuleNamespaceObject::getOwnPropertyNames(JSObject* cell, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-ownpropertykeys
+ JSModuleNamespaceObject* thisObject = jsCast<JSModuleNamespaceObject*>(cell);
+ for (const auto& name : thisObject->m_exports)
+ propertyNames.add(name.get());
+ return JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
+}
+
+bool JSModuleNamespaceObject::defineOwnProperty(JSObject*, ExecState* exec, PropertyName, const PropertyDescriptor&, bool shouldThrow)
+{
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-defineownproperty-p-desc
+ if (shouldThrow)
+ throwTypeError(exec, ASCIILiteral("Attempting to define property on object that is not extensible."));
+ return false;
+}
+
+EncodedJSValue JSC_HOST_CALL moduleNamespaceObjectSymbolIterator(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("|this| should be an object")));
+ return JSValue::encode(JSPropertyNameIterator::create(exec, exec->lexicalGlobalObject()->propertyNameIteratorStructure(), asObject(thisValue)));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h b/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h
new file mode 100644
index 000000000..4d04f5624
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#ifndef JSModuleNamespaceObject_h
+#define JSModuleNamespaceObject_h
+
+#include "JSDestructibleObject.h"
+#include <wtf/ListHashSet.h>
+
+namespace JSC {
+
+class JSModuleRecord;
+
+class JSModuleNamespaceObject : public JSDestructibleObject {
+public:
+ typedef JSDestructibleObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames;
+
+ static JSModuleNamespaceObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSModuleRecord* moduleRecord, const IdentifierSet& exports)
+ {
+ JSModuleNamespaceObject* object = new (NotNull, allocateCell<JSModuleNamespaceObject>(exec->vm().heap)) JSModuleNamespaceObject(exec->vm(), structure);
+ object->finishCreation(exec->vm(), globalObject, moduleRecord, exports);
+ return object;
+ }
+
+ JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+ JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
+ JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName);
+ JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
+
+ DECLARE_EXPORT_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ JSModuleRecord* moduleRecord() { return m_moduleRecord.get(); }
+
+protected:
+ JS_EXPORT_PRIVATE void finishCreation(VM&, JSGlobalObject*, JSModuleRecord*, const IdentifierSet& exports);
+ JS_EXPORT_PRIVATE JSModuleNamespaceObject(VM&, Structure*);
+
+private:
+ static void destroy(JSCell*);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ typedef WTF::ListHashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> OrderedIdentifierSet;
+
+ OrderedIdentifierSet m_exports;
+ WriteBarrier<JSModuleRecord> m_moduleRecord;
+};
+
+} // namespace JSC
+
+#endif // JSModuleNamespaceObject_h
diff --git a/Source/JavaScriptCore/runtime/JSModuleRecord.cpp b/Source/JavaScriptCore/runtime/JSModuleRecord.cpp
new file mode 100644
index 000000000..1cc49375d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSModuleRecord.cpp
@@ -0,0 +1,903 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "JSModuleRecord.h"
+
+#include "Error.h"
+#include "Executable.h"
+#include "IdentifierInlines.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSMap.h"
+#include "JSModuleEnvironment.h"
+#include "JSModuleNamespaceObject.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+const ClassInfo JSModuleRecord::s_info = { "ModuleRecord", &Base::s_info, 0, CREATE_METHOD_TABLE(JSModuleRecord) };
+
+void JSModuleRecord::destroy(JSCell* cell)
+{
+ JSModuleRecord* thisObject = jsCast<JSModuleRecord*>(cell);
+ thisObject->JSModuleRecord::~JSModuleRecord();
+}
+
+void JSModuleRecord::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+ putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("registryEntry")), jsUndefined());
+ putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("evaluated")), jsBoolean(false));
+
+ m_dependenciesMap.set(vm, this, JSMap::create(vm, globalObject()->mapStructure()));
+ putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("dependenciesMap")), m_dependenciesMap.get());
+}
+
+void JSModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSModuleRecord* thisObject = jsCast<JSModuleRecord*>(cell);
+ Base::visitChildren(thisObject, visitor);
+ visitor.append(&thisObject->m_moduleEnvironment);
+ visitor.append(&thisObject->m_moduleNamespaceObject);
+ visitor.append(&thisObject->m_moduleProgramExecutable);
+ visitor.append(&thisObject->m_dependenciesMap);
+}
+
+void JSModuleRecord::appendRequestedModule(const Identifier& moduleName)
+{
+ m_requestedModules.add(moduleName.impl());
+}
+
+void JSModuleRecord::addStarExportEntry(const Identifier& moduleName)
+{
+ m_starExportEntries.add(moduleName.impl());
+}
+
+void JSModuleRecord::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 JSModuleRecord::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 JSModuleRecord::tryGetImportEntry(UniquedStringImpl* localName) -> Optional<ImportEntry>
+{
+ const auto iterator = m_importEntries.find(localName);
+ if (iterator == m_importEntries.end())
+ return Nullopt;
+ return Optional<ImportEntry>(iterator->value);
+}
+
+auto JSModuleRecord::tryGetExportEntry(UniquedStringImpl* exportName) -> Optional<ExportEntry>
+{
+ const auto iterator = m_exportEntries.find(exportName);
+ if (iterator == m_exportEntries.end())
+ return Nullopt;
+ return Optional<ExportEntry>(iterator->value);
+}
+
+auto JSModuleRecord::ExportEntry::createLocal(const Identifier& exportName, const Identifier& localName, const VariableEnvironmentEntry& variable) -> ExportEntry
+{
+ return ExportEntry { Type::Local, exportName, Identifier(), Identifier(), localName, variable };
+}
+
+auto JSModuleRecord::ExportEntry::createNamespace(const Identifier& exportName, const Identifier& moduleName) -> ExportEntry
+{
+ return ExportEntry { Type::Namespace, exportName, moduleName, Identifier(), Identifier(), VariableEnvironmentEntry() };
+}
+
+auto JSModuleRecord::ExportEntry::createIndirect(const Identifier& exportName, const Identifier& importName, const Identifier& moduleName) -> ExportEntry
+{
+ return ExportEntry { Type::Indirect, exportName, moduleName, importName, Identifier(), VariableEnvironmentEntry() };
+}
+
+auto JSModuleRecord::Resolution::notFound() -> Resolution
+{
+ return Resolution { Type::NotFound, nullptr, Identifier() };
+}
+
+auto JSModuleRecord::Resolution::error() -> Resolution
+{
+ return Resolution { Type::Error, nullptr, Identifier() };
+}
+
+auto JSModuleRecord::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<SymbolImpl&>(*identifier.impl()));
+ return jsString(&exec->vm(), identifier.impl());
+}
+
+JSModuleRecord* JSModuleRecord::hostResolveImportedModule(ExecState* exec, const Identifier& moduleName)
+{
+ JSValue moduleNameValue = identifierToJSValue(exec, moduleName);
+ JSValue pair = m_dependenciesMap->JSMap::get(exec, moduleNameValue);
+ return jsCast<JSModuleRecord*>(pair.get(exec, Identifier::fromString(exec, "value")));
+}
+
+auto JSModuleRecord::resolveImport(ExecState* exec, const Identifier& localName) -> Resolution
+{
+ Optional<ImportEntry> optionalImportEntry = tryGetImportEntry(localName.impl());
+ if (!optionalImportEntry)
+ return Resolution::notFound();
+
+ const ImportEntry& importEntry = *optionalImportEntry;
+ if (importEntry.isNamespace(exec->vm()))
+ return Resolution::notFound();
+
+ JSModuleRecord* importedModule = hostResolveImportedModule(exec, importEntry.moduleRequest);
+ return importedModule->resolveExport(exec, importEntry.importName);
+}
+
+struct JSModuleRecord::ResolveQuery {
+ struct Hash {
+ static unsigned hash(const ResolveQuery&);
+ static bool equal(const ResolveQuery&, const ResolveQuery&);
+ static const bool safeToCompareToEmptyOrDeleted = true;
+ };
+
+ ResolveQuery(JSModuleRecord* moduleRecord, UniquedStringImpl* exportName)
+ : moduleRecord(moduleRecord)
+ , exportName(exportName)
+ {
+ }
+
+ ResolveQuery(JSModuleRecord* 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.
+ JSModuleRecord* moduleRecord;
+ RefPtr<UniquedStringImpl> exportName;
+};
+
+inline unsigned JSModuleRecord::ResolveQuery::Hash::hash(const ResolveQuery& query)
+{
+ return WTF::PtrHash<JSModuleRecord*>::hash(query.moduleRecord) + IdentifierRepHash::hash(query.exportName);
+}
+
+inline bool JSModuleRecord::ResolveQuery::Hash::equal(const ResolveQuery& lhs, const ResolveQuery& rhs)
+{
+ return lhs.moduleRecord == rhs.moduleRecord && lhs.exportName == rhs.exportName;
+}
+
+auto JSModuleRecord::tryGetCachedResolution(UniquedStringImpl* exportName) -> Optional<Resolution>
+{
+ const auto iterator = m_resolutionCache.find(exportName);
+ if (iterator == m_resolutionCache.end())
+ return Nullopt;
+ return Optional<Resolution>(iterator->value);
+}
+
+void JSModuleRecord::cacheResolution(UniquedStringImpl* exportName, const Resolution& resolution)
+{
+ m_resolutionCache.add(exportName, resolution);
+}
+
+auto JSModuleRecord::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
+ // "Reslove" (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<Resolution>.
+ // Technically, all the JSModuleRecords have the Map<ExportName, Resolution> 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<ResolveQuery, ResolveQuery::Hash, WTF::CustomHashTraits<ResolveQuery>> ResolveSet;
+ enum class Type { Query, IndirectFallback, GatherStars };
+ struct Task {
+ ResolveQuery query;
+ Type type;
+ };
+
+ Vector<Task, 8> pendingTasks;
+ ResolveSet resolveSet;
+ HashSet<JSModuleRecord*> starSet;
+
+ Vector<Resolution, 8> 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<UniquedStringImpl>& starModuleName = *iterator;
+ JSModuleRecord* 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: {
+ JSModuleRecord* 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 (Optional<Resolution> cachedResolution = moduleRecord->tryGetCachedResolution(query.exportName.get())) {
+ if (!mergeToCurrentTop(*cachedResolution))
+ return Resolution::ambiguous();
+ continue;
+ }
+ }
+
+ const Optional<ExportEntry> 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:
+ case ExportEntry::Type::Namespace: {
+ 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: {
+ JSModuleRecord* 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 JSModuleRecord::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 (Optional<Resolution> cachedResolution = tryGetCachedResolution(exportName.impl()))
+ return *cachedResolution;
+ return resolveExportImpl(exec, ResolveQuery(this, exportName.impl()));
+}
+
+static void getExportedNames(ExecState* exec, JSModuleRecord* root, IdentifierSet& exportedNames)
+{
+ HashSet<JSModuleRecord*> exportStarSet;
+ Vector<JSModuleRecord*, 8> pendingModules;
+
+ pendingModules.append(root);
+
+ while (!pendingModules.isEmpty()) {
+ JSModuleRecord* moduleRecord = pendingModules.takeLast();
+ if (exportStarSet.contains(moduleRecord))
+ continue;
+ exportStarSet.add(moduleRecord);
+
+ for (const auto& pair : moduleRecord->exportEntries()) {
+ const JSModuleRecord::ExportEntry& exportEntry = pair.value;
+ switch (exportEntry.type) {
+ case JSModuleRecord::ExportEntry::Type::Local:
+ case JSModuleRecord::ExportEntry::Type::Indirect:
+ if (moduleRecord == root || exec->propertyNames().defaultKeyword != exportEntry.exportName)
+ exportedNames.add(exportEntry.exportName.impl());
+ break;
+
+ case JSModuleRecord::ExportEntry::Type::Namespace:
+ break;
+ }
+ }
+
+ for (const auto& starModuleName : moduleRecord->starExportEntries()) {
+ JSModuleRecord* requestedModuleRecord = moduleRecord->hostResolveImportedModule(exec, Identifier::fromUid(exec, starModuleName.get()));
+ pendingModules.append(requestedModuleRecord);
+ }
+ }
+}
+
+JSModuleNamespaceObject* JSModuleRecord::getModuleNamespace(ExecState* exec)
+{
+ // 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);
+
+ IdentifierSet unambiguousNames;
+ for (auto& name : exportedNames) {
+ const JSModuleRecord::Resolution resolution = resolveExport(exec, Identifier::fromUid(exec, name.get()));
+ switch (resolution.type) {
+ case Resolution::Type::NotFound:
+ throwSyntaxError(exec, makeString("Exported binding name '", String(name.get()), "' is not found."));
+ return nullptr;
+
+ case Resolution::Type::Error:
+ throwSyntaxError(exec, makeString("Exported binding name 'default' cannot be resolved by star export entries."));
+ return nullptr;
+
+ case Resolution::Type::Ambiguous:
+ break;
+
+ case Resolution::Type::Resolved:
+ unambiguousNames.add(name);
+ break;
+ }
+ }
+
+ m_moduleNamespaceObject.set(exec->vm(), this, JSModuleNamespaceObject::create(exec, globalObject, globalObject->moduleNamespaceObjectStructure(), this, unambiguousNames));
+ return m_moduleNamespaceObject.get();
+}
+
+void JSModuleRecord::link(ExecState* exec)
+{
+ ModuleProgramExecutable* executable = ModuleProgramExecutable::create(exec, sourceCode());
+ if (!executable) {
+ throwSyntaxError(exec);
+ return;
+ }
+ m_moduleProgramExecutable.set(exec->vm(), this, executable);
+ instantiateDeclarations(exec, executable);
+}
+
+void JSModuleRecord::instantiateDeclarations(ExecState* exec, ModuleProgramExecutable* moduleProgramExecutable)
+{
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
+
+ SymbolTable* symbolTable = moduleProgramExecutable->moduleEnvironmentSymbolTable();
+ JSModuleEnvironment* moduleEnvironment = JSModuleEnvironment::create(exec->vm(), exec->lexicalGlobalObject(), exec->lexicalGlobalObject(), symbolTable, jsTDZValue(), this);
+
+ VM& vm = exec->vm();
+
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
+ // section 15.2.1.16.4 step 9.
+ // Ensure all the indirect exports are correctly resolved to unique bindings.
+ // Even if we avoided duplicate exports in the parser, still ambiguous exports occur due to the star export (`export * from "mod"`).
+ // When we see this type of ambiguity for the indirect exports here, throw a syntax error.
+ for (const auto& pair : m_exportEntries) {
+ const ExportEntry& exportEntry = pair.value;
+ if (exportEntry.type == JSModuleRecord::ExportEntry::Type::Indirect) {
+ Resolution resolution = resolveExport(exec, exportEntry.exportName);
+ switch (resolution.type) {
+ case Resolution::Type::NotFound:
+ throwSyntaxError(exec, makeString("Indirectly exported binding name '", String(exportEntry.exportName.impl()), "' is not found."));
+ return;
+
+ case Resolution::Type::Ambiguous:
+ throwSyntaxError(exec, makeString("Indirectly exported binding name '", String(exportEntry.exportName.impl()), "' cannot be resolved due to ambiguous multiple bindings."));
+ return;
+
+ case Resolution::Type::Error:
+ throwSyntaxError(exec, makeString("Indirectly exported binding name 'default' cannot be resolved by star export entries."));
+ return;
+
+ case Resolution::Type::Resolved:
+ break;
+ }
+ }
+ }
+
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
+ // section 15.2.1.16.4 step 12.
+ // Instantiate namespace objects and initialize the bindings with them if required.
+ // And ensure that all the imports correctly resolved to unique bindings.
+ for (const auto& pair : m_importEntries) {
+ const ImportEntry& importEntry = pair.value;
+ JSModuleRecord* importedModule = hostResolveImportedModule(exec, importEntry.moduleRequest);
+ if (importEntry.isNamespace(vm)) {
+ JSModuleNamespaceObject* namespaceObject = importedModule->getModuleNamespace(exec);
+ if (exec->hadException())
+ return;
+ symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, importEntry.localName, namespaceObject, /* shouldThrowReadOnlyError */ false, /* ignoreReadOnlyErrors */ true);
+ } else {
+ Resolution resolution = importedModule->resolveExport(exec, importEntry.importName);
+ switch (resolution.type) {
+ case Resolution::Type::NotFound:
+ throwSyntaxError(exec, makeString("Importing binding name '", String(importEntry.importName.impl()), "' is not found."));
+ return;
+
+ case Resolution::Type::Ambiguous:
+ throwSyntaxError(exec, makeString("Importing binding name '", String(importEntry.importName.impl()), "' cannot be resolved due to ambiguous multiple bindings."));
+ return;
+
+ case Resolution::Type::Error:
+ throwSyntaxError(exec, makeString("Importing binding name 'default' cannot be resolved by star export entries."));
+ return;
+
+ case Resolution::Type::Resolved:
+ break;
+ }
+ }
+ }
+
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
+ // section 15.2.1.16.4 step 14.
+ // Module environment contains the heap allocated "var", "function", "let", "const", and "class".
+ // When creating the environment, we initialized all the slots with empty, it's ok for lexical values.
+ // But for "var" and "function", we should initialize it with undefined. They are contained in the declared variables.
+ for (const auto& variable : m_declaredVariables) {
+ SymbolTableEntry entry = symbolTable->get(variable.key.get());
+ VarOffset offset = entry.varOffset();
+ if (!offset.isStack())
+ symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, Identifier::fromUid(exec, variable.key.get()), jsUndefined(), /* shouldThrowReadOnlyError */ false, /* ignoreReadOnlyErrors */ true);
+ }
+
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
+ // section 15.2.1.16.4 step 16-a-iv.
+ // Initialize heap allocated function declarations.
+ // They can be called before the body of the module is executed under circular dependencies.
+ UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock = moduleProgramExecutable->unlinkedModuleProgramCodeBlock();
+ for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) {
+ UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i);
+ SymbolTableEntry entry = symbolTable->get(unlinkedFunctionExecutable->name().impl());
+ VarOffset offset = entry.varOffset();
+ if (!offset.isStack()) {
+ ASSERT(!unlinkedFunctionExecutable->name().isEmpty());
+ if (vm.typeProfiler() || vm.controlFlowProfiler()) {
+ vm.functionHasExecutedCache()->insertUnexecutedRange(moduleProgramExecutable->sourceID(),
+ unlinkedFunctionExecutable->typeProfilingStartOffset(),
+ unlinkedFunctionExecutable->typeProfilingEndOffset());
+ }
+ JSFunction* function = JSFunction::create(vm, unlinkedFunctionExecutable->link(vm, moduleProgramExecutable->source()), moduleEnvironment);
+ symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, unlinkedFunctionExecutable->name(), function, /* shouldThrowReadOnlyError */ false, /* ignoreReadOnlyErrors */ true);
+ }
+ }
+
+ m_moduleEnvironment.set(vm, this, moduleEnvironment);
+}
+
+JSValue JSModuleRecord::evaluate(ExecState* exec)
+{
+ if (!m_moduleProgramExecutable)
+ return jsUndefined();
+ JSValue result = exec->interpreter()->execute(m_moduleProgramExecutable.get(), exec, m_moduleEnvironment.get());
+ m_moduleProgramExecutable.clear();
+ return result;
+}
+
+static String printableName(const RefPtr<UniquedStringImpl>& uid)
+{
+ if (uid->isSymbol())
+ return uid.get();
+ return WTF::makeString("'", String(uid.get()), "'");
+}
+
+static String printableName(const Identifier& ident)
+{
+ return printableName(ident.impl());
+}
+
+void JSModuleRecord::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::Namespace:
+ dataLog(" [Namespace] ", "export(", printableName(exportEntry.exportName), "), module(", printableName(exportEntry.moduleName), ")\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/JSModuleRecord.h b/Source/JavaScriptCore/runtime/JSModuleRecord.h
new file mode 100644
index 000000000..b82a9e1d5
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSModuleRecord.h
@@ -0,0 +1,221 @@
+/*
+ * 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.
+ */
+
+#ifndef JSModuleRecord_h
+#define JSModuleRecord_h
+
+#include "Identifier.h"
+#include "JSDestructibleObject.h"
+#include "SourceCode.h"
+#include "VariableEnvironment.h"
+#include <wtf/HashMap.h>
+#include <wtf/ListHashSet.h>
+#include <wtf/Optional.h>
+
+namespace JSC {
+
+class JSModuleNamespaceObject;
+class JSModuleEnvironment;
+class JSMap;
+class ModuleProgramExecutable;
+
+// Based on the Source Text Module Record
+// http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records
+class JSModuleRecord : public JSDestructibleObject {
+ friend class LLIntOffsetsExtractor;
+public:
+ typedef JSDestructibleObject Base;
+
+ struct ExportEntry {
+ enum class Type {
+ Local,
+ Namespace,
+ Indirect
+ };
+
+ static ExportEntry createLocal(const Identifier& exportName, const Identifier& localName, const VariableEnvironmentEntry&);
+ static ExportEntry createNamespace(const Identifier& exportName, const Identifier& moduleName);
+ static ExportEntry createIndirect(const Identifier& exportName, const Identifier& importName, const Identifier& moduleName);
+
+ Type type;
+ Identifier exportName;
+ Identifier moduleName;
+ Identifier importName;
+ Identifier localName;
+ VariableEnvironmentEntry variable;
+ };
+
+ struct ImportEntry {
+ Identifier moduleRequest;
+ Identifier importName;
+ Identifier localName;
+
+ bool isNamespace(VM& vm) const
+ {
+ return importName == vm.propertyNames->timesIdentifier;
+ }
+ };
+
+ typedef WTF::ListHashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> OrderedIdentifierSet;
+ typedef HashMap<RefPtr<UniquedStringImpl>, ImportEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> ImportEntries;
+ typedef HashMap<RefPtr<UniquedStringImpl>, ExportEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> ExportEntries;
+
+ DECLARE_EXPORT_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ static JSModuleRecord* create(VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
+ {
+ JSModuleRecord* instance = new (NotNull, allocateCell<JSModuleRecord>(vm.heap)) JSModuleRecord(vm, structure, moduleKey, sourceCode, declaredVariables, lexicalVariables);
+ instance->finishCreation(vm);
+ return instance;
+ }
+
+ void appendRequestedModule(const Identifier&);
+ void addStarExportEntry(const Identifier&);
+ void addImportEntry(const ImportEntry&);
+ void addExportEntry(const ExportEntry&);
+
+ Optional<ImportEntry> tryGetImportEntry(UniquedStringImpl* localName);
+ Optional<ExportEntry> tryGetExportEntry(UniquedStringImpl* exportName);
+
+ const SourceCode& sourceCode() const { return m_sourceCode; }
+ 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; }
+
+ const VariableEnvironment& declaredVariables() const { return m_declaredVariables; }
+ const VariableEnvironment& lexicalVariables() const { return m_lexicalVariables; }
+
+ void dump();
+
+ JSModuleEnvironment* moduleEnvironment()
+ {
+ ASSERT(m_moduleEnvironment);
+ return m_moduleEnvironment.get();
+ }
+
+ void link(ExecState*);
+ JS_EXPORT_PRIVATE JSValue evaluate(ExecState*);
+
+ ModuleProgramExecutable* moduleProgramExecutable() const { return m_moduleProgramExecutable.get(); }
+
+ struct Resolution {
+ enum class Type { Resolved, NotFound, Ambiguous, Error };
+
+ static Resolution notFound();
+ static Resolution error();
+ static Resolution ambiguous();
+
+ Type type;
+ JSModuleRecord* moduleRecord;
+ Identifier localName;
+ };
+
+ Resolution resolveExport(ExecState*, const Identifier& exportName);
+ Resolution resolveImport(ExecState*, const Identifier& localName);
+
+ JSModuleRecord* hostResolveImportedModule(ExecState*, const Identifier& moduleName);
+
+private:
+ JSModuleRecord(VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
+ : Base(vm, structure)
+ , m_moduleKey(moduleKey)
+ , m_sourceCode(sourceCode)
+ , m_declaredVariables(declaredVariables)
+ , m_lexicalVariables(lexicalVariables)
+ {
+ }
+
+ void finishCreation(VM&);
+
+ JSModuleNamespaceObject* getModuleNamespace(ExecState*);
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+ static void destroy(JSCell*);
+
+ void instantiateDeclarations(ExecState*, ModuleProgramExecutable*);
+
+ struct ResolveQuery;
+ static Resolution resolveExportImpl(ExecState*, const ResolveQuery&);
+ Optional<Resolution> 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;
+
+ SourceCode m_sourceCode;
+
+ VariableEnvironment m_declaredVariables;
+ VariableEnvironment m_lexicalVariables;
+
+ // 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<JSMap> m_dependenciesMap;
+
+ WriteBarrier<ModuleProgramExecutable> m_moduleProgramExecutable;
+ WriteBarrier<JSModuleEnvironment> m_moduleEnvironment;
+ WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
+
+ // We assume that all the JSModuleRecord are retained by ModuleLoaderObject'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<RefPtr<UniquedStringImpl>, Resolution, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> Resolutions;
+ Resolutions m_resolutionCache;
+};
+
+} // namespace JSC
+
+#endif // JSModuleRecord_h
diff --git a/Source/JavaScriptCore/runtime/JSNameScope.cpp b/Source/JavaScriptCore/runtime/JSNameScope.cpp
deleted file mode 100644
index 76542f676..000000000
--- a/Source/JavaScriptCore/runtime/JSNameScope.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2008, 2009, 2012 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 "JSNameScope.h"
-
-#include "Error.h"
-#include "Operations.h"
-
-namespace JSC {
-
-const ClassInfo JSNameScope::s_info = { "NameScope", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSNameScope) };
-
-void JSNameScope::visitChildren(JSCell* cell, SlotVisitor& visitor)
-{
- JSNameScope* thisObject = jsCast<JSNameScope*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
- Base::visitChildren(thisObject, visitor);
- visitor.append(&thisObject->m_registerStore);
-}
-
-JSValue JSNameScope::toThis(JSCell*, ExecState* exec, ECMAMode ecmaMode)
-{
- if (ecmaMode == StrictMode)
- return jsUndefined();
- return exec->globalThisValue();
-}
-
-void JSNameScope::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
-{
- JSNameScope* thisObject = jsCast<JSNameScope*>(cell);
- if (slot.isStrictMode()) {
- // Double lookup in strict mode, but this only occurs when
- // a) indirectly writing to an exception slot
- // b) writing to a function expression name
- // (a) is unlikely, and (b) is an error.
- // Also with a single entry the symbol table lookup should simply be
- // a pointer compare.
- PropertySlot slot(thisObject);
- bool isWritable = true;
- symbolTableGet(thisObject, propertyName, slot, isWritable);
- if (!isWritable) {
- exec->vm().throwException(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
- return;
- }
- }
- if (symbolTablePut(thisObject, exec, propertyName, value, slot.isStrictMode()))
- return;
-
- RELEASE_ASSERT_NOT_REACHED();
-}
-
-bool JSNameScope::getOwnPropertySlot(JSObject* object, ExecState*, PropertyName propertyName, PropertySlot& slot)
-{
- return symbolTableGet(jsCast<JSNameScope*>(object), propertyName, slot);
-}
-
-} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSNameScope.h b/Source/JavaScriptCore/runtime/JSNameScope.h
deleted file mode 100644
index f5b15a214..000000000
--- a/Source/JavaScriptCore/runtime/JSNameScope.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2008, 2009 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 JSNameScope_h
-#define JSNameScope_h
-
-#include "JSGlobalObject.h"
-#include "JSVariableObject.h"
-
-namespace JSC {
-
-// Used for scopes with a single named variable: catch and named function expression.
-class JSNameScope : public JSVariableObject {
-public:
- typedef JSVariableObject Base;
-
- static JSNameScope* create(ExecState* exec, const Identifier& identifier, JSValue value, unsigned attributes)
- {
- VM& vm = exec->vm();
- JSNameScope* scopeObject = new (NotNull, allocateCell<JSNameScope>(vm.heap)) JSNameScope(exec, exec->scope());
- scopeObject->finishCreation(vm, identifier, value, attributes);
- return scopeObject;
- }
-
- static JSNameScope* create(ExecState* exec, const Identifier& identifier, JSValue value, unsigned attributes, JSScope* next)
- {
- VM& vm = exec->vm();
- JSNameScope* scopeObject = new (NotNull, allocateCell<JSNameScope>(vm.heap)) JSNameScope(exec, next);
- scopeObject->finishCreation(vm, identifier, value, attributes);
- return scopeObject;
- }
-
- static void visitChildren(JSCell*, SlotVisitor&);
- static JSValue toThis(JSCell*, ExecState*, ECMAMode);
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(NameScopeObjectType, StructureFlags), info()); }
-
- DECLARE_INFO;
-
-protected:
- void finishCreation(VM& vm, const Identifier& identifier, JSValue value, unsigned attributes)
- {
- Base::finishCreation(vm);
- m_registerStore.set(vm, this, value);
- symbolTable()->add(identifier.impl(), SymbolTableEntry(-1, attributes));
- }
-
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | Base::StructureFlags;
-
-private:
- JSNameScope(ExecState* exec, JSScope* next)
- : Base(
- exec->vm(),
- exec->lexicalGlobalObject()->nameScopeStructure(),
- reinterpret_cast<Register*>(&m_registerStore + 1),
- next
- )
- {
- }
-
- WriteBarrier<Unknown> m_registerStore;
-};
-
-}
-
-#endif // JSNameScope_h
diff --git a/Source/JavaScriptCore/runtime/JSNativeStdFunction.cpp b/Source/JavaScriptCore/runtime/JSNativeStdFunction.cpp
new file mode 100644
index 000000000..f11a865c0
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSNativeStdFunction.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "JSNativeStdFunction.h"
+
+#include "JSCInlines.h"
+#include "JSFunction.h"
+#include "JSFunctionInlines.h"
+#include "JSObject.h"
+#include "NativeStdFunctionCell.h"
+#include "VM.h"
+
+namespace JSC {
+
+const ClassInfo JSNativeStdFunction::s_info = { "Function", &Base::s_info, nullptr, CREATE_METHOD_TABLE(JSNativeStdFunction) };
+
+JSNativeStdFunction::JSNativeStdFunction(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+ : Base(vm, globalObject, structure)
+{
+}
+
+void JSNativeStdFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSNativeStdFunction* thisObject = jsCast<JSNativeStdFunction*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+ visitor.append(&thisObject->m_functionCell);
+}
+
+void JSNativeStdFunction::finishCreation(VM& vm, NativeExecutable* executable, int length, const String& name, NativeStdFunctionCell* functionCell)
+{
+ Base::finishCreation(vm, executable, length, name);
+ ASSERT(inherits(info()));
+ m_functionCell.set(vm, this, functionCell);
+}
+
+static EncodedJSValue JSC_HOST_CALL runStdFunction(ExecState* state)
+{
+ JSNativeStdFunction* function = jsCast<JSNativeStdFunction*>(state->callee());
+ ASSERT(function);
+ return function->nativeStdFunctionCell()->function()(state);
+}
+
+JSNativeStdFunction* JSNativeStdFunction::create(VM& vm, JSGlobalObject* globalObject, int length, const String& name, NativeStdFunction&& nativeStdFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)
+{
+ NativeExecutable* executable = lookUpOrCreateNativeExecutable(vm, runStdFunction, intrinsic, nativeConstructor, name);
+ NativeStdFunctionCell* functionCell = NativeStdFunctionCell::create(vm, WTFMove(nativeStdFunction));
+ JSNativeStdFunction* function = new (NotNull, allocateCell<JSNativeStdFunction>(vm.heap)) JSNativeStdFunction(vm, globalObject, globalObject->nativeStdFunctionStructure());
+ function->finishCreation(vm, executable, length, name, functionCell);
+ return function;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSNativeStdFunction.h b/Source/JavaScriptCore/runtime/JSNativeStdFunction.h
new file mode 100644
index 000000000..e99015ac5
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSNativeStdFunction.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#ifndef JSNativeStdFunction_h
+#define JSNativeStdFunction_h
+
+#include "JSFunction.h"
+
+namespace JSC {
+
+class JSGlobalObject;
+class NativeStdFunctionCell;
+
+typedef std::function<EncodedJSValue (ExecState*)> NativeStdFunction;
+
+class JSNativeStdFunction : public JSFunction {
+public:
+ typedef JSFunction Base;
+
+ const static unsigned StructureFlags = Base::StructureFlags;
+
+ DECLARE_EXPORT_INFO;
+
+ JS_EXPORT_PRIVATE static JSNativeStdFunction* create(VM&, JSGlobalObject*, int length, const String& name, NativeStdFunction&&, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor);
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ ASSERT(globalObject);
+ return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
+ }
+
+ NativeStdFunctionCell* nativeStdFunctionCell() { return m_functionCell.get(); }
+
+protected:
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ void finishCreation(VM&, NativeExecutable*, int length, const String& name, NativeStdFunctionCell*);
+
+private:
+ JSNativeStdFunction(VM&, JSGlobalObject*, Structure*);
+
+ WriteBarrier<NativeStdFunctionCell> m_functionCell;
+};
+
+} // namespace JSC
+
+#endif // JSNativeStdFunction_h
diff --git a/Source/JavaScriptCore/runtime/JSNotAnObject.cpp b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp
index 7b7f3650f..af4737e9b 100644
--- a/Source/JavaScriptCore/runtime/JSNotAnObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp
@@ -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.
*
@@ -30,13 +30,13 @@
#include "config.h"
#include "JSNotAnObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSNotAnObject);
-const ClassInfo JSNotAnObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSNotAnObject) };
+const ClassInfo JSNotAnObject::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(JSNotAnObject) };
// JSValue methods
JSValue JSNotAnObject::defaultValue(const JSObject*, ExecState* exec, PreferredPrimitiveType)
diff --git a/Source/JavaScriptCore/runtime/JSNotAnObject.h b/Source/JavaScriptCore/runtime/JSNotAnObject.h
index 8c3dd7263..0c26ec98b 100644
--- a/Source/JavaScriptCore/runtime/JSNotAnObject.h
+++ b/Source/JavaScriptCore/runtime/JSNotAnObject.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.
*
@@ -33,52 +33,50 @@
namespace JSC {
- // This unholy class is used to allow us to avoid multiple exception checks
- // in certain SquirrelFish bytecodes -- effectively it just silently consumes
- // any operations performed on the result of a failed toObject call.
- class JSNotAnObject : public JSNonFinalObject {
- private:
- explicit JSNotAnObject(VM& vm)
- : JSNonFinalObject(vm, vm.notAnObjectStructure.get())
- {
- }
-
- public:
- typedef JSNonFinalObject Base;
+// This unholy class is used to allow us to avoid multiple exception checks
+// in certain SquirrelFish bytecodes -- effectively it just silently consumes
+// any operations performed on the result of a failed toObject call.
+class JSNotAnObject final : public JSNonFinalObject {
+private:
+ explicit JSNotAnObject(VM& vm)
+ : JSNonFinalObject(vm, vm.notAnObjectStructure.get())
+ {
+ }
- static JSNotAnObject* create(VM& vm)
- {
- JSNotAnObject* object = new (NotNull, allocateCell<JSNotAnObject>(vm.heap)) JSNotAnObject(vm);
- object->finishCreation(vm);
- return object;
- }
+public:
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames;
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
+ static JSNotAnObject* create(VM& vm)
+ {
+ JSNotAnObject* object = new (NotNull, allocateCell<JSNotAnObject>(vm.heap)) JSNotAnObject(vm);
+ object->finishCreation(vm);
+ return object;
+ }
- DECLARE_INFO;
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
- private:
-
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | JSObject::StructureFlags;
+ DECLARE_INFO;
- // JSValue methods
- static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
+private:
+ // JSValue methods
+ static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
- // JSObject methods
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
+ // JSObject methods
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
- static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
- static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
+ 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 deleteProperty(JSCell*, ExecState*, PropertyName);
+ static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
- static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
- };
+ static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp
index 982628917..20244652f 100644
--- a/Source/JavaScriptCore/runtime/JSONObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSONObject.cpp
@@ -36,7 +36,7 @@
#include "LocalScope.h"
#include "Lookup.h"
#include "ObjectConstructor.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "PropertyNameArray.h"
#include <wtf/MathExtras.h>
#include <wtf/text/StringBuilder.h>
@@ -45,8 +45,8 @@ namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSONObject);
-static EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*);
-static EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*);
+EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*);
+EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*);
}
@@ -63,6 +63,8 @@ void JSONObject::finishCreation(VM& vm)
{
Base::finishCreation(vm);
ASSERT(inherits(info()));
+
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "JSON"), DontEnum | ReadOnly);
}
// PropertyNameForFunctionCall objects must be on the stack, since the JSValue that they create is not marked.
@@ -107,11 +109,10 @@ private:
friend class Holder;
- static void appendQuotedString(StringBuilder&, const String&);
-
JSValue toJSON(JSValue, const PropertyNameForFunctionCall&);
+ JSValue toJSONImpl(JSValue, const PropertyNameForFunctionCall&);
- enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedValue };
+ enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedOrSymbolValue };
StringifyResult appendStringifiedValue(StringBuilder&, JSValue, JSObject* holder, const PropertyNameForFunctionCall&);
bool willIndent() const;
@@ -145,6 +146,9 @@ static inline JSValue unwrapBoxedPrimitive(ExecState* exec, JSValue value)
return object->toString(exec);
if (object->inherits(BooleanObject::info()))
return object->toPrimitive(exec);
+
+ // Do not unwrap SymbolObject to Symbol. It is not performed in the spec.
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-serializejsonproperty
return value;
}
@@ -207,7 +211,7 @@ Stringifier::Stringifier(ExecState* exec, const Local<Unknown>& replacer, const
: m_exec(exec)
, m_replacer(replacer)
, m_usingArrayReplacer(false)
- , m_arrayReplacerPropertyNames(exec)
+ , m_arrayReplacerPropertyNames(exec, PropertyNameMode::Strings)
, m_replacerCallType(CallTypeNone)
, m_gap(gap(exec, space.get()))
{
@@ -226,9 +230,10 @@ Stringifier::Stringifier(ExecState* exec, const Local<Unknown>& replacer, const
if (name.isObject()) {
if (!asObject(name)->inherits(NumberObject::info()) && !asObject(name)->inherits(StringObject::info()))
continue;
- }
+ } else if (!name.isNumber() && !name.isString())
+ continue;
- m_arrayReplacerPropertyNames.add(Identifier(exec, name.toString(exec)->value(exec)));
+ m_arrayReplacerPropertyNames.add(name.toString(exec)->toIdentifier(exec));
}
return;
}
@@ -254,83 +259,16 @@ Local<Unknown> Stringifier::stringify(Handle<Unknown> value)
return Local<Unknown>(m_exec->vm(), jsString(m_exec, result.toString()));
}
-template <typename CharType>
-static void appendStringToStringBuilder(StringBuilder& builder, const CharType* data, int length)
-{
- for (int i = 0; i < length; ++i) {
- int start = i;
- while (i < length && (data[i] > 0x1F && data[i] != '"' && data[i] != '\\'))
- ++i;
- builder.append(data + start, i - start);
- if (i >= length)
- break;
- switch (data[i]) {
- case '\t':
- builder.append('\\');
- builder.append('t');
- break;
- case '\r':
- builder.append('\\');
- builder.append('r');
- break;
- case '\n':
- builder.append('\\');
- builder.append('n');
- break;
- case '\f':
- builder.append('\\');
- builder.append('f');
- break;
- case '\b':
- builder.append('\\');
- builder.append('b');
- break;
- case '"':
- builder.append('\\');
- builder.append('"');
- break;
- case '\\':
- builder.append('\\');
- builder.append('\\');
- break;
- default:
- static const char hexDigits[] = "0123456789abcdef";
- UChar ch = data[i];
- LChar hex[] = { '\\', 'u', static_cast<LChar>(hexDigits[(ch >> 12) & 0xF]), static_cast<LChar>(hexDigits[(ch >> 8) & 0xF]), static_cast<LChar>(hexDigits[(ch >> 4) & 0xF]), static_cast<LChar>(hexDigits[ch & 0xF]) };
- builder.append(hex, WTF_ARRAY_LENGTH(hex));
- break;
- }
- }
-}
-
-void escapeStringToBuilder(StringBuilder& builder, const String& message)
-{
- if (message.is8Bit())
- appendStringToStringBuilder(builder, message.characters8(), message.length());
- else
- appendStringToStringBuilder(builder, message.characters16(), message.length());
-}
-
-void Stringifier::appendQuotedString(StringBuilder& builder, const String& value)
-{
- int length = value.length();
-
- builder.append('"');
-
- if (value.is8Bit())
- appendStringToStringBuilder<LChar>(builder, value.characters8(), length);
- else
- appendStringToStringBuilder<UChar>(builder, value.characters16(), length);
-
- builder.append('"');
-}
-
-inline JSValue Stringifier::toJSON(JSValue value, const PropertyNameForFunctionCall& propertyName)
+ALWAYS_INLINE JSValue Stringifier::toJSON(JSValue value, const PropertyNameForFunctionCall& propertyName)
{
ASSERT(!m_exec->hadException());
if (!value.isObject() || !asObject(value)->hasProperty(m_exec, m_exec->vm().propertyNames->toJSON))
return value;
+ return toJSONImpl(value, propertyName);
+}
+JSValue Stringifier::toJSONImpl(JSValue value, const PropertyNameForFunctionCall& propertyName)
+{
JSValue toJSONFunction = asObject(value)->get(m_exec, m_exec->vm().propertyNames->toJSON);
if (m_exec->hadException())
return jsNull();
@@ -366,8 +304,8 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder&
return StringifyFailed;
}
- if (value.isUndefined() && !holder->inherits(JSArray::info()))
- return StringifyFailedDueToUndefinedValue;
+ if ((value.isUndefined() || value.isSymbol()) && !holder->inherits(JSArray::info()))
+ return StringifyFailedDueToUndefinedOrSymbolValue;
if (value.isNull()) {
builder.appendLiteral("null");
@@ -387,18 +325,21 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder&
return StringifySucceeded;
}
- String stringValue;
- if (value.getString(m_exec, stringValue)) {
- appendQuotedString(builder, stringValue);
+ if (value.isString()) {
+ builder.appendQuotedJSONString(asString(value)->value(m_exec));
return StringifySucceeded;
}
if (value.isNumber()) {
- double number = value.asNumber();
- if (!std::isfinite(number))
- builder.appendLiteral("null");
- else
- builder.append(String::numberToStringECMAScript(number));
+ if (value.isInt32())
+ builder.appendNumber(value.asInt32());
+ else {
+ double number = value.asNumber();
+ if (!std::isfinite(number))
+ builder.appendLiteral("null");
+ else
+ builder.appendECMAScriptNumber(number);
+ }
return StringifySucceeded;
}
@@ -413,7 +354,7 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder&
builder.appendLiteral("null");
return StringifySucceeded;
}
- return StringifyFailedDueToUndefinedValue;
+ return StringifyFailedDueToUndefinedOrSymbolValue;
}
// Handle cycle detection, and put the holder on the stack.
@@ -487,14 +428,17 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui
if (!m_index) {
if (m_isArray) {
m_isJSArray = isJSArray(m_object.get());
- m_size = m_object->get(exec, exec->vm().propertyNames->length).toUInt32(exec);
+ if (m_isJSArray)
+ m_size = asArray(m_object.get())->length();
+ else
+ m_size = m_object->get(exec, exec->vm().propertyNames->length).toUInt32(exec);
builder.append('[');
} else {
if (stringifier.m_usingArrayReplacer)
m_propertyNames = stringifier.m_arrayReplacerPropertyNames.data();
else {
- PropertyNameArray objectPropertyNames(exec);
- m_object->methodTable()->getOwnPropertyNames(m_object.get(), exec, objectPropertyNames, ExcludeDontEnumProperties);
+ PropertyNameArray objectPropertyNames(exec, PropertyNameMode::Strings);
+ m_object->methodTable()->getOwnPropertyNames(m_object.get(), exec, objectPropertyNames, EnumerationMode());
m_propertyNames = objectPropertyNames.releaseData();
}
m_size = m_propertyNames->propertyNameVector().size();
@@ -522,7 +466,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui
if (m_isJSArray && asArray(m_object.get())->canGetIndexQuickly(index))
value = asArray(m_object.get())->getIndexQuickly(index);
else {
- PropertySlot slot(m_object.get());
+ PropertySlot slot(m_object.get(), PropertySlot::InternalMethodType::Get);
if (m_object->methodTable()->getOwnPropertySlotByIndex(m_object.get(), exec, index, slot)) {
value = slot.getValue(exec, index);
if (exec->hadException())
@@ -540,7 +484,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui
stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object.get(), index);
} else {
// Get the value.
- PropertySlot slot(m_object.get());
+ PropertySlot slot(m_object.get(), PropertySlot::InternalMethodType::Get);
Identifier& propertyName = m_propertyNames->propertyNameVector()[index];
if (!m_object->methodTable()->getOwnPropertySlot(m_object.get(), exec, propertyName, slot))
return true;
@@ -556,7 +500,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui
stringifier.startNewLine(builder);
// Append the property name.
- appendQuotedString(builder, propertyName.string());
+ builder.appendQuotedJSONString(propertyName.string());
builder.append(':');
if (stringifier.willIndent())
builder.append(' ');
@@ -575,10 +519,10 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui
break;
case StringifySucceeded:
break;
- case StringifyFailedDueToUndefinedValue:
- // This only occurs when get an undefined value for an object property.
- // In this case we don't want the separator and property name that we
- // already appended, so roll back.
+ case StringifyFailedDueToUndefinedOrSymbolValue:
+ // This only occurs when get an undefined value or a symbol value for
+ // an object property. In this case we don't want the separator and
+ // property name that we already appended, so roll back.
builder.resize(rollBackPoint);
break;
}
@@ -588,7 +532,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui
// ------------------------------ JSONObject --------------------------------
-const ClassInfo JSONObject::s_info = { "JSON", &JSNonFinalObject::s_info, 0, ExecState::jsonTable, CREATE_METHOD_TABLE(JSONObject) };
+const ClassInfo JSONObject::s_info = { "JSON", &JSNonFinalObject::s_info, &jsonTable, CREATE_METHOD_TABLE(JSONObject) };
/* Source for JSONObject.lut.h
@begin jsonTable
@@ -601,7 +545,7 @@ const ClassInfo JSONObject::s_info = { "JSON", &JSNonFinalObject::s_info, 0, Exe
bool JSONObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
- return getStaticFunctionSlot<JSObject>(exec, ExecState::jsonTable(exec->vm()), jsCast<JSONObject*>(object), propertyName, slot);
+ return getStaticFunctionSlot<JSObject>(exec, jsonTable, jsCast<JSONObject*>(object), propertyName, slot);
}
class Walker {
@@ -654,7 +598,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered)
ASSERT(inValue.isObject());
ASSERT(isJSArray(asObject(inValue)) || asObject(inValue)->inherits(JSArray::info()));
if (objectStack.size() + arrayStack.size() > maximumFilterRecursion)
- return m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec));
+ return throwStackOverflowError(m_exec);
JSArray* array = asArray(inValue);
arrayStack.push(array);
@@ -674,7 +618,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered)
if (isJSArray(array) && array->canGetIndexQuickly(index))
inValue = array->getIndexQuickly(index);
else {
- PropertySlot slot(array);
+ PropertySlot slot(array, PropertySlot::InternalMethodType::Get);
if (array->methodTable()->getOwnPropertySlotByIndex(array, m_exec, index, slot))
inValue = slot.getValue(m_exec, index);
else
@@ -705,13 +649,13 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered)
ASSERT(inValue.isObject());
ASSERT(!isJSArray(asObject(inValue)) && !asObject(inValue)->inherits(JSArray::info()));
if (objectStack.size() + arrayStack.size() > maximumFilterRecursion)
- return m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec));
+ return throwStackOverflowError(m_exec);
JSObject* object = asObject(inValue);
objectStack.push(object);
indexStack.append(0);
- propertyStack.append(PropertyNameArray(m_exec));
- object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
+ propertyStack.append(PropertyNameArray(m_exec, PropertyNameMode::Strings));
+ object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode());
}
objectStartVisitMember:
FALLTHROUGH;
@@ -726,7 +670,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered)
propertyStack.removeLast();
break;
}
- PropertySlot slot(object);
+ PropertySlot slot(object, PropertySlot::InternalMethodType::Get);
if (object->methodTable()->getOwnPropertySlot(object, m_exec, properties[index], slot))
inValue = slot.getValue(m_exec, properties[index]);
else
@@ -785,7 +729,7 @@ EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec)
{
if (!exec->argumentCount())
return throwVMError(exec, createError(exec, ASCIILiteral("JSON.parse requires at least one parameter")));
- String source = exec->uncheckedArgument(0).toString(exec)->value(exec);
+ JSString::SafeView source = exec->uncheckedArgument(0).toString(exec)->view(exec);
if (exec->hadException())
return JSValue::encode(jsNull());
diff --git a/Source/JavaScriptCore/runtime/JSONObject.h b/Source/JavaScriptCore/runtime/JSONObject.h
index cacfc5d6c..db00a69e3 100644
--- a/Source/JavaScriptCore/runtime/JSONObject.h
+++ b/Source/JavaScriptCore/runtime/JSONObject.h
@@ -30,40 +30,36 @@
namespace JSC {
- class Stringifier;
+class JSONObject : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
- class JSONObject : public JSNonFinalObject {
- public:
- typedef JSNonFinalObject Base;
+ static JSONObject* create(VM& vm, Structure* structure)
+ {
+ JSONObject* object = new (NotNull, allocateCell<JSONObject>(vm.heap)) JSONObject(vm, structure);
+ object->finishCreation(vm);
+ return object;
+ }
- static JSONObject* create(VM& vm, Structure* structure)
- {
- JSONObject* object = new (NotNull, allocateCell<JSONObject>(vm.heap)) JSONObject(vm, structure);
- object->finishCreation(vm);
- return object;
- }
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
-
- DECLARE_INFO;
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
- protected:
- void finishCreation(VM&);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags;
+ DECLARE_INFO;
- private:
- JSONObject(VM&, Structure*);
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+protected:
+ void finishCreation(VM&);
- };
+private:
+ JSONObject(VM&, Structure*);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+};
- JS_EXPORT_PRIVATE JSValue JSONParse(ExecState*, const String&);
- JS_EXPORT_PRIVATE String JSONStringify(ExecState*, JSValue, unsigned indent);
+JS_EXPORT_PRIVATE JSValue JSONParse(ExecState*, const String&);
+JS_EXPORT_PRIVATE String JSONStringify(ExecState*, JSValue, unsigned indent);
- void escapeStringToBuilder(StringBuilder&, const String&);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index 6910b7e04..730194f3a 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -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, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2003-2006, 2008, 2009, 2012-2016 Apple Inc. All rights reserved.
* Copyright (C) 2007 Eric Seidel (eric@webkit.org)
*
* This library is free software; you can redistribute it and/or
@@ -25,23 +25,28 @@
#include "JSObject.h"
#include "ButterflyInlines.h"
+#include "CopiedBlockInlines.h"
#include "CopiedSpaceInlines.h"
#include "CopyVisitor.h"
#include "CopyVisitorInlines.h"
+#include "CustomGetterSetter.h"
#include "DatePrototype.h"
#include "ErrorConstructor.h"
+#include "Exception.h"
#include "Executable.h"
#include "GetterSetter.h"
#include "IndexingHeaderInlines.h"
+#include "JSBoundSlotBaseFunction.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "Lookup.h"
#include "NativeErrorConstructor.h"
#include "Nodes.h"
#include "ObjectPrototype.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "PropertyDescriptor.h"
#include "PropertyNameArray.h"
+#include "ProxyObject.h"
#include "Reject.h"
#include "SlotVisitorInlines.h"
#include <math.h>
@@ -55,40 +60,28 @@ namespace JSC {
// ArrayConventions.h.
static unsigned lastArraySize = 0;
-JSCell* getCallableObjectSlow(JSCell* cell)
-{
- Structure* structure = cell->structure();
- if (structure->typeInfo().type() == JSFunctionType)
- return cell;
- if (structure->classInfo()->isSubClassOf(InternalFunction::info()))
- return cell;
- return 0;
-}
-
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSObject);
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSFinalObject);
const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property.";
-const ClassInfo JSObject::s_info = { "Object", 0, 0, 0, CREATE_METHOD_TABLE(JSObject) };
+const ClassInfo JSObject::s_info = { "Object", 0, 0, CREATE_METHOD_TABLE(JSObject) };
-const ClassInfo JSFinalObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFinalObject) };
+const ClassInfo JSFinalObject::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(JSFinalObject) };
-static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode, bool didReify)
+static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode)
{
+ VM& vm = exec->vm();
+
// Add properties from the static hashtables of properties
for (; classInfo; classInfo = classInfo->parentClass) {
- const HashTable* table = classInfo->propHashTable(exec);
+ const HashTable* table = classInfo->staticPropHashTable;
if (!table)
continue;
- table->initializeIfNeeded(exec);
- ASSERT(table->table);
-
- int hashSizeMask = table->compactSize - 1;
- const HashEntry* entry = table->table;
- for (int i = 0; i <= hashSizeMask; ++i, ++entry) {
- if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)) && !((entry->attributes() & Function) && didReify))
- propertyNames.add(entry->key());
+
+ for (auto iter = table->begin(); iter != table->end(); ++iter) {
+ if (!(iter->attributes() & DontEnum) || mode.includeDontEnumProperties())
+ propertyNames.add(Identifier::fromString(&vm, iter.key()));
}
}
}
@@ -113,7 +106,7 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt
size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
if (visitor.checkIfShouldCopy(butterfly->base(preCapacity, propertyCapacity))) {
Butterfly* newButterfly = Butterfly::createUninitializedDuringCollection(visitor, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
-
+
// Copy the properties.
PropertyStorage currentTarget = newButterfly->propertyStorage();
PropertyStorage currentSource = butterfly->propertyStorage();
@@ -129,7 +122,7 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt
WriteBarrier<Unknown>* currentSource;
size_t count;
- switch (structure->indexingType()) {
+ switch (this->indexingType()) {
case ALL_UNDECIDED_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
case ALL_INT32_INDEXING_TYPES:
@@ -159,7 +152,7 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt
memcpy(currentTarget, currentSource, count * sizeof(EncodedJSValue));
}
- m_butterfly.setWithoutWriteBarrier(newButterfly);
+ m_butterfly.setWithoutBarrier(newButterfly);
visitor.didCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
}
}
@@ -168,7 +161,7 @@ ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* but
{
ASSERT(butterfly);
- Structure* structure = this->structure();
+ Structure* structure = this->structure(visitor.vm());
size_t propertyCapacity = structure->outOfLineCapacity();
size_t preCapacity;
@@ -190,7 +183,7 @@ ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* but
butterfly->base(preCapacity, propertyCapacity), capacityInBytes);
// Mark the array if appropriate.
- switch (structure->indexingType()) {
+ switch (this->indexingType()) {
case ALL_CONTIGUOUS_INDEXING_TYPES:
visitor.appendValues(butterfly->contiguous().data(), butterfly->publicLength());
break;
@@ -204,6 +197,13 @@ ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* but
}
}
+size_t JSObject::estimatedSize(JSCell* cell)
+{
+ JSObject* thisObject = jsCast<JSObject*>(cell);
+ size_t butterflyOutOfLineSize = thisObject->m_butterfly ? thisObject->structure()->outOfLineSize() : 0;
+ return Base::estimatedSize(cell) + butterflyOutOfLineSize;
+}
+
void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSObject* thisObject = jsCast<JSObject*>(cell);
@@ -215,9 +215,9 @@ void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
JSCell::visitChildren(thisObject, visitor);
- Butterfly* butterfly = thisObject->butterfly();
+ Butterfly* butterfly = thisObject->m_butterfly.getWithoutBarrier();
if (butterfly)
- thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
+ thisObject->visitButterfly(visitor, butterfly, thisObject->structure(visitor.vm())->outOfLineSize());
#if !ASSERT_DISABLED
visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
@@ -228,11 +228,11 @@ void JSObject::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken to
{
JSObject* thisObject = jsCast<JSObject*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
-
+
if (token != ButterflyCopyToken)
return;
- Butterfly* butterfly = thisObject->butterfly();
+ Butterfly* butterfly = thisObject->m_butterfly.getWithoutBarrier();
if (butterfly)
thisObject->copyButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
}
@@ -248,11 +248,12 @@ void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
JSCell::visitChildren(thisObject, visitor);
+ Structure* structure = thisObject->structure();
Butterfly* butterfly = thisObject->butterfly();
if (butterfly)
- thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize());
+ thisObject->visitButterfly(visitor, butterfly, structure->outOfLineSize());
- size_t storageSize = thisObject->structure()->inlineSize();
+ size_t storageSize = structure->inlineSize();
visitor.appendValues(thisObject->inlineStorage(), storageSize);
#if !ASSERT_DISABLED
@@ -267,6 +268,44 @@ String JSObject::className(const JSObject* object)
return info->className;
}
+String JSObject::calculatedClassName(JSObject* object)
+{
+ String prototypeFunctionName;
+ ExecState* exec = object->globalObject()->globalExec();
+ PropertySlot slot(object->structure()->storedPrototype(), PropertySlot::InternalMethodType::VMInquiry);
+ PropertyName constructor(exec->propertyNames().constructor);
+ if (object->getPropertySlot(exec, constructor, slot)) {
+ if (slot.isValue()) {
+ JSValue constructorValue = slot.getValue(exec, constructor);
+ if (constructorValue.isCell()) {
+ if (JSCell* constructorCell = constructorValue.asCell()) {
+ if (JSObject* ctorObject = constructorCell->getObject()) {
+ if (JSFunction* constructorFunction = jsDynamicCast<JSFunction*>(ctorObject))
+ prototypeFunctionName = constructorFunction->calculatedDisplayName(exec);
+ else if (InternalFunction* constructorFunction = jsDynamicCast<InternalFunction*>(ctorObject))
+ prototypeFunctionName = constructorFunction->calculatedDisplayName(exec);
+ }
+ }
+ }
+ }
+ }
+
+ if (prototypeFunctionName.isNull() || prototypeFunctionName == "Object") {
+ String tableClassName = object->methodTable()->className(object);
+ if (!tableClassName.isNull() && tableClassName != "Object")
+ return tableClassName;
+
+ String classInfoName = object->classInfo()->className;
+ if (!classInfoName.isNull())
+ return classInfoName;
+
+ if (prototypeFunctionName.isNull())
+ return ASCIILiteral("Object");
+ }
+
+ return prototypeFunctionName;
+}
+
bool JSObject::getOwnPropertySlotByIndex(JSObject* thisObject, ExecState* exec, unsigned i, PropertySlot& slot)
{
// NB. The fact that we're directly consulting our indexed storage implies that it is not
@@ -274,9 +313,9 @@ bool JSObject::getOwnPropertySlotByIndex(JSObject* thisObject, ExecState* exec,
// getOwnPropertySlotByIndex().
if (i > MAX_ARRAY_INDEX)
- return thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
+ return thisObject->methodTable(exec->vm())->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
- switch (thisObject->structure()->indexingType()) {
+ switch (thisObject->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
break;
@@ -311,7 +350,7 @@ bool JSObject::getOwnPropertySlotByIndex(JSObject* thisObject, ExecState* exec,
}
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
- ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
+ ArrayStorage* storage = thisObject->m_butterfly.get(thisObject)->arrayStorage();
if (i >= storage->length())
return false;
@@ -342,42 +381,20 @@ bool JSObject::getOwnPropertySlotByIndex(JSObject* thisObject, ExecState* exec,
// ECMA 8.6.2.2
void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
{
- JSObject* thisObject = jsCast<JSObject*>(cell);
- ASSERT(value);
- ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
+ putInline(cell, exec, propertyName, value, slot);
+}
+
+void JSObject::putInlineSlow(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
VM& vm = exec->vm();
-
- // Try indexed put first. This is required for correctness, since loads on property names that appear like
- // valid indices will never look in the named property storage.
- unsigned i = propertyName.asIndex();
- if (i != PropertyName::NotAnIndex) {
- putByIndex(thisObject, exec, i, value, slot.isStrictMode());
- return;
- }
-
- // Check if there are any setters or getters in the prototype chain
- JSValue prototype;
- if (propertyName != exec->propertyNames().underscoreProto) {
- for (JSObject* obj = thisObject; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
- prototype = obj->prototype();
- if (prototype.isNull()) {
- ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName));
- if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value))
- && slot.isStrictMode())
- throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
- return;
- }
- }
- }
- JSObject* obj;
- for (obj = thisObject; ; obj = asObject(prototype)) {
+ JSObject* obj = this;
+ for (;;) {
unsigned attributes;
- JSCell* specificValue;
- PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue);
+ PropertyOffset offset = obj->structure(vm)->get(vm, propertyName, attributes);
if (isValidOffset(offset)) {
if (attributes & ReadOnly) {
- ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
+ ASSERT(structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == this);
if (slot.isStrictMode())
exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)));
return;
@@ -385,31 +402,42 @@ void JSObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSV
JSValue gs = obj->getDirect(offset);
if (gs.isGetterSetter()) {
- callSetter(exec, cell, gs, value, slot.isStrictMode() ? StrictMode : NotStrictMode);
+ callSetter(exec, this, gs, value, slot.isStrictMode() ? StrictMode : NotStrictMode);
+ if (!structure()->isDictionary())
+ slot.setCacheableSetter(obj, offset);
return;
- } else
- ASSERT(!(attributes & Accessor));
+ }
+ if (gs.isCustomGetterSetter()) {
+ callCustomSetter(exec, gs, attributes & CustomAccessor, obj, slot.thisValue(), value);
+ if (attributes & CustomAccessor)
+ slot.setCustomAccessor(obj, jsCast<CustomGetterSetter*>(gs.asCell())->setter());
+ else
+ slot.setCustomValue(obj, jsCast<CustomGetterSetter*>(gs.asCell())->setter());
+ return;
+ }
+ ASSERT(!(attributes & Accessor));
// If there's an existing property on the object or one of its
// prototypes it should be replaced, so break here.
break;
}
- const ClassInfo* info = obj->classInfo();
- if (info->hasStaticSetterOrReadonlyProperties(vm)) {
- if (const HashEntry* entry = obj->findPropertyHashEntry(exec, propertyName)) {
- putEntry(exec, entry, obj, propertyName, value, slot);
- return;
+ if (!obj->staticFunctionsReified()) {
+ if (obj->classInfo()->hasStaticSetterOrReadonlyProperties()) {
+ if (auto* entry = obj->findPropertyHashEntry(propertyName)) {
+ putEntry(exec, entry, obj, this, propertyName, value, slot);
+ return;
+ }
}
}
- prototype = obj->prototype();
+ JSValue prototype = obj->prototype();
if (prototype.isNull())
break;
+ obj = asObject(prototype);
}
- ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject);
- if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode())
+ ASSERT(!structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == this);
+ if (!putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot) && slot.isStrictMode())
throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
- return;
}
void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
@@ -422,7 +450,7 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
return;
}
- switch (thisObject->structure()->indexingType()) {
+ switch (thisObject->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
break;
@@ -477,7 +505,7 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage: {
- ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
+ ArrayStorage* storage = thisObject->m_butterfly.get(thisObject)->arrayStorage();
if (propertyName >= storage->vectorLength())
break;
@@ -499,7 +527,7 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName,
case NonArrayWithSlowPutArrayStorage:
case ArrayWithSlowPutArrayStorage: {
- ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
+ ArrayStorage* storage = thisObject->m_butterfly.get(thisObject)->arrayStorage();
if (propertyName >= storage->vectorLength())
break;
@@ -549,11 +577,11 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists
// This will always be a new entry in the map, so no need to check we can write,
// and attributes are default so no need to set them.
if (value)
- map->add(this, i).iterator->value.set(vm, this, value);
+ map->add(this, i).iterator->value.set(vm, map, value);
}
DeferGC deferGC(vm.heap);
- Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, this, structure(), 0, ArrayStorage::sizeFor(0));
+ Butterfly* newButterfly = storage->butterfly()->resizeArray(vm, this, structure(vm), 0, ArrayStorage::sizeFor(0));
RELEASE_ASSERT(newButterfly);
newButterfly->arrayStorage()->m_indexBias = 0;
newButterfly->arrayStorage()->setVectorLength(0);
@@ -565,18 +593,21 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists
void JSObject::enterDictionaryIndexingMode(VM& vm)
{
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
case ALL_INT32_INDEXING_TYPES:
case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
// NOTE: this is horribly inefficient, as it will perform two conversions. We could optimize
- // this case if we ever cared.
- enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, ensureArrayStorageSlow(vm));
+ // this case if we ever cared. Note that ensureArrayStorage() can return null if the object
+ // doesn't support traditional indexed properties. At the time of writing, this just affects
+ // typed arrays.
+ if (ArrayStorage* storage = ensureArrayStorageSlow(vm))
+ enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, storage);
break;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly->arrayStorage());
+ enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly.get(this)->arrayStorage());
break;
default:
@@ -589,7 +620,7 @@ void JSObject::notifyPresenceOfIndexedAccessors(VM& vm)
if (mayInterceptIndexedAccesses())
return;
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AddIndexedAccessors));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AddIndexedAccessors));
if (!vm.prototypeMap.isPrototype(this))
return;
@@ -600,13 +631,13 @@ void JSObject::notifyPresenceOfIndexedAccessors(VM& vm)
Butterfly* JSObject::createInitialIndexedStorage(VM& vm, unsigned length, size_t elementSize)
{
ASSERT(length < MAX_ARRAY_INDEX);
- IndexingType oldType = structure()->indexingType();
+ IndexingType oldType = indexingType();
ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
ASSERT(!structure()->needsSlowPutIndexing());
ASSERT(!indexingShouldBeSparse());
unsigned vectorLength = std::max(length, BASE_VECTOR_LEN);
Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
- m_butterfly.get(), vm, this, structure(), structure()->outOfLineCapacity(), false, 0,
+ m_butterfly.get(this), vm, this, structure(), structure()->outOfLineCapacity(), false, 0,
elementSize * vectorLength);
newButterfly->setPublicLength(length);
newButterfly->setVectorLength(vectorLength);
@@ -617,7 +648,7 @@ Butterfly* JSObject::createInitialUndecided(VM& vm, unsigned length)
{
DeferGC deferGC(vm.heap);
Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateUndecided);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateUndecided);
setStructureAndButterfly(vm, newStructure, newButterfly);
return newButterfly;
}
@@ -626,7 +657,7 @@ ContiguousJSValues JSObject::createInitialInt32(VM& vm, unsigned length)
{
DeferGC deferGC(vm.heap);
Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateInt32);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateInt32);
setStructureAndButterfly(vm, newStructure, newButterfly);
return newButterfly->contiguousInt32();
}
@@ -636,8 +667,8 @@ ContiguousDoubles JSObject::createInitialDouble(VM& vm, unsigned length)
DeferGC deferGC(vm.heap);
Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(double));
for (unsigned i = newButterfly->vectorLength(); i--;)
- newButterfly->contiguousDouble()[i] = QNaN;
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateDouble);
+ newButterfly->contiguousDouble()[i] = PNaN;
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateDouble);
setStructureAndButterfly(vm, newStructure, newButterfly);
return newButterfly->contiguousDouble();
}
@@ -646,7 +677,7 @@ ContiguousJSValues JSObject::createInitialContiguous(VM& vm, unsigned length)
{
DeferGC deferGC(vm.heap);
Butterfly* newButterfly = createInitialIndexedStorage(vm, length, sizeof(EncodedJSValue));
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), AllocateContiguous);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous);
setStructureAndButterfly(vm, newStructure, newButterfly);
return newButterfly->contiguous();
}
@@ -654,10 +685,11 @@ ContiguousJSValues JSObject::createInitialContiguous(VM& vm, unsigned length)
ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vectorLength)
{
DeferGC deferGC(vm.heap);
- IndexingType oldType = structure()->indexingType();
+ Structure* structure = this->structure(vm);
+ IndexingType oldType = indexingType();
ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType));
Butterfly* newButterfly = Butterfly::createOrGrowArrayRight(
- m_butterfly.get(), vm, this, structure(), structure()->outOfLineCapacity(), false, 0,
+ m_butterfly.get(this), vm, this, structure, structure->outOfLineCapacity(), false, 0,
ArrayStorage::sizeFor(vectorLength));
RELEASE_ASSERT(newButterfly);
@@ -667,7 +699,7 @@ ArrayStorage* JSObject::createArrayStorage(VM& vm, unsigned length, unsigned vec
result->m_sparseMap.clear();
result->m_numValuesInVector = 0;
result->m_indexBias = 0;
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), structure()->suggestedArrayStorageTransition());
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure, structure->suggestedArrayStorageTransition());
setStructureAndButterfly(vm, newStructure, newButterfly);
return result;
}
@@ -679,41 +711,43 @@ ArrayStorage* JSObject::createInitialArrayStorage(VM& vm)
ContiguousJSValues JSObject::convertUndecidedToInt32(VM& vm)
{
- ASSERT(hasUndecided(structure()->indexingType()));
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateInt32));
- return m_butterfly->contiguousInt32();
+ ASSERT(hasUndecided(indexingType()));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateInt32));
+ return m_butterfly.get(this)->contiguousInt32();
}
ContiguousDoubles JSObject::convertUndecidedToDouble(VM& vm)
{
- ASSERT(hasUndecided(structure()->indexingType()));
-
- for (unsigned i = m_butterfly->vectorLength(); i--;)
- m_butterfly->contiguousDouble()[i] = QNaN;
+ ASSERT(hasUndecided(indexingType()));
+
+ Butterfly* butterfly = m_butterfly.get(this);
+ for (unsigned i = butterfly->vectorLength(); i--;)
+ butterfly->contiguousDouble()[i] = PNaN;
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble));
- return m_butterfly->contiguousDouble();
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateDouble));
+ return m_butterfly.get(this)->contiguousDouble();
}
ContiguousJSValues JSObject::convertUndecidedToContiguous(VM& vm)
{
- ASSERT(hasUndecided(structure()->indexingType()));
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
- return m_butterfly->contiguous();
+ ASSERT(hasUndecided(indexingType()));
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous));
+ return m_butterfly.get(this)->contiguous();
}
ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(VM& vm, unsigned neededLength)
{
- unsigned publicLength = m_butterfly->publicLength();
- unsigned propertyCapacity = structure()->outOfLineCapacity();
- unsigned propertySize = structure()->outOfLineSize();
+ Structure* structure = this->structure(vm);
+ unsigned publicLength = m_butterfly.get(this)->publicLength();
+ unsigned propertyCapacity = structure->outOfLineCapacity();
+ unsigned propertySize = structure->outOfLineSize();
Butterfly* newButterfly = Butterfly::createUninitialized(
vm, this, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength));
memcpy(
newButterfly->propertyStorage() - propertySize,
- m_butterfly->propertyStorage() - propertySize,
+ m_butterfly.get(this)->propertyStorage() - propertySize,
propertySize * sizeof(EncodedJSValue));
ArrayStorage* newStorage = newButterfly->arrayStorage();
@@ -726,182 +760,154 @@ ArrayStorage* JSObject::constructConvertedArrayStorageWithoutCopyingElements(VM&
return newStorage;
}
-ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
+ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition)
{
DeferGC deferGC(vm.heap);
- ASSERT(hasUndecided(structure()->indexingType()));
-
- ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
+ ASSERT(hasUndecided(indexingType()));
+
+ unsigned vectorLength = m_butterfly.get(this)->vectorLength();
+ ArrayStorage* storage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
// No need to copy elements.
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
setStructureAndButterfly(vm, newStructure, storage->butterfly());
return storage;
}
-ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm, NonPropertyTransition transition)
-{
- return convertUndecidedToArrayStorage(vm, transition, m_butterfly->vectorLength());
-}
-
ArrayStorage* JSObject::convertUndecidedToArrayStorage(VM& vm)
{
- return convertUndecidedToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
+ return convertUndecidedToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
}
ContiguousDoubles JSObject::convertInt32ToDouble(VM& vm)
{
- ASSERT(hasInt32(structure()->indexingType()));
-
- for (unsigned i = m_butterfly->vectorLength(); i--;) {
- WriteBarrier<Unknown>* current = &m_butterfly->contiguousInt32()[i];
+ ASSERT(hasInt32(indexingType()));
+
+ Butterfly* butterfly = m_butterfly.get(this);
+ for (unsigned i = butterfly->vectorLength(); i--;) {
+ WriteBarrier<Unknown>* current = &butterfly->contiguousInt32()[i];
double* currentAsDouble = bitwise_cast<double*>(current);
JSValue v = current->get();
if (!v) {
- *currentAsDouble = QNaN;
+ *currentAsDouble = PNaN;
continue;
}
ASSERT(v.isInt32());
*currentAsDouble = v.asInt32();
}
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateDouble));
- return m_butterfly->contiguousDouble();
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateDouble));
+ return m_butterfly.get(this)->contiguousDouble();
}
ContiguousJSValues JSObject::convertInt32ToContiguous(VM& vm)
{
- ASSERT(hasInt32(structure()->indexingType()));
+ ASSERT(hasInt32(indexingType()));
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
- return m_butterfly->contiguous();
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous));
+ return m_butterfly.get(this)->contiguous();
}
-ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
+ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition)
{
- ASSERT(hasInt32(structure()->indexingType()));
-
DeferGC deferGC(vm.heap);
- ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
- for (unsigned i = m_butterfly->publicLength(); i--;) {
- JSValue v = m_butterfly->contiguous()[i].get();
- if (!v)
- continue;
- newStorage->m_vector[i].setWithoutWriteBarrier(v);
- newStorage->m_numValuesInVector++;
+ ASSERT(hasInt32(indexingType()));
+
+ unsigned vectorLength = m_butterfly.get(this)->vectorLength();
+ ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
+ Butterfly* butterfly = m_butterfly.get(this);
+ for (unsigned i = 0; i < butterfly->publicLength(); i++) {
+ JSValue v = butterfly->contiguous()[i].get();
+ if (v) {
+ newStorage->m_vector[i].setWithoutWriteBarrier(v);
+ newStorage->m_numValuesInVector++;
+ } else
+ ASSERT(newStorage->m_vector[i].get().isEmpty());
}
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
setStructureAndButterfly(vm, newStructure, newStorage->butterfly());
return newStorage;
}
-ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm, NonPropertyTransition transition)
-{
- return convertInt32ToArrayStorage(vm, transition, m_butterfly->vectorLength());
-}
-
ArrayStorage* JSObject::convertInt32ToArrayStorage(VM& vm)
{
- return convertInt32ToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
+ return convertInt32ToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
}
-template<JSObject::DoubleToContiguousMode mode>
-ContiguousJSValues JSObject::genericConvertDoubleToContiguous(VM& vm)
+ContiguousJSValues JSObject::convertDoubleToContiguous(VM& vm)
{
- ASSERT(hasDouble(structure()->indexingType()));
-
- for (unsigned i = m_butterfly->vectorLength(); i--;) {
- double* current = &m_butterfly->contiguousDouble()[i];
+ ASSERT(hasDouble(indexingType()));
+
+ Butterfly* butterfly = m_butterfly.get(this);
+ for (unsigned i = butterfly->vectorLength(); i--;) {
+ double* current = &butterfly->contiguousDouble()[i];
WriteBarrier<Unknown>* currentAsValue = bitwise_cast<WriteBarrier<Unknown>*>(current);
double value = *current;
if (value != value) {
currentAsValue->clear();
continue;
}
- JSValue v;
- switch (mode) {
- case EncodeValueAsDouble:
- v = JSValue(JSValue::EncodeAsDouble, value);
- break;
- case RageConvertDoubleToValue:
- v = jsNumber(value);
- break;
- }
- ASSERT(v.isNumber());
+ JSValue v = JSValue(JSValue::EncodeAsDouble, value);
currentAsValue->setWithoutWriteBarrier(v);
}
- setStructure(vm, Structure::nonPropertyTransition(vm, structure(), AllocateContiguous));
- return m_butterfly->contiguous();
-}
-
-ContiguousJSValues JSObject::convertDoubleToContiguous(VM& vm)
-{
- return genericConvertDoubleToContiguous<EncodeValueAsDouble>(vm);
+ setStructure(vm, Structure::nonPropertyTransition(vm, structure(vm), AllocateContiguous));
+ return m_butterfly.get(this)->contiguous();
}
-ContiguousJSValues JSObject::rageConvertDoubleToContiguous(VM& vm)
-{
- return genericConvertDoubleToContiguous<RageConvertDoubleToValue>(vm);
-}
-
-ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
+ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition)
{
DeferGC deferGC(vm.heap);
- ASSERT(hasDouble(structure()->indexingType()));
-
- ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
- for (unsigned i = m_butterfly->publicLength(); i--;) {
- double value = m_butterfly->contiguousDouble()[i];
- if (value != value)
- continue;
- newStorage->m_vector[i].setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value));
- newStorage->m_numValuesInVector++;
+ ASSERT(hasDouble(indexingType()));
+
+ unsigned vectorLength = m_butterfly.get(this)->vectorLength();
+ ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
+ Butterfly* butterfly = m_butterfly.get(this);
+ for (unsigned i = 0; i < butterfly->publicLength(); i++) {
+ double value = butterfly->contiguousDouble()[i];
+ if (value == value) {
+ newStorage->m_vector[i].setWithoutWriteBarrier(JSValue(JSValue::EncodeAsDouble, value));
+ newStorage->m_numValuesInVector++;
+ } else
+ ASSERT(newStorage->m_vector[i].get().isEmpty());
}
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
setStructureAndButterfly(vm, newStructure, newStorage->butterfly());
return newStorage;
}
-ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm, NonPropertyTransition transition)
-{
- return convertDoubleToArrayStorage(vm, transition, m_butterfly->vectorLength());
-}
-
ArrayStorage* JSObject::convertDoubleToArrayStorage(VM& vm)
{
- return convertDoubleToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
+ return convertDoubleToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
}
-ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition, unsigned neededLength)
+ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition)
{
DeferGC deferGC(vm.heap);
- ASSERT(hasContiguous(structure()->indexingType()));
-
- ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, neededLength);
- for (unsigned i = m_butterfly->publicLength(); i--;) {
- JSValue v = m_butterfly->contiguous()[i].get();
- if (!v)
- continue;
- newStorage->m_vector[i].setWithoutWriteBarrier(v);
- newStorage->m_numValuesInVector++;
+ ASSERT(hasContiguous(indexingType()));
+
+ unsigned vectorLength = m_butterfly.get(this)->vectorLength();
+ ArrayStorage* newStorage = constructConvertedArrayStorageWithoutCopyingElements(vm, vectorLength);
+ Butterfly* butterfly = m_butterfly.get(this);
+ for (unsigned i = 0; i < butterfly->publicLength(); i++) {
+ JSValue v = butterfly->contiguous()[i].get();
+ if (v) {
+ newStorage->m_vector[i].setWithoutWriteBarrier(v);
+ newStorage->m_numValuesInVector++;
+ } else
+ ASSERT(newStorage->m_vector[i].get().isEmpty());
}
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), transition);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), transition);
setStructureAndButterfly(vm, newStructure, newStorage->butterfly());
return newStorage;
}
-ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm, NonPropertyTransition transition)
-{
- return convertContiguousToArrayStorage(vm, transition, m_butterfly->vectorLength());
-}
-
ArrayStorage* JSObject::convertContiguousToArrayStorage(VM& vm)
{
- return convertContiguousToArrayStorage(vm, structure()->suggestedArrayStorageTransition());
+ return convertContiguousToArrayStorage(vm, structure(vm)->suggestedArrayStorageTransition());
}
void JSObject::convertUndecidedForValue(VM& vm, JSValue value)
@@ -941,7 +947,7 @@ void JSObject::convertInt32ForValue(VM& vm, JSValue value)
{
ASSERT(!value.isInt32());
- if (value.isDouble()) {
+ if (value.isDouble() && !std::isnan(value.asDouble())) {
convertInt32ToDouble(vm);
return;
}
@@ -951,8 +957,8 @@ void JSObject::convertInt32ForValue(VM& vm, JSValue value)
void JSObject::setIndexQuicklyToUndecided(VM& vm, unsigned index, JSValue value)
{
- ASSERT(index < m_butterfly->publicLength());
- ASSERT(index < m_butterfly->vectorLength());
+ ASSERT(index < m_butterfly.get(this)->publicLength());
+ ASSERT(index < m_butterfly.get(this)->vectorLength());
convertUndecidedForValue(vm, value);
setIndexQuickly(vm, index, value);
}
@@ -975,9 +981,12 @@ ContiguousJSValues JSObject::ensureInt32Slow(VM& vm)
{
ASSERT(inherits(info()));
- switch (structure()->indexingType()) {
+ if (structure(vm)->hijacksIndexingHeader())
+ return ContiguousJSValues();
+
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
- if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
+ if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing()))
return ContiguousJSValues();
return createInitialInt32(vm, 0);
@@ -999,9 +1008,12 @@ ContiguousDoubles JSObject::ensureDoubleSlow(VM& vm)
{
ASSERT(inherits(info()));
- switch (structure()->indexingType()) {
+ if (structure(vm)->hijacksIndexingHeader())
+ return ContiguousDoubles();
+
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
- if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
+ if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing()))
return ContiguousDoubles();
return createInitialDouble(vm, 0);
@@ -1021,13 +1033,16 @@ ContiguousDoubles JSObject::ensureDoubleSlow(VM& vm)
}
}
-ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm, DoubleToContiguousMode mode)
+ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm)
{
ASSERT(inherits(info()));
- switch (structure()->indexingType()) {
+ if (structure(vm)->hijacksIndexingHeader())
+ return ContiguousJSValues();
+
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
- if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing()))
+ if (UNLIKELY(indexingShouldBeSparse() || structure(vm)->needsSlowPutIndexing()))
return ContiguousJSValues();
return createInitialContiguous(vm, 0);
@@ -1038,8 +1053,6 @@ ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm, DoubleToContiguousMode
return convertInt32ToContiguous(vm);
case ALL_DOUBLE_INDEXING_TYPES:
- if (mode == RageConvertDoubleToValue)
- return rageConvertDoubleToContiguous(vm);
return convertDoubleToContiguous(vm);
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
@@ -1051,21 +1064,14 @@ ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm, DoubleToContiguousMode
}
}
-ContiguousJSValues JSObject::ensureContiguousSlow(VM& vm)
-{
- return ensureContiguousSlow(vm, EncodeValueAsDouble);
-}
-
-ContiguousJSValues JSObject::rageEnsureContiguousSlow(VM& vm)
-{
- return ensureContiguousSlow(vm, RageConvertDoubleToValue);
-}
-
ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm)
{
ASSERT(inherits(info()));
+
+ if (structure(vm)->hijacksIndexingHeader())
+ return nullptr;
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
if (UNLIKELY(indexingShouldBeSparse()))
return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm);
@@ -1073,22 +1079,22 @@ ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm)
case ALL_UNDECIDED_INDEXING_TYPES:
ASSERT(!indexingShouldBeSparse());
- ASSERT(!structure()->needsSlowPutIndexing());
+ ASSERT(!structure(vm)->needsSlowPutIndexing());
return convertUndecidedToArrayStorage(vm);
case ALL_INT32_INDEXING_TYPES:
ASSERT(!indexingShouldBeSparse());
- ASSERT(!structure()->needsSlowPutIndexing());
+ ASSERT(!structure(vm)->needsSlowPutIndexing());
return convertInt32ToArrayStorage(vm);
case ALL_DOUBLE_INDEXING_TYPES:
ASSERT(!indexingShouldBeSparse());
- ASSERT(!structure()->needsSlowPutIndexing());
+ ASSERT(!structure(vm)->needsSlowPutIndexing());
return convertDoubleToArrayStorage(vm);
case ALL_CONTIGUOUS_INDEXING_TYPES:
ASSERT(!indexingShouldBeSparse());
- ASSERT(!structure()->needsSlowPutIndexing());
+ ASSERT(!structure(vm)->needsSlowPutIndexing());
return convertContiguousToArrayStorage(vm);
default:
@@ -1099,7 +1105,7 @@ ArrayStorage* JSObject::ensureArrayStorageSlow(VM& vm)
ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM& vm)
{
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES: {
createArrayStorage(vm, 0, 0);
SparseArrayValueMap* map = allocateSparseIndexMap(vm);
@@ -1120,7 +1126,7 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(V
return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, convertContiguousToArrayStorage(vm));
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly->arrayStorage());
+ return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(vm, m_butterfly.get(this)->arrayStorage());
default:
CRASH();
@@ -1130,7 +1136,7 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(V
void JSObject::switchToSlowPutArrayStorage(VM& vm)
{
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_UNDECIDED_INDEXING_TYPES:
convertUndecidedToArrayStorage(vm, AllocateSlowPutArrayStorage);
break;
@@ -1149,7 +1155,7 @@ void JSObject::switchToSlowPutArrayStorage(VM& vm)
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage: {
- Structure* newStructure = Structure::nonPropertyTransition(vm, structure(), SwitchToSlowPutArrayStorage);
+ Structure* newStructure = Structure::nonPropertyTransition(vm, structure(vm), SwitchToSlowPutArrayStorage);
setStructure(vm, newStructure);
break;
}
@@ -1166,7 +1172,7 @@ void JSObject::setPrototype(VM& vm, JSValue prototype)
if (prototype.isObject())
vm.prototypeMap.addPrototype(asObject(prototype));
- Structure* newStructure = Structure::changePrototypeTransition(vm, structure(), prototype);
+ Structure* newStructure = Structure::changePrototypeTransition(vm, structure(vm), prototype);
setStructure(vm, newStructure);
if (!newStructure->anyObjectInChainMayInterceptIndexedAccesses())
@@ -1177,10 +1183,10 @@ void JSObject::setPrototype(VM& vm, JSValue prototype)
return;
}
- if (!hasIndexedProperties(structure()->indexingType()))
+ if (!hasIndexedProperties(indexingType()))
return;
- if (shouldUseSlowPut(structure()->indexingType()))
+ if (shouldUseSlowPut(indexingType()))
return;
switchToSlowPutArrayStorage(vm);
@@ -1188,7 +1194,7 @@ void JSObject::setPrototype(VM& vm, JSValue prototype)
bool JSObject::setPrototypeWithCycleCheck(ExecState* exec, JSValue prototype)
{
- ASSERT(methodTable()->toThis(this, exec, NotStrictMode) == this);
+ ASSERT(methodTable(exec->vm())->toThis(this, exec, NotStrictMode) == this);
JSValue nextPrototype = prototype;
while (nextPrototype && nextPrototype.isObject()) {
if (nextPrototype == this)
@@ -1205,45 +1211,84 @@ bool JSObject::allowsAccessFrom(ExecState* exec)
return globalObject->globalObjectMethodTable()->allowsAccessFrom(globalObject, exec);
}
+void JSObject::putGetter(ExecState* exec, PropertyName propertyName, JSValue getter, unsigned attributes)
+{
+ PropertyDescriptor descriptor;
+ descriptor.setGetter(getter);
+
+ ASSERT(attributes & Accessor);
+ if (!(attributes & ReadOnly))
+ descriptor.setConfigurable(true);
+ if (!(attributes & DontEnum))
+ descriptor.setEnumerable(true);
+
+ defineOwnProperty(this, exec, propertyName, descriptor, false);
+}
+
+void JSObject::putSetter(ExecState* exec, PropertyName propertyName, JSValue setter, unsigned attributes)
+{
+ PropertyDescriptor descriptor;
+ descriptor.setSetter(setter);
+
+ ASSERT(attributes & Accessor);
+ if (!(attributes & ReadOnly))
+ descriptor.setConfigurable(true);
+ if (!(attributes & DontEnum))
+ descriptor.setEnumerable(true);
+
+ defineOwnProperty(this, exec, propertyName, descriptor, false);
+}
+
void JSObject::putDirectAccessor(ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes)
{
ASSERT(value.isGetterSetter() && (attributes & Accessor));
- unsigned index = propertyName.asIndex();
- if (index != PropertyName::NotAnIndex) {
- putDirectIndex(exec, index, value, attributes, PutDirectIndexLikePutDirect);
+ if (Optional<uint32_t> index = parseIndex(propertyName)) {
+ putDirectIndex(exec, index.value(), value, attributes, PutDirectIndexLikePutDirect);
return;
}
putDirectNonIndexAccessor(exec->vm(), propertyName, value, attributes);
}
-void JSObject::putDirectNonIndexAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
+void JSObject::putDirectCustomAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
{
+ ASSERT(!parseIndex(propertyName));
+
PutPropertySlot slot(this);
- putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot, getCallableObject(value));
+ putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
- // putDirect will change our Structure if we add a new property. For
- // getters and setters, though, we also need to change our Structure
- // if we override an existing non-getter or non-setter.
- if (slot.type() != PutPropertySlot::NewProperty)
- setStructure(vm, Structure::attributeChangeTransition(vm, structure(), propertyName, attributes));
+ ASSERT(slot.type() == PutPropertySlot::NewProperty);
+ Structure* structure = this->structure(vm);
if (attributes & ReadOnly)
- structure()->setContainsReadOnlyProperties();
+ structure->setContainsReadOnlyProperties();
+ structure->setHasCustomGetterSetterPropertiesWithProtoCheck(propertyName == vm.propertyNames->underscoreProto);
+}
+
+void JSObject::putDirectNonIndexAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
+{
+ PutPropertySlot slot(this);
+ putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
+
+ Structure* structure = this->structure(vm);
+ if (attributes & ReadOnly)
+ structure->setContainsReadOnlyProperties();
- structure()->setHasGetterSetterProperties(propertyName == vm.propertyNames->underscoreProto);
+ structure->setHasGetterSetterPropertiesWithProtoCheck(propertyName == vm.propertyNames->underscoreProto);
}
+// HasProperty(O, P) from Section 7.3.10 of the spec.
+// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasproperty
bool JSObject::hasProperty(ExecState* exec, PropertyName propertyName) const
{
- PropertySlot slot(this);
+ PropertySlot slot(this, PropertySlot::InternalMethodType::HasProperty);
return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
}
bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const
{
- PropertySlot slot(this);
+ PropertySlot slot(this, PropertySlot::InternalMethodType::HasProperty);
return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
}
@@ -1251,40 +1296,36 @@ bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const
bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
{
JSObject* thisObject = jsCast<JSObject*>(cell);
+ VM& vm = exec->vm();
- unsigned i = propertyName.asIndex();
- if (i != PropertyName::NotAnIndex)
- return thisObject->methodTable()->deletePropertyByIndex(thisObject, exec, i);
+ if (Optional<uint32_t> index = parseIndex(propertyName))
+ return thisObject->methodTable(vm)->deletePropertyByIndex(thisObject, exec, index.value());
if (!thisObject->staticFunctionsReified())
- thisObject->reifyStaticFunctionsForDelete(exec);
+ thisObject->reifyAllStaticProperties(exec);
unsigned attributes;
- JSCell* specificValue;
- if (isValidOffset(thisObject->structure()->get(exec->vm(), propertyName, attributes, specificValue))) {
- if (attributes & DontDelete && !exec->vm().isInDefineOwnProperty())
+ if (isValidOffset(thisObject->structure(vm)->get(vm, propertyName, attributes))) {
+ if (attributes & DontDelete && !vm.isInDefineOwnProperty())
return false;
- thisObject->removeDirect(exec->vm(), propertyName);
- return true;
- }
-
- // Look in the static hashtable of properties
- const HashEntry* entry = thisObject->findPropertyHashEntry(exec, propertyName);
- if (entry) {
- if (entry->attributes() & DontDelete && !exec->vm().isInDefineOwnProperty())
- return false; // this builtin property can't be deleted
-
- PutPropertySlot slot(thisObject);
- putEntry(exec, entry, thisObject, propertyName, jsUndefined(), slot);
+ thisObject->removeDirect(vm, propertyName);
}
return true;
}
+// HasOwnProperty(O, P) from section 7.3.11 in the spec.
+// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasownproperty
bool JSObject::hasOwnProperty(ExecState* exec, PropertyName propertyName) const
{
- PropertySlot slot(this);
- return const_cast<JSObject*>(this)->methodTable()->getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot);
+ PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
+ return const_cast<JSObject*>(this)->methodTable(exec->vm())->getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot);
+}
+
+bool JSObject::hasOwnProperty(ExecState* exec, unsigned propertyName) const
+{
+ PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
+ return const_cast<JSObject*>(this)->methodTable(exec->vm())->getOwnPropertySlotByIndex(const_cast<JSObject*>(this), exec, propertyName, slot);
}
bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
@@ -1292,9 +1333,9 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
JSObject* thisObject = jsCast<JSObject*>(cell);
if (i > MAX_ARRAY_INDEX)
- return thisObject->methodTable()->deleteProperty(thisObject, exec, Identifier::from(exec, i));
+ return thisObject->methodTable(exec->vm())->deleteProperty(thisObject, exec, Identifier::from(exec, i));
- switch (thisObject->structure()->indexingType()) {
+ switch (thisObject->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
return true;
@@ -1312,12 +1353,12 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
Butterfly* butterfly = thisObject->butterfly();
if (i >= butterfly->vectorLength())
return true;
- butterfly->contiguousDouble()[i] = QNaN;
+ butterfly->contiguousDouble()[i] = PNaN;
return true;
}
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
- ArrayStorage* storage = thisObject->m_butterfly->arrayStorage();
+ ArrayStorage* storage = thisObject->m_butterfly.get(thisObject)->arrayStorage();
if (i < storage->vectorLength()) {
WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
@@ -1367,7 +1408,7 @@ static ALWAYS_INLINE JSValue callDefaultValueFunction(ExecState* exec, const JSO
bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const
{
- result = methodTable()->defaultValue(this, exec, PreferNumber);
+ result = methodTable(exec->vm())->defaultValue(this, exec, PreferNumber);
number = result.toNumber(exec);
return !result.isString();
}
@@ -1375,6 +1416,10 @@ bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& resu
// ECMA 8.6.2.6
JSValue JSObject::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint)
{
+ // Make sure that whatever default value methods there are on object's prototype chain are
+ // being watched.
+ object->structure()->startWatchingInternalPropertiesIfNecessaryForEntireChain(exec->vm());
+
// Must call toString first for Date objects.
if ((hint == PreferString) || (hint != PreferNumber && object->prototype() == exec->lexicalGlobalObject()->datePrototype())) {
JSValue value = callDefaultValueFunction(exec, object, exec->propertyNames().toString);
@@ -1397,28 +1442,51 @@ JSValue JSObject::defaultValue(const JSObject* object, ExecState* exec, Preferre
return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("No default value")));
}
-const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, PropertyName propertyName) const
+const HashTableValue* JSObject::findPropertyHashEntry(PropertyName propertyName) const
{
for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
- if (const HashTable* propHashTable = info->propHashTable(exec)) {
- if (const HashEntry* entry = propHashTable->entry(exec, propertyName))
+ if (const HashTable* propHashTable = info->staticPropHashTable) {
+ if (const HashTableValue* entry = propHashTable->entry(propertyName))
return entry;
}
}
return 0;
}
-bool JSObject::hasInstance(ExecState* exec, JSValue value)
+bool JSObject::hasInstance(ExecState* exec, JSValue value, JSValue hasInstanceValue)
{
- TypeInfo info = structure()->typeInfo();
+ VM& vm = exec->vm();
+
+ if (!hasInstanceValue.isUndefinedOrNull() && hasInstanceValue != exec->lexicalGlobalObject()->functionProtoHasInstanceSymbolFunction()) {
+ CallData callData;
+ CallType callType = JSC::getCallData(hasInstanceValue, callData);
+ if (callType == CallTypeNone) {
+ vm.throwException(exec, createInvalidInstanceofParameterErrorhasInstanceValueNotFunction(exec, this));
+ return false;
+ }
+
+ MarkedArgumentBuffer args;
+ args.append(value);
+ JSValue result = call(exec, hasInstanceValue, callType, callData, this, args);
+ return result.toBoolean(exec);
+ }
+
+ TypeInfo info = structure(vm)->typeInfo();
if (info.implementsDefaultHasInstance())
return defaultHasInstance(exec, value, get(exec, exec->propertyNames().prototype));
if (info.implementsHasInstance())
- return methodTable()->customHasInstance(this, exec, value);
- exec->vm().throwException(exec, createInvalidParameterError(exec, "instanceof" , this));
+ return methodTable(vm)->customHasInstance(this, exec, value);
+ vm.throwException(exec, createInvalidInstanceofParameterErrorNotFunction(exec, this));
return false;
}
+bool JSObject::hasInstance(ExecState* exec, JSValue value)
+{
+ JSValue hasInstanceValue = get(exec, exec->propertyNames().hasInstanceSymbol);
+
+ return hasInstance(exec, value, hasInstanceValue);
+}
+
bool JSObject::defaultHasInstance(ExecState* exec, JSValue value, JSValue proto)
{
if (!value.isObject())
@@ -1437,34 +1505,29 @@ bool JSObject::defaultHasInstance(ExecState* exec, JSValue value, JSValue proto)
return false;
}
-bool JSObject::getPropertySpecificValue(ExecState* exec, PropertyName propertyName, JSCell*& specificValue) const
+EncodedJSValue JSC_HOST_CALL objectPrivateFuncInstanceOf(ExecState* exec)
{
- unsigned attributes;
- if (isValidOffset(structure()->get(exec->vm(), propertyName, attributes, specificValue)))
- return true;
+ JSValue value = exec->uncheckedArgument(0);
+ JSValue proto = exec->uncheckedArgument(1);
- // This could be a function within the static table? - should probably
- // also look in the hash? This currently should not be a problem, since
- // we've currently always call 'get' first, which should have populated
- // the normal storage.
- return false;
+ return JSValue::encode(jsBoolean(JSObject::defaultHasInstance(exec, value, proto)));
}
void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
- propertyNames.setBaseObject(object);
- object->methodTable()->getOwnPropertyNames(object, exec, propertyNames, mode);
+ object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, propertyNames, mode);
if (object->prototype().isNull())
return;
+ VM& vm = exec->vm();
JSObject* prototype = asObject(object->prototype());
while(1) {
- if (prototype->structure()->typeInfo().overridesGetPropertyNames()) {
- prototype->methodTable()->getPropertyNames(prototype, exec, propertyNames, mode);
+ if (prototype->structure(vm)->typeInfo().overridesGetPropertyNames()) {
+ prototype->methodTable(vm)->getPropertyNames(prototype, exec, propertyNames, mode);
break;
}
- prototype->methodTable()->getOwnPropertyNames(prototype, exec, propertyNames, mode);
+ prototype->methodTable(vm)->getOwnPropertyNames(prototype, exec, propertyNames, mode);
JSValue nextProto = prototype->prototype();
if (nextProto.isNull())
break;
@@ -1474,81 +1537,90 @@ void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameA
void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
- // Add numeric properties first. That appears to be the accepted convention.
- // FIXME: Filling PropertyNameArray with an identifier for every integer
- // is incredibly inefficient for large arrays. We need a different approach,
- // which almost certainly means a different structure for PropertyNameArray.
- switch (object->structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
- case ALL_UNDECIDED_INDEXING_TYPES:
- break;
-
- case ALL_INT32_INDEXING_TYPES:
- case ALL_CONTIGUOUS_INDEXING_TYPES: {
- Butterfly* butterfly = object->butterfly();
- unsigned usedLength = butterfly->publicLength();
- for (unsigned i = 0; i < usedLength; ++i) {
- if (!butterfly->contiguous()[i])
- continue;
- propertyNames.add(Identifier::from(exec, i));
- }
- break;
+ if (!mode.includeJSObjectProperties()) {
+ // We still have to get non-indexed properties from any subclasses of JSObject that have them.
+ object->methodTable(exec->vm())->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
+ return;
}
-
- case ALL_DOUBLE_INDEXING_TYPES: {
- Butterfly* butterfly = object->butterfly();
- unsigned usedLength = butterfly->publicLength();
- for (unsigned i = 0; i < usedLength; ++i) {
- double value = butterfly->contiguousDouble()[i];
- if (value != value)
- continue;
- propertyNames.add(Identifier::from(exec, i));
+
+ if (propertyNames.includeStringProperties()) {
+ // Add numeric properties first. That appears to be the accepted convention.
+ // FIXME: Filling PropertyNameArray with an identifier for every integer
+ // is incredibly inefficient for large arrays. We need a different approach,
+ // which almost certainly means a different structure for PropertyNameArray.
+ switch (object->indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ break;
+
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ Butterfly* butterfly = object->butterfly();
+ unsigned usedLength = butterfly->publicLength();
+ for (unsigned i = 0; i < usedLength; ++i) {
+ if (!butterfly->contiguous()[i])
+ continue;
+ propertyNames.add(i);
+ }
+ break;
}
- break;
- }
-
- case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
- ArrayStorage* storage = object->m_butterfly->arrayStorage();
-
- unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
- for (unsigned i = 0; i < usedVectorLength; ++i) {
- if (storage->m_vector[i])
- propertyNames.add(Identifier::from(exec, i));
+
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ Butterfly* butterfly = object->butterfly();
+ unsigned usedLength = butterfly->publicLength();
+ for (unsigned i = 0; i < usedLength; ++i) {
+ double value = butterfly->contiguousDouble()[i];
+ if (value != value)
+ continue;
+ propertyNames.add(i);
+ }
+ break;
}
-
- if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
- Vector<unsigned, 0, UnsafeVectorOverflow> keys;
- keys.reserveInitialCapacity(map->size());
- SparseArrayValueMap::const_iterator end = map->end();
- for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
- if (mode == IncludeDontEnumProperties || !(it->value.attributes & DontEnum))
- keys.uncheckedAppend(static_cast<unsigned>(it->key));
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
+ ArrayStorage* storage = object->m_butterfly.get(object)->arrayStorage();
+
+ unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
+ for (unsigned i = 0; i < usedVectorLength; ++i) {
+ if (storage->m_vector[i])
+ propertyNames.add(i);
+ }
+
+ if (SparseArrayValueMap* map = storage->m_sparseMap.get()) {
+ Vector<unsigned, 0, UnsafeVectorOverflow> keys;
+ keys.reserveInitialCapacity(map->size());
+
+ SparseArrayValueMap::const_iterator end = map->end();
+ for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
+ if (mode.includeDontEnumProperties() || !(it->value.attributes & DontEnum))
+ keys.uncheckedAppend(static_cast<unsigned>(it->key));
+ }
+
+ std::sort(keys.begin(), keys.end());
+ for (unsigned i = 0; i < keys.size(); ++i)
+ propertyNames.add(keys[i]);
}
+ break;
+ }
- std::sort(keys.begin(), keys.end());
- for (unsigned i = 0; i < keys.size(); ++i)
- propertyNames.add(Identifier::from(exec, keys[i]));
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
}
- break;
}
-
- default:
- RELEASE_ASSERT_NOT_REACHED();
- }
-
- object->methodTable()->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
+
+ object->methodTable(exec->vm())->getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
}
void JSObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
- getClassPropertyNames(exec, object->classInfo(), propertyNames, mode, object->staticFunctionsReified());
-
- bool canCachePropertiesFromStructure = !propertyNames.size();
- object->structure()->getPropertyNamesFromStructure(exec->vm(), propertyNames, mode);
+ if (!object->staticFunctionsReified())
+ getClassPropertyNames(exec, object->classInfo(), propertyNames, mode);
- if (canCachePropertiesFromStructure)
- propertyNames.setNumCacheableSlotsForObject(object, propertyNames.size());
+ if (!mode.includeJSObjectProperties())
+ return;
+
+ VM& vm = exec->vm();
+ object->structure(vm)->getPropertyNamesFromStructure(vm, propertyNames, mode);
}
double JSObject::toNumber(ExecState* exec) const
@@ -1576,28 +1648,27 @@ void JSObject::seal(VM& vm)
{
if (isSealed(vm))
return;
- preventExtensions(vm);
- setStructure(vm, Structure::sealTransition(vm, structure()));
+ enterDictionaryIndexingMode(vm);
+ setStructure(vm, Structure::sealTransition(vm, structure(vm)));
}
void JSObject::freeze(VM& vm)
{
if (isFrozen(vm))
return;
- preventExtensions(vm);
- setStructure(vm, Structure::freezeTransition(vm, structure()));
+ enterDictionaryIndexingMode(vm);
+ setStructure(vm, Structure::freezeTransition(vm, structure(vm)));
}
void JSObject::preventExtensions(VM& vm)
{
+ if (!isExtensible())
+ return;
enterDictionaryIndexingMode(vm);
- if (isExtensible())
- setStructure(vm, Structure::preventExtensionsTransition(vm, structure()));
+ setStructure(vm, Structure::preventExtensionsTransition(vm, structure(vm)));
}
-// This presently will flatten to an uncachable dictionary; this is suitable
-// for use in delete, we may want to do something different elsewhere.
-void JSObject::reifyStaticFunctionsForDelete(ExecState* exec)
+void JSObject::reifyAllStaticProperties(ExecState* exec)
{
ASSERT(!staticFunctionsReified());
VM& vm = exec->vm();
@@ -1605,42 +1676,45 @@ void JSObject::reifyStaticFunctionsForDelete(ExecState* exec)
// If this object's ClassInfo has no static properties, then nothing to reify!
// We can safely set the flag to avoid the expensive check again in the future.
if (!classInfo()->hasStaticProperties()) {
- structure()->setStaticFunctionsReified();
+ structure(vm)->setStaticFunctionsReified(true);
return;
}
- if (!structure()->isUncacheableDictionary())
- setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure()));
+ if (!structure(vm)->isUncacheableDictionary())
+ setStructure(vm, Structure::toUncacheableDictionaryTransition(vm, structure(vm)));
for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
- const HashTable* hashTable = info->propHashTable(globalObject()->globalExec());
+ const HashTable* hashTable = info->staticPropHashTable;
if (!hashTable)
continue;
- PropertySlot slot(this);
- for (HashTable::ConstIterator iter = hashTable->begin(vm); iter != hashTable->end(vm); ++iter) {
- if (iter->attributes() & Function)
- setUpStaticFunctionSlot(globalObject()->globalExec(), *iter, this, Identifier(&vm, iter->key()), slot);
+
+ for (auto& value : *hashTable) {
+ unsigned attributes;
+ PropertyOffset offset = getDirectOffset(vm, Identifier::fromString(&vm, value.m_key), attributes);
+ if (!isValidOffset(offset))
+ reifyStaticProperty(vm, value, *this);
}
}
- structure()->setStaticFunctionsReified();
+ structure(vm)->setStaticFunctionsReified(true);
}
bool JSObject::removeDirect(VM& vm, PropertyName propertyName)
{
- if (!isValidOffset(structure()->get(vm, propertyName)))
+ Structure* structure = this->structure(vm);
+ if (!isValidOffset(structure->get(vm, propertyName)))
return false;
PropertyOffset offset;
- if (structure()->isUncacheableDictionary()) {
- offset = structure()->removePropertyWithoutTransition(vm, propertyName);
+ if (structure->isUncacheableDictionary()) {
+ offset = structure->removePropertyWithoutTransition(vm, propertyName);
if (offset == invalidOffset)
return false;
putDirectUndefined(offset);
return true;
}
- setStructure(vm, Structure::removePropertyTransition(vm, structure(), propertyName, offset));
+ setStructure(vm, Structure::removePropertyTransition(vm, structure, propertyName, offset));
if (offset == invalidOffset)
return false;
putDirectUndefined(offset);
@@ -1653,19 +1727,19 @@ NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue g
slot.setGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter));
return;
}
-
slot.setCacheableGetterSlot(this, attributes, jsCast<GetterSetter*>(getterSetter), offset);
}
void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMap, const PropertyDescriptor& descriptor, PropertyDescriptor& oldDescriptor)
{
VM& vm = exec->vm();
+ auto map = m_butterfly.get(this)->arrayStorage()->m_sparseMap.get();
if (descriptor.isDataDescriptor()) {
if (descriptor.value())
- entryInMap->set(vm, this, descriptor.value());
+ entryInMap->set(vm, map, descriptor.value());
else if (oldDescriptor.isAccessorDescriptor())
- entryInMap->set(vm, this, jsUndefined());
+ entryInMap->set(vm, map, jsUndefined());
entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~Accessor;
return;
}
@@ -1682,13 +1756,13 @@ void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMa
else if (oldDescriptor.isAccessorDescriptor())
setter = oldDescriptor.setterObject();
- GetterSetter* accessor = GetterSetter::create(vm);
+ GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject());
if (getter)
- accessor->setGetter(vm, getter);
+ accessor->setGetter(vm, exec->lexicalGlobalObject(), getter);
if (setter)
- accessor->setSetter(vm, setter);
+ accessor->setSetter(vm, exec->lexicalGlobalObject(), setter);
- entryInMap->set(vm, this, accessor);
+ entryInMap->set(vm, map, accessor);
entryInMap->attributes = descriptor.attributesOverridingCurrent(oldDescriptor) & ~ReadOnly;
return;
}
@@ -1701,13 +1775,13 @@ void JSObject::putIndexedDescriptor(ExecState* exec, SparseArrayEntry* entryInMa
bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, const PropertyDescriptor& descriptor, bool throwException)
{
ASSERT(index <= MAX_ARRAY_INDEX);
-
+
if (!inSparseIndexingMode()) {
// Fast case: we're putting a regular property to a regular array
// FIXME: this will pessimistically assume that if attributes are missing then they'll default to false
// however if the property currently exists missing attributes will override from their current 'true'
// state (i.e. defineOwnProperty could be used to set a value without needing to entering 'SparseMode').
- if (!descriptor.attributes()) {
+ if (!descriptor.attributes() && descriptor.value()) {
ASSERT(!descriptor.isAccessorDescriptor());
return putDirectIndex(exec, index, descriptor.value(), 0, throwException ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
}
@@ -1718,7 +1792,7 @@ bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, const P
if (descriptor.attributes() & (ReadOnly | Accessor))
notifyPresenceOfIndexedAccessors(exec->vm());
- SparseArrayValueMap* map = m_butterfly->arrayStorage()->m_sparseMap.get();
+ SparseArrayValueMap* map = m_butterfly.get(this)->arrayStorage()->m_sparseMap.get();
RELEASE_ASSERT(map);
// 1. Let current be the result of calling the [[GetOwnProperty]] internal method of O with property name P.
@@ -1750,8 +1824,9 @@ bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, const P
entryInMap->get(defaults);
putIndexedDescriptor(exec, entryInMap, descriptor, defaults);
- if (index >= m_butterfly->arrayStorage()->length())
- m_butterfly->arrayStorage()->setLength(index + 1);
+ Butterfly* butterfly = m_butterfly.get(this);
+ if (index >= butterfly->arrayStorage()->length())
+ butterfly->arrayStorage()->setLength(index + 1);
return true;
}
@@ -1869,19 +1944,21 @@ bool JSObject::attemptToInterceptPutByIndexOnHole(ExecState* exec, unsigned i, J
template<IndexingType indexingShape>
void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, unsigned i, JSValue value)
{
- ASSERT((structure()->indexingType() & IndexingShapeMask) == indexingShape);
+ ASSERT((indexingType() & IndexingShapeMask) == indexingShape);
ASSERT(!indexingShouldBeSparse());
+
+ Butterfly* butterfly = m_butterfly.get(this);
// For us to get here, the index is either greater than the public length, or greater than
// or equal to the vector length.
- ASSERT(i >= m_butterfly->vectorLength());
+ ASSERT(i >= butterfly->vectorLength());
VM& vm = exec->vm();
- if (i >= MAX_ARRAY_INDEX - 1
+ if (i > MAX_STORAGE_VECTOR_INDEX
|| (i >= MIN_SPARSE_ARRAY_INDEX
- && !isDenseEnoughForVector(i, countElements<indexingShape>(butterfly())))
- || indexIsSufficientlyBeyondLengthForSparseMap(i, m_butterfly->vectorLength())) {
+ && !isDenseEnoughForVector(i, countElements<indexingShape>(butterfly)))
+ || indexIsSufficientlyBeyondLengthForSparseMap(i, butterfly->vectorLength())) {
ASSERT(i <= MAX_ARRAY_INDEX);
ensureArrayStorageSlow(vm);
SparseArrayValueMap* map = allocateSparseIndexMap(vm);
@@ -1892,24 +1969,25 @@ void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, un
}
ensureLength(vm, i + 1);
+ butterfly = m_butterfly.get(this);
- RELEASE_ASSERT(i < m_butterfly->vectorLength());
+ RELEASE_ASSERT(i < butterfly->vectorLength());
switch (indexingShape) {
case Int32Shape:
ASSERT(value.isInt32());
- m_butterfly->contiguousInt32()[i].setWithoutWriteBarrier(value);
+ butterfly->contiguousInt32()[i].setWithoutWriteBarrier(value);
break;
case DoubleShape: {
ASSERT(value.isNumber());
double valueAsDouble = value.asNumber();
ASSERT(valueAsDouble == valueAsDouble);
- m_butterfly->contiguousDouble()[i] = valueAsDouble;
+ butterfly->contiguousDouble()[i] = valueAsDouble;
break;
}
case ContiguousShape:
- m_butterfly->contiguous()[i].set(vm, this, value);
+ butterfly->contiguous()[i].set(vm, this, value);
break;
default:
@@ -1917,6 +1995,11 @@ void JSObject::putByIndexBeyondVectorLengthWithoutAttributes(ExecState* exec, un
}
}
+// Explicit instantiations needed by JSArray.cpp.
+template void JSObject::putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(ExecState*, unsigned, JSValue);
+template void JSObject::putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(ExecState*, unsigned, JSValue);
+template void JSObject::putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(ExecState*, unsigned, JSValue);
+
void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage)
{
VM& vm = exec->vm();
@@ -1998,7 +2081,7 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue
// i should be a valid array index that is outside of the current vector.
ASSERT(i <= MAX_ARRAY_INDEX);
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES: {
if (indexingShouldBeSparse()) {
putByIndexBeyondVectorLengthWithArrayStorage(
@@ -2011,10 +2094,10 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue
exec, i, value, shouldThrow, createArrayStorage(vm, 0, 0));
break;
}
- if (structure()->needsSlowPutIndexing()) {
- ArrayStorage* storage = createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, i + 1));
- storage->m_vector[i].set(vm, this, value);
- storage->m_numValuesInVector++;
+ if (structure(vm)->needsSlowPutIndexing()) {
+ // Convert the indexing type to the SlowPutArrayStorage and retry.
+ createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, i + 1));
+ putByIndex(this, exec, i, value, shouldThrow);
break;
}
@@ -2066,7 +2149,7 @@ bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec,
VM& vm = exec->vm();
// i should be a valid array index that is outside of the current vector.
- ASSERT(hasArrayStorage(structure()->indexingType()));
+ ASSERT(hasAnyArrayStorage(indexingType()));
ASSERT(arrayStorage() == storage);
ASSERT(i >= storage->vectorLength() || attributes);
ASSERT(i <= MAX_ARRAY_INDEX);
@@ -2148,7 +2231,7 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV
if (attributes & (ReadOnly | Accessor))
notifyPresenceOfIndexedAccessors(vm);
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES: {
if (indexingShouldBeSparse() || attributes) {
return putDirectIndexBeyondVectorLengthWithArrayStorage(
@@ -2159,7 +2242,7 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV
return putDirectIndexBeyondVectorLengthWithArrayStorage(
exec, i, value, attributes, mode, createArrayStorage(vm, 0, 0));
}
- if (structure()->needsSlowPutIndexing()) {
+ if (structure(vm)->needsSlowPutIndexing()) {
ArrayStorage* storage = createArrayStorage(vm, i + 1, getNewVectorLength(0, 0, i + 1));
storage->m_vector[i].set(vm, this, value);
storage->m_numValuesInVector++;
@@ -2177,9 +2260,10 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV
}
case ALL_INT32_INDEXING_TYPES: {
- if (attributes & (ReadOnly | Accessor)) {
- return putDirectIndexBeyondVectorLengthWithArrayStorage(
- exec, i, value, attributes, mode, convertInt32ToArrayStorage(vm));
+ if (attributes) {
+ if (i < m_butterfly.get(this)->vectorLength())
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, convertInt32ToArrayStorage(vm));
}
if (!value.isInt32()) {
convertInt32ForValue(vm, value);
@@ -2190,9 +2274,10 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV
}
case ALL_DOUBLE_INDEXING_TYPES: {
- if (attributes & (ReadOnly | Accessor)) {
- return putDirectIndexBeyondVectorLengthWithArrayStorage(
- exec, i, value, attributes, mode, convertDoubleToArrayStorage(vm));
+ if (attributes) {
+ if (i < m_butterfly.get(this)->vectorLength())
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, convertDoubleToArrayStorage(vm));
}
if (!value.isNumber()) {
convertDoubleToContiguous(vm);
@@ -2208,15 +2293,20 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV
}
case ALL_CONTIGUOUS_INDEXING_TYPES: {
- if (attributes & (ReadOnly | Accessor)) {
- return putDirectIndexBeyondVectorLengthWithArrayStorage(
- exec, i, value, attributes, mode, convertContiguousToArrayStorage(vm));
+ if (attributes) {
+ if (i < m_butterfly.get(this)->vectorLength())
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, convertContiguousToArrayStorage(vm));
}
putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, i, value);
return true;
}
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ if (attributes) {
+ if (i < m_butterfly.get(this)->vectorLength())
+ return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(vm));
+ }
return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, arrayStorage());
default:
@@ -2225,6 +2315,14 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV
}
}
+void JSObject::putDirectNativeIntrinsicGetter(VM& vm, JSGlobalObject* globalObject, Identifier name, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
+{
+ GetterSetter* accessor = GetterSetter::create(vm, globalObject);
+ JSFunction* function = JSFunction::create(vm, globalObject, 0, name.string(), nativeFunction, intrinsic);
+ accessor->setGetter(vm, globalObject, function);
+ putDirectNonIndexAccessor(vm, name, accessor, attributes);
+}
+
void JSObject::putDirectNativeFunction(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
{
StringImpl* name = propertyName.publicName();
@@ -2236,11 +2334,30 @@ void JSObject::putDirectNativeFunction(VM& vm, JSGlobalObject* globalObject, con
putDirect(vm, propertyName, function, attributes);
}
-void JSObject::putDirectNativeFunctionWithoutTransition(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
+JSFunction* JSObject::putDirectBuiltinFunction(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, FunctionExecutable* functionExecutable, unsigned attributes)
{
StringImpl* name = propertyName.publicName();
+ if (!name)
+ name = vm.propertyNames->anonymous.impl();
ASSERT(name);
+ JSFunction* function = JSFunction::createBuiltinFunction(vm, static_cast<FunctionExecutable*>(functionExecutable), globalObject);
+ putDirect(vm, propertyName, function, attributes);
+ return function;
+}
+
+JSFunction* JSObject::putDirectBuiltinFunctionWithoutTransition(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, FunctionExecutable* functionExecutable, unsigned attributes)
+{
+ JSFunction* function = JSFunction::createBuiltinFunction(vm, static_cast<FunctionExecutable*>(functionExecutable), globalObject);
+ putDirectWithoutTransition(vm, propertyName, function, attributes);
+ return function;
+}
+void JSObject::putDirectNativeFunctionWithoutTransition(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
+{
+ StringImpl* name = propertyName.publicName();
+ if (!name)
+ name = vm.propertyNames->anonymous.impl();
+ ASSERT(name);
JSFunction* function = JSFunction::create(vm, globalObject, functionLength, name, nativeFunction, intrinsic);
putDirectWithoutTransition(vm, propertyName, function, attributes);
}
@@ -2272,9 +2389,9 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength)
unsigned vectorLength;
unsigned length;
- if (hasIndexedProperties(structure()->indexingType())) {
- vectorLength = m_butterfly->vectorLength();
- length = m_butterfly->publicLength();
+ if (hasIndexedProperties(indexingType())) {
+ vectorLength = m_butterfly.get(this)->vectorLength();
+ length = m_butterfly.get(this)->publicLength();
} else {
vectorLength = 0;
length = 0;
@@ -2311,7 +2428,7 @@ unsigned JSObject::countElements(Butterfly* butterfly)
unsigned JSObject::countElements()
{
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
return 0;
@@ -2350,10 +2467,11 @@ bool JSObject::increaseVectorLength(VM& vm, unsigned newLength)
unsigned newVectorLength = getNewVectorLength(newLength);
// Fast case - there is no precapacity. In these cases a realloc makes sense.
+ Structure* structure = this->structure(vm);
if (LIKELY(!indexBias)) {
DeferGC deferGC(vm.heap);
Butterfly* newButterfly = storage->butterfly()->growArrayRight(
- vm, this, structure(), structure()->outOfLineCapacity(), true,
+ vm, this, structure, structure->outOfLineCapacity(), true,
ArrayStorage::sizeFor(vectorLength), ArrayStorage::sizeFor(newVectorLength));
if (!newButterfly)
return false;
@@ -2367,7 +2485,7 @@ bool JSObject::increaseVectorLength(VM& vm, unsigned newLength)
unsigned newIndexBias = std::min(indexBias >> 1, MAX_STORAGE_VECTOR_LENGTH - newVectorLength);
Butterfly* newButterfly = storage->butterfly()->resizeArray(
vm, this,
- structure()->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength),
+ structure->outOfLineCapacity(), true, ArrayStorage::sizeFor(vectorLength),
newIndexBias, true, ArrayStorage::sizeFor(newVectorLength));
if (!newButterfly)
return false;
@@ -2379,49 +2497,108 @@ bool JSObject::increaseVectorLength(VM& vm, unsigned newLength)
void JSObject::ensureLengthSlow(VM& vm, unsigned length)
{
+ Butterfly* butterfly = m_butterfly.get(this);
+
ASSERT(length < MAX_ARRAY_INDEX);
- ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType()));
- ASSERT(length > m_butterfly->vectorLength());
+ ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType()));
+ ASSERT(length > butterfly->vectorLength());
unsigned newVectorLength = std::min(
length << 1,
MAX_STORAGE_VECTOR_LENGTH);
- unsigned oldVectorLength = m_butterfly->vectorLength();
+ unsigned oldVectorLength = butterfly->vectorLength();
DeferGC deferGC(vm.heap);
- m_butterfly.set(vm, this, m_butterfly->growArrayRight(
+ butterfly = butterfly->growArrayRight(
vm, this, structure(), structure()->outOfLineCapacity(), true,
oldVectorLength * sizeof(EncodedJSValue),
- newVectorLength * sizeof(EncodedJSValue)));
+ newVectorLength * sizeof(EncodedJSValue));
+ m_butterfly.set(vm, this, butterfly);
- m_butterfly->setVectorLength(newVectorLength);
+ butterfly->setVectorLength(newVectorLength);
- if (hasDouble(structure()->indexingType())) {
+ if (hasDouble(indexingType())) {
for (unsigned i = oldVectorLength; i < newVectorLength; ++i)
- m_butterfly->contiguousDouble().data()[i] = QNaN;
+ butterfly->contiguousDouble().data()[i] = PNaN;
}
}
+void JSObject::reallocateAndShrinkButterfly(VM& vm, unsigned length)
+{
+ ASSERT(length < MAX_ARRAY_INDEX);
+ ASSERT(length < MAX_STORAGE_VECTOR_LENGTH);
+ ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType()));
+ ASSERT(m_butterfly.get(this)->vectorLength() > length);
+ ASSERT(!m_butterfly.get(this)->indexingHeader()->preCapacity(structure()));
+
+ DeferGC deferGC(vm.heap);
+ Butterfly* newButterfly = m_butterfly.get(this)->resizeArray(vm, this, structure(), 0, ArrayStorage::sizeFor(length));
+ m_butterfly.set(vm, this, newButterfly);
+ newButterfly->setVectorLength(length);
+ newButterfly->setPublicLength(length);
+}
+
Butterfly* JSObject::growOutOfLineStorage(VM& vm, size_t oldSize, size_t newSize)
{
ASSERT(newSize > oldSize);
// It's important that this function not rely on structure(), for the property
// capacity, since we might have already mutated the structure in-place.
-
- return m_butterfly->growPropertyStorage(vm, this, structure(), oldSize, newSize);
+
+ return Butterfly::createOrGrowPropertyStorage(m_butterfly.get(this), vm, this, structure(vm), oldSize, newSize);
+}
+
+static JSBoundSlotBaseFunction* getBoundSlotBaseFunctionForGetterSetter(ExecState* exec, PropertyName propertyName, JSC::PropertySlot& slot, CustomGetterSetter* getterSetter, JSBoundSlotBaseFunction::Type type)
+{
+ auto key = std::make_pair(getterSetter, (int)type);
+ JSBoundSlotBaseFunction* boundSlotBase = exec->vm().customGetterSetterFunctionMap.get(key);
+ if (!boundSlotBase) {
+ boundSlotBase = JSBoundSlotBaseFunction::create(exec->vm(), exec->lexicalGlobalObject(), slot.slotBase(), getterSetter, type, propertyName.publicName());
+ exec->vm().customGetterSetterFunctionMap.set(key, boundSlotBase);
+ }
+ return boundSlotBase;
}
bool JSObject::getOwnPropertyDescriptor(ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
{
- JSC::PropertySlot slot(this);
- if (!methodTable()->getOwnPropertySlot(this, exec, propertyName, slot))
- return false;
- /* Workaround, JSDOMWindow::getOwnPropertySlot searches the prototype chain. :-( */
- if (slot.slotBase() != this && slot.slotBase() && slot.slotBase()->methodTable()->toThis(slot.slotBase(), exec, NotStrictMode) != this)
+ JSC::PropertySlot slot(this, PropertySlot::InternalMethodType::GetOwnProperty);
+ if (!methodTable(exec->vm())->getOwnPropertySlot(this, exec, propertyName, slot))
return false;
+
+ // DebuggerScope::getOwnPropertySlot() (and possibly others) may return attributes from the prototype chain
+ // but getOwnPropertyDescriptor() should only work for 'own' properties so we exit early if we detect that
+ // the property is not an own property.
+ if (slot.slotBase() != this && slot.slotBase()) {
+ JSProxy* jsProxy = jsDynamicCast<JSProxy*>(this);
+ if (!jsProxy || jsProxy->target() != slot.slotBase()) {
+ // Try ProxyObject.
+ ProxyObject* proxyObject = jsDynamicCast<ProxyObject*>(this);
+ if (!proxyObject || proxyObject->target() != slot.slotBase())
+ return false;
+ }
+ }
+
if (slot.isAccessor())
descriptor.setAccessorDescriptor(slot.getterSetter(), slot.attributes());
- else
+ else if (slot.attributes() & CustomAccessor) {
+ descriptor.setCustomDescriptor(slot.attributes());
+
+ JSObject* thisObject = this;
+ if (auto* proxy = jsDynamicCast<JSProxy*>(this))
+ thisObject = proxy->target();
+
+ JSValue maybeGetterSetter = thisObject->getDirect(exec->vm(), propertyName);
+ if (!maybeGetterSetter) {
+ thisObject->reifyAllStaticProperties(exec);
+ maybeGetterSetter = thisObject->getDirect(exec->vm(), propertyName);
+ }
+
+ ASSERT(maybeGetterSetter);
+ auto* getterSetter = jsCast<CustomGetterSetter*>(maybeGetterSetter);
+ if (getterSetter->getter())
+ descriptor.setGetter(getBoundSlotBaseFunctionForGetterSetter(exec, propertyName, slot, getterSetter, JSBoundSlotBaseFunction::Type::Getter));
+ if (getterSetter->setter())
+ descriptor.setSetter(getBoundSlotBaseFunctionForGetterSetter(exec, propertyName, slot, getterSetter, JSBoundSlotBaseFunction::Type::Setter));
+ } else
descriptor.setDescriptor(slot.getValue(exec, propertyName), slot.attributes());
return true;
}
@@ -2431,11 +2608,11 @@ static bool putDescriptor(ExecState* exec, JSObject* target, PropertyName proper
VM& vm = exec->vm();
if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) {
if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) {
- GetterSetter* accessor = GetterSetter::create(vm);
+ GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject());
if (oldDescriptor.getterPresent())
- accessor->setGetter(vm, oldDescriptor.getterObject());
+ accessor->setGetter(vm, exec->lexicalGlobalObject(), oldDescriptor.getterObject());
if (oldDescriptor.setterPresent())
- accessor->setSetter(vm, oldDescriptor.setterObject());
+ accessor->setSetter(vm, exec->lexicalGlobalObject(), oldDescriptor.setterObject());
target->putDirectAccessor(exec, propertyName, accessor, attributes | Accessor);
return true;
}
@@ -2446,20 +2623,20 @@ static bool putDescriptor(ExecState* exec, JSObject* target, PropertyName proper
newValue = oldDescriptor.value();
target->putDirect(vm, propertyName, newValue, attributes & ~Accessor);
if (attributes & ReadOnly)
- target->structure()->setContainsReadOnlyProperties();
+ target->structure(vm)->setContainsReadOnlyProperties();
return true;
}
attributes &= ~ReadOnly;
- GetterSetter* accessor = GetterSetter::create(vm);
+ GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject());
if (descriptor.getterPresent())
- accessor->setGetter(vm, descriptor.getterObject());
+ accessor->setGetter(vm, exec->lexicalGlobalObject(), descriptor.getterObject());
else if (oldDescriptor.getterPresent())
- accessor->setGetter(vm, oldDescriptor.getterObject());
+ accessor->setGetter(vm, exec->lexicalGlobalObject(), oldDescriptor.getterObject());
if (descriptor.setterPresent())
- accessor->setSetter(vm, descriptor.setterObject());
+ accessor->setSetter(vm, exec->lexicalGlobalObject(), descriptor.setterObject());
else if (oldDescriptor.setterPresent())
- accessor->setSetter(vm, oldDescriptor.setterObject());
+ accessor->setSetter(vm, exec->lexicalGlobalObject(), oldDescriptor.setterObject());
target->putDirectAccessor(exec, propertyName, accessor, attributes | Accessor);
return true;
@@ -2467,11 +2644,10 @@ static bool putDescriptor(ExecState* exec, JSObject* target, PropertyName proper
void JSObject::putDirectMayBeIndex(ExecState* exec, PropertyName propertyName, JSValue value)
{
- unsigned asIndex = propertyName.asIndex();
- if (asIndex == PropertyName::NotAnIndex)
- putDirect(exec->vm(), propertyName, value);
+ if (Optional<uint32_t> index = parseIndex(propertyName))
+ putDirectIndex(exec, index.value(), value);
else
- putDirectIndex(exec, asIndex, value);
+ putDirect(exec->vm(), propertyName, value);
}
class DefineOwnPropertyScope {
@@ -2491,39 +2667,43 @@ private:
VM& m_vm;
};
-bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
+
+// 9.1.6.3 of the spec
+// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-validateandapplypropertydescriptor
+bool validateAndApplyPropertyDescriptor(ExecState* exec, JSObject* object, PropertyName propertyName, bool isExtensible,
+ const PropertyDescriptor& descriptor, bool isCurrentDefined, const PropertyDescriptor& current, bool throwException)
{
- // Track on the globaldata that we're in define property.
- // Currently DefineOwnProperty uses delete to remove properties when they are being replaced
- // (particularly when changing attributes), however delete won't allow non-configurable (i.e.
- // DontDelete) properties to be deleted. For now, we can use this flag to make this work.
- DefineOwnPropertyScope scope(exec);
-
// If we have a new property we can just put it on normally
- PropertyDescriptor current;
- if (!getOwnPropertyDescriptor(exec, propertyName, current)) {
+ // Step 2.
+ if (!isCurrentDefined) {
// unless extensions are prevented!
- if (!isExtensible()) {
+ // Step 2.a
+ if (!isExtensible) {
if (throwException)
exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to define property on object that is not extensible.")));
return false;
}
+ if (!object)
+ return true;
+ // Step 2.c/d
PropertyDescriptor oldDescriptor;
oldDescriptor.setValue(jsUndefined());
- return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributes(), oldDescriptor);
+ // FIXME: spec says to always return true here.
+ return putDescriptor(exec, object, propertyName, descriptor, descriptor.attributes(), oldDescriptor);
}
-
+ // Step 3.
if (descriptor.isEmpty())
return true;
-
+ // Step 4.
if (current.equalTo(exec, descriptor))
return true;
+ // Step 5.
// Filter out invalid changes
if (!current.configurable()) {
if (descriptor.configurable()) {
if (throwException)
- exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to configurable attribute of unconfigurable property.")));
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change configurable attribute of unconfigurable property.")));
return false;
}
if (descriptor.enumerablePresent() && descriptor.enumerable() != current.enumerable()) {
@@ -2532,16 +2712,18 @@ bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyN
return false;
}
}
-
+
+ // Step 6.
// A generic descriptor is simply changing the attributes of an existing property
if (descriptor.isGenericDescriptor()) {
- if (!current.attributesEqual(descriptor)) {
- methodTable()->deleteProperty(this, exec, propertyName);
- return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
+ if (!current.attributesEqual(descriptor) && object) {
+ object->methodTable(exec->vm())->deleteProperty(object, exec, propertyName);
+ return putDescriptor(exec, object, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
}
return true;
}
-
+
+ // Step 7.
// Changing between a normal property or an accessor property
if (descriptor.isDataDescriptor() != current.isDataDescriptor()) {
if (!current.configurable()) {
@@ -2549,10 +2731,15 @@ bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyN
exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property.")));
return false;
}
- methodTable()->deleteProperty(this, exec, propertyName);
- return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
+
+ if (!object)
+ return true;
+
+ object->methodTable(exec->vm())->deleteProperty(object, exec, propertyName);
+ return putDescriptor(exec, object, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
}
+ // Step 8.
// Changing the value and attributes of an existing property
if (descriptor.isDataDescriptor()) {
if (!current.configurable()) {
@@ -2571,10 +2758,13 @@ bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyN
}
if (current.attributesEqual(descriptor) && !descriptor.value())
return true;
- methodTable()->deleteProperty(this, exec, propertyName);
- return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
+ if (!object)
+ return true;
+ object->methodTable(exec->vm())->deleteProperty(object, exec, propertyName);
+ return putDescriptor(exec, object, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
}
+ // Step 9.
// Changing the accessor functions of an existing accessor property
ASSERT(descriptor.isAccessorDescriptor());
if (!current.configurable()) {
@@ -2588,51 +2778,197 @@ bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyN
exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change the getter of an unconfigurable property.")));
return false;
}
+ if (current.attributes() & CustomAccessor) {
+ if (throwException)
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property.")));
+ return false;
+ }
}
- JSValue accessor = getDirect(exec->vm(), propertyName);
+
+ // Step 10/11.
+ if (!object)
+ return true;
+ JSValue accessor = object->getDirect(exec->vm(), propertyName);
if (!accessor)
return false;
- GetterSetter* getterSetter = asGetterSetter(accessor);
- if (descriptor.setterPresent())
- getterSetter->setSetter(exec->vm(), descriptor.setterObject());
- if (descriptor.getterPresent())
- getterSetter->setGetter(exec->vm(), descriptor.getterObject());
- if (current.attributesEqual(descriptor))
+ GetterSetter* getterSetter;
+ bool getterSetterChanged = false;
+ if (accessor.isCustomGetterSetter())
+ getterSetter = GetterSetter::create(exec->vm(), exec->lexicalGlobalObject());
+ else {
+ ASSERT(accessor.isGetterSetter());
+ getterSetter = asGetterSetter(accessor);
+ }
+ if (descriptor.setterPresent()) {
+ getterSetter = getterSetter->withSetter(exec->vm(), exec->lexicalGlobalObject(), descriptor.setterObject());
+ getterSetterChanged = true;
+ }
+ if (descriptor.getterPresent()) {
+ getterSetter = getterSetter->withGetter(exec->vm(), exec->lexicalGlobalObject(), descriptor.getterObject());
+ getterSetterChanged = true;
+ }
+ if (current.attributesEqual(descriptor) && !getterSetterChanged)
return true;
- methodTable()->deleteProperty(this, exec, propertyName);
+ object->methodTable(exec->vm())->deleteProperty(object, exec, propertyName);
unsigned attrs = descriptor.attributesOverridingCurrent(current);
- putDirectAccessor(exec, propertyName, getterSetter, attrs | Accessor);
+ object->putDirectAccessor(exec, propertyName, getterSetter, attrs | Accessor);
return true;
}
+bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
+{
+ // Track on the globaldata that we're in define property.
+ // Currently DefineOwnProperty uses delete to remove properties when they are being replaced
+ // (particularly when changing attributes), however delete won't allow non-configurable (i.e.
+ // DontDelete) properties to be deleted. For now, we can use this flag to make this work.
+ DefineOwnPropertyScope scope(exec);
+ PropertyDescriptor current;
+ bool isCurrentDefined = getOwnPropertyDescriptor(exec, propertyName, current);
+ return validateAndApplyPropertyDescriptor(exec, this, propertyName, isExtensible(), descriptor, isCurrentDefined, current, throwException);
+}
+
bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
{
// If it's an array index, then use the indexed property storage.
- unsigned index = propertyName.asIndex();
- if (index != PropertyName::NotAnIndex) {
+ if (Optional<uint32_t> index = parseIndex(propertyName)) {
// c. Let succeeded be the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing P, Desc, and false as arguments.
// d. Reject if succeeded is false.
// e. If index >= oldLen
// e.i. Set oldLenDesc.[[Value]] to index + 1.
// e.ii. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", oldLenDesc, and false as arguments. This call will always return true.
// f. Return true.
- return object->defineOwnIndexedProperty(exec, index, descriptor, throwException);
+ return object->defineOwnIndexedProperty(exec, index.value(), descriptor, throwException);
}
return object->defineOwnNonIndexProperty(exec, propertyName, descriptor, throwException);
}
-bool JSObject::getOwnPropertySlotSlow(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+JSObject* throwTypeError(ExecState* exec, const String& message)
{
- unsigned i = propertyName.asIndex();
- if (i != PropertyName::NotAnIndex)
- return getOwnPropertySlotByIndex(this, exec, i, slot);
- return false;
+ return exec->vm().throwException(exec, createTypeError(exec, message));
}
-JSObject* throwTypeError(ExecState* exec, const String& message)
+void JSObject::convertToDictionary(VM& vm)
{
- return exec->vm().throwException(exec, createTypeError(exec, message));
+ DeferredStructureTransitionWatchpointFire deferredWatchpointFire;
+ setStructure(
+ vm, Structure::toCacheableDictionaryTransition(vm, structure(vm), &deferredWatchpointFire));
+}
+
+void JSObject::shiftButterflyAfterFlattening(VM& vm, size_t outOfLineCapacityBefore, size_t outOfLineCapacityAfter)
+{
+ Butterfly* butterfly = this->butterfly();
+ size_t preCapacity = this->butterflyPreCapacity();
+ void* currentBase = butterfly->base(preCapacity, outOfLineCapacityAfter);
+ void* newBase = butterfly->base(preCapacity, outOfLineCapacityBefore);
+
+ memmove(newBase, currentBase, this->butterflyTotalSize());
+ setButterflyWithoutChangingStructure(vm, Butterfly::fromBase(newBase, preCapacity, outOfLineCapacityAfter));
+}
+
+uint32_t JSObject::getEnumerableLength(ExecState* exec, JSObject* object)
+{
+ VM& vm = exec->vm();
+ Structure* structure = object->structure(vm);
+ if (structure->holesMustForwardToPrototype(vm))
+ return 0;
+ switch (object->indexingType()) {
+ case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ return 0;
+
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_CONTIGUOUS_INDEXING_TYPES: {
+ Butterfly* butterfly = object->butterfly();
+ unsigned usedLength = butterfly->publicLength();
+ for (unsigned i = 0; i < usedLength; ++i) {
+ if (!butterfly->contiguous()[i])
+ return 0;
+ }
+ return usedLength;
+ }
+
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ Butterfly* butterfly = object->butterfly();
+ unsigned usedLength = butterfly->publicLength();
+ for (unsigned i = 0; i < usedLength; ++i) {
+ double value = butterfly->contiguousDouble()[i];
+ if (value != value)
+ return 0;
+ }
+ return usedLength;
+ }
+
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
+ ArrayStorage* storage = object->m_butterfly.get(object)->arrayStorage();
+ if (storage->m_sparseMap.get())
+ return 0;
+
+ unsigned usedVectorLength = std::min(storage->length(), storage->vectorLength());
+ for (unsigned i = 0; i < usedVectorLength; ++i) {
+ if (!storage->m_vector[i])
+ return 0;
+ }
+ return usedVectorLength;
+ }
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+void JSObject::getStructurePropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ VM& vm = exec->vm();
+ object->structure(vm)->getPropertyNamesFromStructure(vm, propertyNames, mode);
+}
+
+void JSObject::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ VM& vm = exec->vm();
+ object->methodTable(vm)->getOwnPropertyNames(object, exec, propertyNames, EnumerationMode(mode, JSObjectPropertiesMode::Exclude));
+
+ if (object->prototype().isNull())
+ return;
+
+ JSObject* prototype = asObject(object->prototype());
+ while (true) {
+ if (prototype->structure(vm)->typeInfo().overridesGetPropertyNames()) {
+ prototype->methodTable(vm)->getPropertyNames(prototype, exec, propertyNames, mode);
+ break;
+ }
+ prototype->methodTable(vm)->getOwnPropertyNames(prototype, exec, propertyNames, mode);
+ JSValue nextProto = prototype->prototype();
+ if (nextProto.isNull())
+ break;
+ prototype = asObject(nextProto);
+ }
+}
+
+// Implements GetMethod(O, P) in section 7.3.9 of the spec.
+// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-getmethod
+JSValue JSObject::getMethod(ExecState* exec, CallData& callData, CallType& callType, const Identifier& ident, const String& errorMessage)
+{
+ JSValue method = get(exec, ident);
+ if (exec->hadException())
+ return jsUndefined();
+
+ if (!method.isCell()) {
+ if (method.isUndefinedOrNull())
+ return jsUndefined();
+
+ throwVMTypeError(exec, errorMessage);
+ return jsUndefined();
+ }
+
+ callType = method.asCell()->methodTable()->getCallData(method.asCell(), callData);
+ if (callType == CallTypeNone) {
+ throwVMTypeError(exec, errorMessage);
+ return jsUndefined();
+ }
+
+ return method;
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index 02b137b35..f62952eb3 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.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, 2009, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2003-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 Library General Public
@@ -30,9 +30,11 @@
#include "CallFrame.h"
#include "ClassInfo.h"
#include "CommonIdentifiers.h"
-#include "CopyWriteBarrier.h"
+#include "CopyBarrier.h"
+#include "CustomGetterSetter.h"
#include "DeferGC.h"
#include "Heap.h"
+#include "HeapInlines.h"
#include "IndexingHeaderInlines.h"
#include "JSCell.h"
#include "PropertySlot.h"
@@ -50,29 +52,21 @@ namespace JSC {
inline JSCell* getJSFunction(JSValue value)
{
- if (value.isCell() && (value.asCell()->structure()->typeInfo().type() == JSFunctionType))
+ if (value.isCell() && (value.asCell()->type() == JSFunctionType))
return value.asCell();
return 0;
}
-JS_EXPORT_PRIVATE JSCell* getCallableObjectSlow(JSCell*);
-
-inline JSCell* getCallableObject(JSValue value)
-{
- if (!value.isCell())
- return 0;
- return getCallableObjectSlow(value.asCell());
-}
-
class GetterSetter;
-class HashEntry;
class InternalFunction;
+class JSFunction;
class LLIntOffsetsExtractor;
class MarkedBlock;
class PropertyDescriptor;
class PropertyNameArray;
class Structure;
struct HashTable;
+struct HashTableValue;
JS_EXPORT_PRIVATE JSObject* throwTypeError(ExecState*, const String&);
extern JS_EXPORTDATA const char* StrictModeReadonlyPropertyWriteError;
@@ -81,7 +75,6 @@ COMPILE_ASSERT(None < FirstInternalAttribute, None_is_below_FirstInternalAttribu
COMPILE_ASSERT(ReadOnly < FirstInternalAttribute, ReadOnly_is_below_FirstInternalAttribute);
COMPILE_ASSERT(DontEnum < FirstInternalAttribute, DontEnum_is_below_FirstInternalAttribute);
COMPILE_ASSERT(DontDelete < FirstInternalAttribute, DontDelete_is_below_FirstInternalAttribute);
-COMPILE_ASSERT(Function < FirstInternalAttribute, Function_is_below_FirstInternalAttribute);
COMPILE_ASSERT(Accessor < FirstInternalAttribute, Accessor_is_below_FirstInternalAttribute);
class JSFinalObject;
@@ -92,7 +85,7 @@ class JSObject : public JSCell {
friend class JSCell;
friend class JSFinalObject;
friend class MarkedBlock;
- JS_EXPORT_PRIVATE friend bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject*, PropertyName, PropertySlot&);
+ JS_EXPORT_PRIVATE friend bool setUpStaticFunctionSlot(ExecState*, const HashTableValue*, JSObject*, PropertyName, PropertySlot&);
enum PutMode {
PutModePut,
@@ -101,15 +94,17 @@ class JSObject : public JSCell {
public:
typedef JSCell Base;
-
+
+ JS_EXPORT_PRIVATE static size_t estimatedSize(JSCell*);
JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
JS_EXPORT_PRIVATE static String className(const JSObject*);
+ JS_EXPORT_PRIVATE static String calculatedClassName(JSObject*);
JSValue prototype() const;
- void setPrototype(VM&, JSValue prototype);
- bool setPrototypeWithCycleCheck(ExecState*, JSValue prototype);
+ JS_EXPORT_PRIVATE void setPrototype(VM&, JSValue prototype);
+ JS_EXPORT_PRIVATE bool setPrototypeWithCycleCheck(ExecState*, JSValue prototype);
bool mayInterceptIndexedAccesses()
{
@@ -119,7 +114,6 @@ public:
JSValue get(ExecState*, PropertyName) const;
JSValue get(ExecState*, unsigned propertyName) const;
- bool fastGetOwnPropertySlot(ExecState*, PropertyName, PropertySlot&);
bool getPropertySlot(ExecState*, PropertyName, PropertySlot&);
bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
@@ -129,34 +123,36 @@ public:
// The key difference between this and getOwnPropertySlot is that getOwnPropertySlot
// currently returns incorrect results for the DOM window (with non-own properties)
// being returned. Once this is fixed we should migrate code & remove this method.
- bool getOwnPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&);
+ JS_EXPORT_PRIVATE bool getOwnPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&);
- bool allowsAccessFrom(ExecState*);
+ JS_EXPORT_PRIVATE bool allowsAccessFrom(ExecState*);
unsigned getArrayLength() const
{
- if (!hasIndexedProperties(structure()->indexingType()))
+ if (!hasIndexedProperties(indexingType()))
return 0;
- return m_butterfly->publicLength();
+ return m_butterfly.get(this)->publicLength();
}
unsigned getVectorLength()
{
- if (!hasIndexedProperties(structure()->indexingType()))
+ if (!hasIndexedProperties(indexingType()))
return 0;
- return m_butterfly->vectorLength();
+ return m_butterfly.get(this)->vectorLength();
}
-
+
+ static void putInline(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+
JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
- void putByIndexInline(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
+ ALWAYS_INLINE void putByIndexInline(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
{
if (canSetIndexQuickly(propertyName)) {
setIndexQuickly(exec->vm(), propertyName, value);
return;
}
- methodTable()->putByIndex(this, exec, propertyName, value, shouldThrow);
+ methodTable(exec->vm())->putByIndex(this, exec, propertyName, value, shouldThrow);
}
// This is similar to the putDirect* methods:
@@ -187,23 +183,24 @@ public:
bool canGetIndexQuickly(unsigned i)
{
- switch (structure()->indexingType()) {
+ Butterfly* butterfly = m_butterfly.get(this);
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
return false;
case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
- return i < m_butterfly->vectorLength() && m_butterfly->contiguous()[i];
+ return i < butterfly->vectorLength() && butterfly->contiguous()[i];
case ALL_DOUBLE_INDEXING_TYPES: {
- if (i >= m_butterfly->vectorLength())
+ if (i >= butterfly->vectorLength())
return false;
- double value = m_butterfly->contiguousDouble()[i];
+ double value = butterfly->contiguousDouble()[i];
if (value != value)
return false;
return true;
}
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i];
+ return i < butterfly->arrayStorage()->vectorLength() && butterfly->arrayStorage()->m_vector[i];
default:
RELEASE_ASSERT_NOT_REACHED();
return false;
@@ -212,49 +209,51 @@ public:
JSValue getIndexQuickly(unsigned i)
{
- switch (structure()->indexingType()) {
+ Butterfly* butterfly = m_butterfly.get(this);
+ switch (indexingType()) {
case ALL_INT32_INDEXING_TYPES:
- return jsNumber(m_butterfly->contiguous()[i].get().asInt32());
+ return jsNumber(butterfly->contiguous()[i].get().asInt32());
case ALL_CONTIGUOUS_INDEXING_TYPES:
- return m_butterfly->contiguous()[i].get();
+ return butterfly->contiguous()[i].get();
case ALL_DOUBLE_INDEXING_TYPES:
- return JSValue(JSValue::EncodeAsDouble, m_butterfly->contiguousDouble()[i]);
+ return JSValue(JSValue::EncodeAsDouble, butterfly->contiguousDouble()[i]);
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->arrayStorage()->m_vector[i].get();
+ return butterfly->arrayStorage()->m_vector[i].get();
default:
RELEASE_ASSERT_NOT_REACHED();
return JSValue();
}
}
- JSValue tryGetIndexQuickly(unsigned i)
+ JSValue tryGetIndexQuickly(unsigned i) const
{
- switch (structure()->indexingType()) {
+ Butterfly* butterfly = m_butterfly.get(this);
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
break;
case ALL_INT32_INDEXING_TYPES:
- if (i < m_butterfly->publicLength()) {
- JSValue result = m_butterfly->contiguous()[i].get();
+ if (i < butterfly->publicLength()) {
+ JSValue result = butterfly->contiguous()[i].get();
ASSERT(result.isInt32() || !result);
return result;
}
break;
case ALL_CONTIGUOUS_INDEXING_TYPES:
- if (i < m_butterfly->publicLength())
- return m_butterfly->contiguous()[i].get();
+ if (i < butterfly->publicLength())
+ return butterfly->contiguous()[i].get();
break;
case ALL_DOUBLE_INDEXING_TYPES: {
- if (i >= m_butterfly->publicLength())
+ if (i >= butterfly->publicLength())
break;
- double result = m_butterfly->contiguousDouble()[i];
+ double result = butterfly->contiguousDouble()[i];
if (result != result)
break;
return JSValue(JSValue::EncodeAsDouble, result);
}
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- if (i < m_butterfly->arrayStorage()->vectorLength())
- return m_butterfly->arrayStorage()->m_vector[i].get();
+ if (i < butterfly->arrayStorage()->vectorLength())
+ return butterfly->arrayStorage()->m_vector[i].get();
break;
default:
RELEASE_ASSERT_NOT_REACHED();
@@ -267,13 +266,13 @@ public:
{
if (JSValue result = tryGetIndexQuickly(i))
return result;
- PropertySlot slot(this);
- if (methodTable()->getOwnPropertySlotByIndex(this, exec, i, slot))
+ PropertySlot slot(this, PropertySlot::InternalMethodType::Get);
+ if (methodTable(exec->vm())->getOwnPropertySlotByIndex(this, exec, i, slot))
return slot.getValue(exec, i);
return JSValue();
}
- JSValue getIndex(ExecState* exec, unsigned i)
+ JSValue getIndex(ExecState* exec, unsigned i) const
{
if (JSValue result = tryGetIndexQuickly(i))
return result;
@@ -282,7 +281,8 @@ public:
bool canSetIndexQuickly(unsigned i)
{
- switch (structure()->indexingType()) {
+ Butterfly* butterfly = m_butterfly.get(this);
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
return false;
@@ -291,11 +291,11 @@ public:
case ALL_CONTIGUOUS_INDEXING_TYPES:
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage:
- return i < m_butterfly->vectorLength();
+ return i < butterfly->vectorLength();
case NonArrayWithSlowPutArrayStorage:
case ArrayWithSlowPutArrayStorage:
- return i < m_butterfly->arrayStorage()->vectorLength()
- && !!m_butterfly->arrayStorage()->m_vector[i];
+ return i < butterfly->arrayStorage()->vectorLength()
+ && !!butterfly->arrayStorage()->m_vector[i];
default:
RELEASE_ASSERT_NOT_REACHED();
return false;
@@ -304,7 +304,7 @@ public:
bool canSetIndexQuicklyForPutDirect(unsigned i)
{
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
return false;
@@ -312,7 +312,7 @@ public:
case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return i < m_butterfly->vectorLength();
+ return i < m_butterfly.get(this)->vectorLength();
default:
RELEASE_ASSERT_NOT_REACHED();
return false;
@@ -321,9 +321,10 @@ public:
void setIndexQuickly(VM& vm, unsigned i, JSValue v)
{
- switch (structure()->indexingType()) {
+ Butterfly* butterfly = m_butterfly.get(this);
+ switch (indexingType()) {
case ALL_INT32_INDEXING_TYPES: {
- ASSERT(i < m_butterfly->vectorLength());
+ ASSERT(i < butterfly->vectorLength());
if (!v.isInt32()) {
convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(vm, i, v);
return;
@@ -331,14 +332,14 @@ public:
FALLTHROUGH;
}
case ALL_CONTIGUOUS_INDEXING_TYPES: {
- ASSERT(i < m_butterfly->vectorLength());
- m_butterfly->contiguous()[i].set(vm, this, v);
- if (i >= m_butterfly->publicLength())
- m_butterfly->setPublicLength(i + 1);
+ ASSERT(i < butterfly->vectorLength());
+ butterfly->contiguous()[i].set(vm, this, v);
+ if (i >= butterfly->publicLength())
+ butterfly->setPublicLength(i + 1);
break;
}
case ALL_DOUBLE_INDEXING_TYPES: {
- ASSERT(i < m_butterfly->vectorLength());
+ ASSERT(i < butterfly->vectorLength());
if (!v.isNumber()) {
convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v);
return;
@@ -348,13 +349,13 @@ public:
convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v);
return;
}
- m_butterfly->contiguousDouble()[i] = value;
- if (i >= m_butterfly->publicLength())
- m_butterfly->setPublicLength(i + 1);
+ butterfly->contiguousDouble()[i] = value;
+ if (i >= butterfly->publicLength())
+ butterfly->setPublicLength(i + 1);
break;
}
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
- ArrayStorage* storage = m_butterfly->arrayStorage();
+ ArrayStorage* storage = butterfly->arrayStorage();
WriteBarrier<Unknown>& x = storage->m_vector[i];
JSValue old = x.get();
x.set(vm, this, v);
@@ -369,17 +370,23 @@ public:
RELEASE_ASSERT_NOT_REACHED();
}
}
-
+
void initializeIndex(VM& vm, unsigned i, JSValue v)
{
- switch (structure()->indexingType()) {
+ initializeIndex(vm, i, v, indexingType());
+ }
+
+ void initializeIndex(VM& vm, unsigned i, JSValue v, IndexingType indexingType)
+ {
+ Butterfly* butterfly = m_butterfly.get(this);
+ switch (indexingType) {
case ALL_UNDECIDED_INDEXING_TYPES: {
setIndexQuicklyToUndecided(vm, i, v);
break;
}
case ALL_INT32_INDEXING_TYPES: {
- ASSERT(i < m_butterfly->publicLength());
- ASSERT(i < m_butterfly->vectorLength());
+ ASSERT(i < butterfly->publicLength());
+ ASSERT(i < butterfly->vectorLength());
if (!v.isInt32()) {
convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(vm, i, v);
break;
@@ -387,14 +394,14 @@ public:
FALLTHROUGH;
}
case ALL_CONTIGUOUS_INDEXING_TYPES: {
- ASSERT(i < m_butterfly->publicLength());
- ASSERT(i < m_butterfly->vectorLength());
- m_butterfly->contiguous()[i].set(vm, this, v);
+ ASSERT(i < butterfly->publicLength());
+ ASSERT(i < butterfly->vectorLength());
+ butterfly->contiguous()[i].set(vm, this, v);
break;
}
case ALL_DOUBLE_INDEXING_TYPES: {
- ASSERT(i < m_butterfly->publicLength());
- ASSERT(i < m_butterfly->vectorLength());
+ ASSERT(i < butterfly->publicLength());
+ ASSERT(i < butterfly->vectorLength());
if (!v.isNumber()) {
convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v);
return;
@@ -404,11 +411,11 @@ public:
convertDoubleToContiguousWhilePerformingSetIndex(vm, i, v);
return;
}
- m_butterfly->contiguousDouble()[i] = value;
+ butterfly->contiguousDouble()[i] = value;
break;
}
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
- ArrayStorage* storage = m_butterfly->arrayStorage();
+ ArrayStorage* storage = butterfly->arrayStorage();
ASSERT(i < storage->length());
ASSERT(i < storage->m_numValuesInVector);
storage->m_vector[i].set(vm, this, v);
@@ -421,7 +428,7 @@ public:
bool hasSparseMap()
{
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
case ALL_INT32_INDEXING_TYPES:
@@ -429,7 +436,7 @@ public:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return false;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->arrayStorage()->m_sparseMap;
+ return !!m_butterfly.get(this)->arrayStorage()->m_sparseMap;
default:
RELEASE_ASSERT_NOT_REACHED();
return false;
@@ -438,7 +445,7 @@ public:
bool inSparseIndexingMode()
{
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
case ALL_UNDECIDED_INDEXING_TYPES:
case ALL_INT32_INDEXING_TYPES:
@@ -446,7 +453,7 @@ public:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return false;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->arrayStorage()->inSparseMode();
+ return m_butterfly.get(this)->arrayStorage()->inSparseMode();
default:
RELEASE_ASSERT_NOT_REACHED();
return false;
@@ -465,16 +472,22 @@ public:
void putDirectWithoutTransition(VM&, PropertyName, JSValue, unsigned attributes = 0);
void putDirectNonIndexAccessor(VM&, PropertyName, JSValue, unsigned attributes);
void putDirectAccessor(ExecState*, PropertyName, JSValue, unsigned attributes);
+ JS_EXPORT_PRIVATE void putDirectCustomAccessor(VM&, PropertyName, JSValue, unsigned attributes);
+
+ void putGetter(ExecState*, PropertyName, JSValue, unsigned attributes);
+ void putSetter(ExecState*, PropertyName, JSValue, unsigned attributes);
JS_EXPORT_PRIVATE bool hasProperty(ExecState*, PropertyName) const;
JS_EXPORT_PRIVATE bool hasProperty(ExecState*, unsigned propertyName) const;
bool hasOwnProperty(ExecState*, PropertyName) const;
+ bool hasOwnProperty(ExecState*, unsigned) const;
JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName);
JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
JS_EXPORT_PRIVATE static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
+ JS_EXPORT_PRIVATE bool hasInstance(ExecState*, JSValue value, JSValue hasInstanceValue);
bool hasInstance(ExecState*, JSValue);
static bool defaultHasInstance(ExecState*, JSValue, JSValue prototypeProperty);
@@ -482,6 +495,10 @@ public:
JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static uint32_t getEnumerableLength(ExecState*, JSObject*);
+ JS_EXPORT_PRIVATE static void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+
JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
JS_EXPORT_PRIVATE double toNumber(ExecState*) const;
@@ -489,36 +506,36 @@ public:
JS_EXPORT_PRIVATE static JSValue toThis(JSCell*, ExecState*, ECMAMode);
- bool getPropertySpecificValue(ExecState*, PropertyName, JSCell*& specificFunction) const;
-
// This get function only looks at the property map.
JSValue getDirect(VM& vm, PropertyName propertyName) const
{
- PropertyOffset offset = structure()->get(vm, propertyName);
- checkOffset(offset, structure()->inlineCapacity());
+ Structure* structure = this->structure(vm);
+ PropertyOffset offset = structure->get(vm, propertyName);
+ checkOffset(offset, structure->inlineCapacity());
return offset != invalidOffset ? getDirect(offset) : JSValue();
}
-
+
JSValue getDirect(VM& vm, PropertyName propertyName, unsigned& attributes) const
{
- JSCell* specific;
- PropertyOffset offset = structure()->get(vm, propertyName, attributes, specific);
- checkOffset(offset, structure()->inlineCapacity());
+ Structure* structure = this->structure(vm);
+ PropertyOffset offset = structure->get(vm, propertyName, attributes);
+ checkOffset(offset, structure->inlineCapacity());
return offset != invalidOffset ? getDirect(offset) : JSValue();
}
PropertyOffset getDirectOffset(VM& vm, PropertyName propertyName)
{
- PropertyOffset offset = structure()->get(vm, propertyName);
- checkOffset(offset, structure()->inlineCapacity());
+ Structure* structure = this->structure(vm);
+ PropertyOffset offset = structure->get(vm, propertyName);
+ checkOffset(offset, structure->inlineCapacity());
return offset;
}
PropertyOffset getDirectOffset(VM& vm, PropertyName propertyName, unsigned& attributes)
{
- JSCell* specific;
- PropertyOffset offset = structure()->get(vm, propertyName, attributes, specific);
- checkOffset(offset, structure()->inlineCapacity());
+ Structure* structure = this->structure(vm);
+ PropertyOffset offset = structure->get(vm, propertyName, attributes);
+ checkOffset(offset, structure->inlineCapacity());
return offset;
}
@@ -542,11 +559,11 @@ public:
return inlineStorageUnsafe();
}
- const Butterfly* butterfly() const { return m_butterfly.get(); }
- Butterfly* butterfly() { return m_butterfly.get(); }
+ const Butterfly* butterfly() const { return m_butterfly.get(this); }
+ Butterfly* butterfly() { return m_butterfly.get(this); }
- ConstPropertyStorage outOfLineStorage() const { return m_butterfly->propertyStorage(); }
- PropertyStorage outOfLineStorage() { return m_butterfly->propertyStorage(); }
+ ConstPropertyStorage outOfLineStorage() const { return m_butterfly.get(this)->propertyStorage(); }
+ PropertyStorage outOfLineStorage() { return m_butterfly.get(this)->propertyStorage(); }
const WriteBarrierBase<Unknown>* locationForOffset(PropertyOffset offset) const
{
@@ -564,15 +581,16 @@ public:
void transitionTo(VM&, Structure*);
- bool removeDirect(VM&, PropertyName); // Return true if anything is removed.
+ JS_EXPORT_PRIVATE bool removeDirect(VM&, PropertyName); // Return true if anything is removed.
bool hasCustomProperties() { return structure()->didTransition(); }
bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); }
+ bool hasCustomGetterSetterProperties() { return structure()->hasCustomGetterSetterProperties(); }
// putOwnDataProperty has 'put' like semantics, however this method:
// - assumes the object contains no own getter/setter properties.
// - provides no special handling for __proto__
// - does not walk the prototype chain (to check for accessors or non-writable properties).
- // This is used by JSActivation.
+ // This is used by JSLexicalEnvironment.
bool putOwnDataProperty(VM&, PropertyName, JSValue, PutPropertySlot&);
// Fast access to known property offsets.
@@ -580,23 +598,23 @@ public:
void putDirect(VM& vm, PropertyOffset offset, JSValue value) { locationForOffset(offset)->set(vm, this, value); }
void putDirectUndefined(PropertyOffset offset) { locationForOffset(offset)->setUndefined(); }
- void putDirectNativeFunction(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
- void putDirectNativeFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
+ JS_EXPORT_PRIVATE void putDirectNativeIntrinsicGetter(VM&, JSGlobalObject*, Identifier, NativeFunction, Intrinsic, unsigned attributes);
+ JS_EXPORT_PRIVATE void putDirectNativeFunction(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
+ JS_EXPORT_PRIVATE JSFunction* putDirectBuiltinFunction(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes);
+ JSFunction* putDirectBuiltinFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, FunctionExecutable*, unsigned attributes);
+ JS_EXPORT_PRIVATE void putDirectNativeFunctionWithoutTransition(VM&, JSGlobalObject*, const PropertyName&, unsigned functionLength, NativeFunction, Intrinsic, unsigned attributes);
JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
bool isGlobalObject() const;
- bool isVariableObject() const;
- bool isStaticScopeObject() const;
- bool isNameScopeObject() const;
- bool isActivationObject() const;
bool isErrorInstance() const;
+ bool isWithScope() const;
- void seal(VM&);
- void freeze(VM&);
+ JS_EXPORT_PRIVATE void seal(VM&);
+ JS_EXPORT_PRIVATE void freeze(VM&);
JS_EXPORT_PRIVATE void preventExtensions(VM&);
- bool isSealed(VM& vm) { return structure()->isSealed(vm); }
- bool isFrozen(VM& vm) { return structure()->isFrozen(vm); }
+ bool isSealed(VM& vm) { return structure(vm)->isSealed(vm); }
+ bool isFrozen(VM& vm) { return structure(vm)->isFrozen(vm); }
bool isExtensible() { return structure()->isExtensible(); }
bool indexingShouldBeSparse()
{
@@ -605,7 +623,7 @@ public:
}
bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
- void reifyStaticFunctionsForDelete(ExecState* exec);
+ void reifyAllStaticProperties(ExecState*);
JS_EXPORT_PRIVATE Butterfly* growOutOfLineStorage(VM&, size_t oldSize, size_t newSize);
void setButterflyWithoutChangingStructure(VM&, Butterfly*);
@@ -615,10 +633,13 @@ public:
void setStructureAndReallocateStorageIfNecessary(VM&, unsigned oldCapacity, Structure*);
void setStructureAndReallocateStorageIfNecessary(VM&, Structure*);
+ JS_EXPORT_PRIVATE void convertToDictionary(VM&);
+
void flattenDictionaryObject(VM& vm)
{
- structure()->flattenDictionaryStructure(vm, this);
+ structure(vm)->flattenDictionaryStructure(vm, this);
}
+ void shiftButterflyAfterFlattening(VM&, size_t outOfLineCapacityBefore, size_t outOfLineCapacityAfter);
JSGlobalObject* globalObject() const
{
@@ -644,8 +665,8 @@ public:
// contiguous, array storage).
ContiguousJSValues ensureInt32(VM& vm)
{
- if (LIKELY(hasInt32(structure()->indexingType())))
- return m_butterfly->contiguousInt32();
+ if (LIKELY(hasInt32(indexingType())))
+ return m_butterfly.get(this)->contiguousInt32();
return ensureInt32Slow(vm);
}
@@ -656,8 +677,8 @@ public:
// or array storage).
ContiguousDoubles ensureDouble(VM& vm)
{
- if (LIKELY(hasDouble(structure()->indexingType())))
- return m_butterfly->contiguousDouble();
+ if (LIKELY(hasDouble(indexingType())))
+ return m_butterfly.get(this)->contiguousDouble();
return ensureDoubleSlow(vm);
}
@@ -666,32 +687,21 @@ public:
// indexing should be sparse or because we're having a bad time.
ContiguousJSValues ensureContiguous(VM& vm)
{
- if (LIKELY(hasContiguous(structure()->indexingType())))
- return m_butterfly->contiguous();
+ if (LIKELY(hasContiguous(indexingType())))
+ return m_butterfly.get(this)->contiguous();
return ensureContiguousSlow(vm);
}
-
- // Same as ensureContiguous(), except that if the indexed storage is in
- // double mode, then it does a rage conversion to contiguous: it
- // attempts to convert each double to an int32.
- ContiguousJSValues rageEnsureContiguous(VM& vm)
- {
- if (LIKELY(hasContiguous(structure()->indexingType())))
- return m_butterfly->contiguous();
-
- return rageEnsureContiguousSlow(vm);
- }
-
+
// Ensure that the object is in a mode where it has array storage. Use
// this if you're about to perform actions that would have required the
// object to be converted to have array storage, if it didn't have it
// already.
ArrayStorage* ensureArrayStorage(VM& vm)
{
- if (LIKELY(hasArrayStorage(structure()->indexingType())))
- return m_butterfly->arrayStorage();
-
+ if (LIKELY(hasAnyArrayStorage(indexingType())))
+ return m_butterfly.get(this)->arrayStorage();
+
return ensureArrayStorageSlow(vm);
}
@@ -707,6 +717,8 @@ public:
return &m_butterfly;
}
+ JSValue getMethod(ExecState* exec, CallData& callData, CallType& callType, const Identifier& ident, const String& errorMessage);
+
DECLARE_EXPORT_INFO;
protected:
@@ -714,8 +726,6 @@ protected:
{
Base::finishCreation(vm);
ASSERT(inherits(info()));
- ASSERT(!structure()->outOfLineCapacity());
- ASSERT(structure()->isEmpty());
ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
ASSERT(structure()->isObject());
ASSERT(classInfo());
@@ -737,23 +747,26 @@ protected:
// storage. This will assert otherwise.
ArrayStorage* arrayStorage()
{
- ASSERT(hasArrayStorage(structure()->indexingType()));
- return m_butterfly->arrayStorage();
+ ASSERT(hasAnyArrayStorage(indexingType()));
+ return m_butterfly.get(this)->arrayStorage();
}
// Call this if you want to predicate some actions on whether or not the
// object is in a mode where it has array storage.
ArrayStorage* arrayStorageOrNull()
{
- switch (structure()->indexingType()) {
+ switch (indexingType()) {
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->arrayStorage();
+ return m_butterfly.get(this)->arrayStorage();
default:
return 0;
}
}
+ size_t butterflyTotalSize();
+ size_t butterflyPreCapacity();
+
Butterfly* createInitialUndecided(VM&, unsigned length);
ContiguousJSValues createInitialInt32(VM&, unsigned length);
ContiguousDoubles createInitialDouble(VM&, unsigned length);
@@ -769,23 +782,18 @@ protected:
ContiguousJSValues convertUndecidedToInt32(VM&);
ContiguousDoubles convertUndecidedToDouble(VM&);
ContiguousJSValues convertUndecidedToContiguous(VM&);
- ArrayStorage* convertUndecidedToArrayStorage(VM&, NonPropertyTransition, unsigned neededLength);
ArrayStorage* convertUndecidedToArrayStorage(VM&, NonPropertyTransition);
ArrayStorage* convertUndecidedToArrayStorage(VM&);
ContiguousDoubles convertInt32ToDouble(VM&);
ContiguousJSValues convertInt32ToContiguous(VM&);
- ArrayStorage* convertInt32ToArrayStorage(VM&, NonPropertyTransition, unsigned neededLength);
ArrayStorage* convertInt32ToArrayStorage(VM&, NonPropertyTransition);
ArrayStorage* convertInt32ToArrayStorage(VM&);
ContiguousJSValues convertDoubleToContiguous(VM&);
- ContiguousJSValues rageConvertDoubleToContiguous(VM&);
- ArrayStorage* convertDoubleToArrayStorage(VM&, NonPropertyTransition, unsigned neededLength);
ArrayStorage* convertDoubleToArrayStorage(VM&, NonPropertyTransition);
ArrayStorage* convertDoubleToArrayStorage(VM&);
- ArrayStorage* convertContiguousToArrayStorage(VM&, NonPropertyTransition, unsigned neededLength);
ArrayStorage* convertContiguousToArrayStorage(VM&, NonPropertyTransition);
ArrayStorage* convertContiguousToArrayStorage(VM&);
@@ -812,118 +820,25 @@ protected:
void ensureLength(VM& vm, unsigned length)
{
ASSERT(length < MAX_ARRAY_INDEX);
- ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType()));
-
- if (m_butterfly->vectorLength() < length)
+ ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType()));
+
+ if (m_butterfly.get(this)->vectorLength() < length)
ensureLengthSlow(vm, length);
- if (m_butterfly->publicLength() < length)
- m_butterfly->setPublicLength(length);
+ if (m_butterfly.get(this)->publicLength() < length)
+ m_butterfly.get(this)->setPublicLength(length);
}
+ // Call this if you want to shrink the butterfly backing store, and you're
+ // sure that the array is contiguous.
+ void reallocateAndShrinkButterfly(VM&, unsigned length);
+
template<IndexingType indexingShape>
unsigned countElements(Butterfly*);
// This is relevant to undecided, int32, double, and contiguous.
unsigned countElements();
- // This strange method returns a pointer to the start of the indexed data
- // as if it contained JSValues. But it won't always contain JSValues.
- // Make sure you cast this to the appropriate type before using.
- template<IndexingType indexingType>
- ContiguousJSValues indexingData()
- {
- switch (indexingType) {
- case ALL_INT32_INDEXING_TYPES:
- case ALL_DOUBLE_INDEXING_TYPES:
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- return m_butterfly->contiguous();
-
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->arrayStorage()->vector();
-
- default:
- CRASH();
- return ContiguousJSValues();
- }
- }
-
- ContiguousJSValues currentIndexingData()
- {
- switch (structure()->indexingType()) {
- case ALL_INT32_INDEXING_TYPES:
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- return m_butterfly->contiguous();
-
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->arrayStorage()->vector();
-
- default:
- CRASH();
- return ContiguousJSValues();
- }
- }
-
- JSValue getHolyIndexQuickly(unsigned i)
- {
- ASSERT(i < m_butterfly->vectorLength());
- switch (structure()->indexingType()) {
- case ALL_INT32_INDEXING_TYPES:
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- return m_butterfly->contiguous()[i].get();
- case ALL_DOUBLE_INDEXING_TYPES: {
- double value = m_butterfly->contiguousDouble()[i];
- if (value == value)
- return JSValue(JSValue::EncodeAsDouble, value);
- return JSValue();
- }
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->arrayStorage()->m_vector[i].get();
- default:
- CRASH();
- return JSValue();
- }
- }
-
- template<IndexingType indexingType>
- unsigned relevantLength()
- {
- switch (indexingType) {
- case ALL_INT32_INDEXING_TYPES:
- case ALL_DOUBLE_INDEXING_TYPES:
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- return m_butterfly->publicLength();
-
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return std::min(
- m_butterfly->arrayStorage()->length(),
- m_butterfly->arrayStorage()->vectorLength());
-
- default:
- CRASH();
- return 0;
- }
- }
-
- unsigned currentRelevantLength()
- {
- switch (structure()->indexingType()) {
- case ALL_INT32_INDEXING_TYPES:
- case ALL_DOUBLE_INDEXING_TYPES:
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- return m_butterfly->publicLength();
-
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return std::min(
- m_butterfly->arrayStorage()->length(),
- m_butterfly->arrayStorage()->vectorLength());
-
- default:
- CRASH();
- return 0;
- }
- }
-
private:
friend class LLIntOffsetsExtractor;
@@ -940,12 +855,16 @@ private:
ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM&, ArrayStorage*);
template<PutMode>
- bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*);
+ bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&);
- bool inlineGetOwnPropertySlot(ExecState*, PropertyName, PropertySlot&);
+ JS_EXPORT_PRIVATE NEVER_INLINE void putInlineSlow(ExecState*, PropertyName, JSValue, PutPropertySlot&);
+
+ bool getNonIndexPropertySlot(ExecState*, PropertyName, PropertySlot&);
+ bool getOwnNonIndexPropertySlot(VM&, Structure&, PropertyName, PropertySlot&);
JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, JSValue, unsigned, PropertyOffset);
+ void fillCustomGetterPropertySlot(PropertySlot&, JSValue, unsigned, Structure&);
- const HashEntry* findPropertyHashEntry(ExecState*, PropertyName) const;
+ JS_EXPORT_PRIVATE const HashTableValue* findPropertyHashEntry(PropertyName) const;
void putIndexedDescriptor(ExecState*, SparseArrayEntry*, const PropertyDescriptor&, PropertyDescriptor& old);
@@ -956,8 +875,6 @@ private:
unsigned getNewVectorLength(unsigned currentVectorLength, unsigned currentLength, unsigned desiredLength);
unsigned getNewVectorLength(unsigned desiredLength);
- JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&);
-
ArrayStorage* constructConvertedArrayStorageWithoutCopyingElements(VM&, unsigned neededLength);
JS_EXPORT_PRIVATE void setIndexQuicklyToUndecided(VM&, unsigned index, JSValue);
@@ -969,16 +886,14 @@ private:
ContiguousJSValues ensureInt32Slow(VM&);
ContiguousDoubles ensureDoubleSlow(VM&);
ContiguousJSValues ensureContiguousSlow(VM&);
- ContiguousJSValues rageEnsureContiguousSlow(VM&);
- ArrayStorage* ensureArrayStorageSlow(VM&);
-
- enum DoubleToContiguousMode { EncodeValueAsDouble, RageConvertDoubleToValue };
- template<DoubleToContiguousMode mode>
- ContiguousJSValues genericConvertDoubleToContiguous(VM&);
- ContiguousJSValues ensureContiguousSlow(VM&, DoubleToContiguousMode);
-
+ JS_EXPORT_PRIVATE ArrayStorage* ensureArrayStorageSlow(VM&);
+
protected:
- CopyWriteBarrier<Butterfly> m_butterfly;
+ CopyBarrier<Butterfly> m_butterfly;
+#if USE(JSVALUE32_64)
+private:
+ uint32_t m_padding;
+#endif
};
// JSNonFinalObject is a type of JSObject that has some internal storage,
@@ -1004,7 +919,7 @@ protected:
void finishCreation(VM& vm)
{
Base::finishCreation(vm);
- ASSERT(!this->structure()->totalStorageCapacity());
+ ASSERT(!this->structure()->hasInlineStorage());
ASSERT(classInfo());
}
};
@@ -1018,11 +933,15 @@ class JSFinalObject : public JSObject {
public:
typedef JSObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags;
static size_t allocationSize(size_t inlineCapacity)
{
return sizeof(JSObject) + inlineCapacity * sizeof(WriteBarrierBase<Unknown>);
}
+
+ static inline const TypeInfo typeInfo() { return TypeInfo(FinalObjectType, StructureFlags); }
+ static const IndexingType defaultIndexingType = NonArray;
static const unsigned defaultSize = 64;
static inline unsigned defaultInlineCapacity()
@@ -1036,11 +955,11 @@ public:
return (maxSize - allocationSize(0)) / sizeof(WriteBarrier<Unknown>);
}
- static JSFinalObject* create(ExecState*, Structure*);
+ static JSFinalObject* create(ExecState*, Structure*, Butterfly* = nullptr);
static JSFinalObject* create(VM&, Structure*);
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, unsigned inlineCapacity)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), info(), NonArray, inlineCapacity);
+ return Structure::create(vm, globalObject, prototype, typeInfo(), info(), defaultIndexingType, inlineCapacity);
}
JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
@@ -1060,15 +979,16 @@ protected:
private:
friend class LLIntOffsetsExtractor;
- explicit JSFinalObject(VM& vm, Structure* structure)
- : JSObject(vm, structure)
+ explicit JSFinalObject(VM& vm, Structure* structure, Butterfly* butterfly = nullptr)
+ : JSObject(vm, structure, butterfly)
{
}
-
- static const unsigned StructureFlags = JSObject::StructureFlags;
};
-inline JSFinalObject* JSFinalObject::create(ExecState* exec, Structure* structure)
+JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL objectPrivateFuncInstanceOf(ExecState*);
+
+inline JSFinalObject* JSFinalObject::create(
+ ExecState* exec, Structure* structure, Butterfly* butterfly)
{
JSFinalObject* finalObject = new (
NotNull,
@@ -1076,7 +996,7 @@ inline JSFinalObject* JSFinalObject::create(ExecState* exec, Structure* structur
*exec->heap(),
allocationSize(structure->inlineCapacity())
)
- ) JSFinalObject(exec->vm(), structure);
+ ) JSFinalObject(exec->vm(), structure, butterfly);
finalObject->finishCreation(exec->vm());
return finalObject;
}
@@ -1105,35 +1025,17 @@ inline size_t JSObject::offsetOfInlineStorage()
inline bool JSObject::isGlobalObject() const
{
- return structure()->typeInfo().type() == GlobalObjectType;
-}
-
-inline bool JSObject::isVariableObject() const
-{
- return structure()->typeInfo().type() >= VariableObjectType;
-}
-
-
-inline bool JSObject::isStaticScopeObject() const
-{
- JSType type = structure()->typeInfo().type();
- return type == NameScopeObjectType || type == ActivationObjectType;
+ return type() == GlobalObjectType;
}
-
-inline bool JSObject::isNameScopeObject() const
-{
- return structure()->typeInfo().type() == NameScopeObjectType;
-}
-
-inline bool JSObject::isActivationObject() const
+inline bool JSObject::isErrorInstance() const
{
- return structure()->typeInfo().type() == ActivationObjectType;
+ return type() == ErrorInstanceType;
}
-inline bool JSObject::isErrorInstance() const
+inline bool JSObject::isWithScope() const
{
- return structure()->typeInfo().type() == ErrorInstanceType;
+ return type() == WithScopeType;
}
inline void JSObject::setStructureAndButterfly(VM& vm, Structure* structure, Butterfly* butterfly)
@@ -1193,21 +1095,46 @@ inline JSValue JSObject::prototype() const
return structure()->storedPrototype();
}
-ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+// It is safe to call this method with a PropertyName that is actually an index,
+// but if so will always return false (doesn't search index storage).
+ALWAYS_INLINE bool JSObject::getOwnNonIndexPropertySlot(VM& vm, Structure& structure, PropertyName propertyName, PropertySlot& slot)
{
unsigned attributes;
- JSCell* specific;
- PropertyOffset offset = structure()->get(exec->vm(), propertyName, attributes, specific);
- if (LIKELY(isValidOffset(offset))) {
- JSValue value = getDirect(offset);
- if (structure()->hasGetterSetterProperties() && value.isGetterSetter())
+ PropertyOffset offset = structure.get(vm, propertyName, attributes);
+ if (!isValidOffset(offset))
+ return false;
+
+ // getPropertySlot relies on this method never returning index properties!
+ ASSERT(!parseIndex(propertyName));
+
+ JSValue value = getDirect(offset);
+ if (value.isCell()) {
+ ASSERT(value);
+ JSCell* cell = value.asCell();
+ JSType type = cell->type();
+ switch (type) {
+ case GetterSetterType:
fillGetterPropertySlot(slot, value, attributes, offset);
- else
- slot.setValue(this, attributes, value, offset);
- return true;
+ return true;
+ case CustomGetterSetterType:
+ fillCustomGetterPropertySlot(slot, value, attributes, structure);
+ return true;
+ default:
+ break;
+ }
}
+
+ slot.setValue(this, attributes, value, offset);
+ return true;
+}
- return getOwnPropertySlotSlow(exec, propertyName, slot);
+ALWAYS_INLINE void JSObject::fillCustomGetterPropertySlot(PropertySlot& slot, JSValue customGetterSetter, unsigned attributes, Structure& structure)
+{
+ if (structure.isDictionary()) {
+ slot.setCustom(this, attributes, jsCast<CustomGetterSetter*>(customGetterSetter)->getter());
+ return;
+ }
+ slot.setCacheableCustom(this, attributes, jsCast<CustomGetterSetter*>(customGetterSetter)->getter());
}
// It may seem crazy to inline a function this large, especially a virtual function,
@@ -1215,38 +1142,80 @@ ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, PropertyN
// base class call to this.
ALWAYS_INLINE bool JSObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
- return object->inlineGetOwnPropertySlot(exec, propertyName, slot);
-}
-
-ALWAYS_INLINE bool JSObject::fastGetOwnPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
-{
- if (!structure()->typeInfo().overridesGetOwnPropertySlot())
- return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot);
- return methodTable()->getOwnPropertySlot(this, exec, propertyName, slot);
+ VM& vm = exec->vm();
+ Structure& structure = *object->structure(vm);
+ if (object->getOwnNonIndexPropertySlot(vm, structure, propertyName, slot))
+ return true;
+ if (Optional<uint32_t> index = parseIndex(propertyName))
+ return getOwnPropertySlotByIndex(object, exec, index.value(), slot);
+ return false;
}
// It may seem crazy to inline a function this large but it makes a big difference
// since this is function very hot in variable lookup
ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
+ VM& vm = exec->vm();
+ auto& structureIDTable = vm.heap.structureIDTable();
JSObject* object = this;
while (true) {
- if (object->fastGetOwnPropertySlot(exec, propertyName, slot))
+ if (UNLIKELY(TypeInfo::overridesGetOwnPropertySlot(object->inlineTypeFlags()))) {
+ // If propertyName is an index then we may have missed it (as this loop is using
+ // getOwnNonIndexPropertySlot), so we cannot safely call the overridden getOwnPropertySlot
+ // (lest we return a property from a prototype that is shadowed). Check now for an index,
+ // if so we need to start afresh from this object.
+ if (Optional<uint32_t> index = parseIndex(propertyName))
+ return getPropertySlot(exec, index.value(), slot);
+ // Safe to continue searching from current position; call getNonIndexPropertySlot to avoid
+ // parsing the int again.
+ return object->getNonIndexPropertySlot(exec, propertyName, slot);
+ }
+ Structure& structure = *structureIDTable.get(object->structureID());
+ if (object->getOwnNonIndexPropertySlot(vm, structure, propertyName, slot))
return true;
- JSValue prototype = object->prototype();
+ JSValue prototype = structure.storedPrototype();
if (!prototype.isObject())
- return false;
+ break;
object = asObject(prototype);
}
+
+ if (Optional<uint32_t> index = parseIndex(propertyName))
+ return getPropertySlot(exec, index.value(), slot);
+ return false;
}
ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
{
+ VM& vm = exec->vm();
+ auto& structureIDTable = vm.heap.structureIDTable();
+ JSObject* object = this;
+ while (true) {
+ Structure& structure = *structureIDTable.get(object->structureID());
+ if (structure.classInfo()->methodTable.getOwnPropertySlotByIndex(object, exec, propertyName, slot))
+ return true;
+ JSValue prototype = structure.storedPrototype();
+ if (!prototype.isObject())
+ return false;
+ object = asObject(prototype);
+ }
+}
+
+ALWAYS_INLINE bool JSObject::getNonIndexPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ // This method only supports non-index PropertyNames.
+ ASSERT(!parseIndex(propertyName));
+
+ VM& vm = exec->vm();
+ auto& structureIDTable = vm.heap.structureIDTable();
JSObject* object = this;
while (true) {
- if (object->methodTable()->getOwnPropertySlotByIndex(object, exec, propertyName, slot))
+ Structure& structure = *structureIDTable.get(object->structureID());
+ if (LIKELY(!TypeInfo::overridesGetOwnPropertySlot(object->inlineTypeFlags()))) {
+ if (object->getOwnNonIndexPropertySlot(vm, structure, propertyName, slot))
+ return true;
+ } else if (structure.classInfo()->methodTable.getOwnPropertySlot(object, exec, propertyName, slot))
return true;
- JSValue prototype = object->prototype();
+ JSValue prototype = structure.storedPrototype();
if (!prototype.isObject())
return false;
object = asObject(prototype);
@@ -1255,7 +1224,7 @@ ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyN
inline JSValue JSObject::get(ExecState* exec, PropertyName propertyName) const
{
- PropertySlot slot(this);
+ PropertySlot slot(this, PropertySlot::InternalMethodType::Get);
if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
return slot.getValue(exec, propertyName);
@@ -1264,7 +1233,7 @@ inline JSValue JSObject::get(ExecState* exec, PropertyName propertyName) const
inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
{
- PropertySlot slot(this);
+ PropertySlot slot(this, PropertySlot::InternalMethodType::Get);
if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
return slot.getValue(exec, propertyName);
@@ -1272,34 +1241,31 @@ inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
}
template<JSObject::PutMode mode>
-inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot, JSCell* specificFunction)
+ALWAYS_INLINE bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot)
{
ASSERT(value);
ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
- ASSERT(propertyName.asIndex() == PropertyName::NotAnIndex);
+ ASSERT(!parseIndex(propertyName));
- if (structure()->isDictionary()) {
+ Structure* structure = this->structure(vm);
+ if (structure->isDictionary()) {
+ ASSERT(!structure->hasInferredTypes());
+
unsigned currentAttributes;
- JSCell* currentSpecificFunction;
- PropertyOffset offset = structure()->get(vm, propertyName, currentAttributes, currentSpecificFunction);
+ PropertyOffset offset = structure->get(vm, propertyName, currentAttributes);
if (offset != invalidOffset) {
- // If there is currently a specific function, and there now either isn't,
- // or the new value is different, then despecify.
- if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
- structure()->despecifyDictionaryFunction(vm, propertyName);
if ((mode == PutModePut) && currentAttributes & ReadOnly)
return false;
putDirect(vm, offset, value);
- // At this point, the objects structure only has a specific value set if previously there
- // had been one set, and if the new value being specified is the same (otherwise we would
- // have despecified, above). So, if currentSpecificFunction is not set, or if the new
- // value is different (or there is no new value), then the slot now has no value - and
- // as such it is cachable.
- // If there was previously a value, and the new value is the same, then we cannot cache.
- if (!currentSpecificFunction || (specificFunction != currentSpecificFunction))
- slot.setExistingProperty(this, offset);
+ structure->didReplaceProperty(offset);
+ slot.setExistingProperty(this, offset);
+
+ if ((attributes & Accessor) != (currentAttributes & Accessor) || (attributes & CustomAccessor) != (currentAttributes & CustomAccessor)) {
+ ASSERT(!(attributes & ReadOnly));
+ setStructure(vm, Structure::attributeChangeTransition(vm, structure, propertyName, attributes));
+ }
return true;
}
@@ -1308,91 +1274,87 @@ inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSVal
DeferGC deferGC(vm.heap);
Butterfly* newButterfly = butterfly();
- if (structure()->putWillGrowOutOfLineStorage())
- newButterfly = growOutOfLineStorage(vm, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
- offset = structure()->addPropertyWithoutTransition(vm, propertyName, attributes, specificFunction);
- setStructureAndButterfly(vm, structure(), newButterfly);
+ if (this->structure()->putWillGrowOutOfLineStorage())
+ newButterfly = growOutOfLineStorage(vm, this->structure()->outOfLineCapacity(), this->structure()->suggestedNewOutOfLineStorageCapacity());
+ offset = this->structure()->addPropertyWithoutTransition(vm, propertyName, attributes);
+ setStructureAndButterfly(vm, this->structure(), newButterfly);
validateOffset(offset);
- ASSERT(structure()->isValidOffset(offset));
+ ASSERT(this->structure()->isValidOffset(offset));
putDirect(vm, offset, value);
- // See comment on setNewProperty call below.
- if (!specificFunction)
- slot.setNewProperty(this, offset);
+ slot.setNewProperty(this, offset);
if (attributes & ReadOnly)
- structure()->setContainsReadOnlyProperties();
+ this->structure()->setContainsReadOnlyProperties();
return true;
}
PropertyOffset offset;
- size_t currentCapacity = structure()->outOfLineCapacity();
- if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) {
+ size_t currentCapacity = this->structure()->outOfLineCapacity();
+ Structure* newStructure = Structure::addPropertyTransitionToExistingStructure(
+ structure, propertyName, attributes, offset);
+ if (newStructure) {
+ newStructure->willStoreValueForExistingTransition(
+ vm, propertyName, value, slot.context() == PutPropertySlot::PutById);
+
DeferGC deferGC(vm.heap);
Butterfly* newButterfly = butterfly();
- if (currentCapacity != structure->outOfLineCapacity()) {
- ASSERT(structure != this->structure());
- newButterfly = growOutOfLineStorage(vm, currentCapacity, structure->outOfLineCapacity());
+ if (currentCapacity != newStructure->outOfLineCapacity()) {
+ ASSERT(newStructure != this->structure());
+ newButterfly = growOutOfLineStorage(vm, currentCapacity, newStructure->outOfLineCapacity());
}
validateOffset(offset);
- ASSERT(structure->isValidOffset(offset));
- setStructureAndButterfly(vm, structure, newButterfly);
+ ASSERT(newStructure->isValidOffset(offset));
+ setStructureAndButterfly(vm, newStructure, newButterfly);
putDirect(vm, offset, value);
- // This is a new property; transitions with specific values are not currently cachable,
- // so leave the slot in an uncachable state.
- if (!specificFunction)
- slot.setNewProperty(this, offset);
+ slot.setNewProperty(this, offset);
return true;
}
unsigned currentAttributes;
- JSCell* currentSpecificFunction;
- offset = structure()->get(vm, propertyName, currentAttributes, currentSpecificFunction);
+ bool hasInferredType;
+ offset = structure->get(vm, propertyName, currentAttributes, hasInferredType);
if (offset != invalidOffset) {
if ((mode == PutModePut) && currentAttributes & ReadOnly)
return false;
- // There are three possibilities here:
- // (1) There is an existing specific value set, and we're overwriting with *the same value*.
- // * Do nothing - no need to despecify, but that means we can't cache (a cached
- // put could write a different value). Leave the slot in an uncachable state.
- // (2) There is a specific value currently set, but we're writing a different value.
- // * First, we have to despecify. Having done so, this is now a regular slot
- // with no specific value, so go ahead & cache like normal.
- // (3) Normal case, there is no specific value set.
- // * Go ahead & cache like normal.
- if (currentSpecificFunction) {
- // case (1) Do the put, then return leaving the slot uncachable.
- if (specificFunction == currentSpecificFunction) {
- putDirect(vm, offset, value);
- return true;
- }
- // case (2) Despecify, fall through to (3).
- setStructure(vm, Structure::despecifyFunctionTransition(vm, structure(), propertyName));
+ structure->didReplaceProperty(offset);
+ if (UNLIKELY(hasInferredType)) {
+ structure->willStoreValueForReplace(
+ vm, propertyName, value, slot.context() == PutPropertySlot::PutById);
}
- // case (3) set the slot, do the put, return.
slot.setExistingProperty(this, offset);
putDirect(vm, offset, value);
+
+ if ((attributes & Accessor) != (currentAttributes & Accessor)) {
+ ASSERT(!(attributes & ReadOnly));
+ setStructure(vm, Structure::attributeChangeTransition(vm, structure, propertyName, attributes));
+ }
return true;
}
if ((mode == PutModePut) && !isExtensible())
return false;
- Structure* structure = Structure::addPropertyTransition(vm, this->structure(), propertyName, attributes, specificFunction, offset, slot.context());
+ // We want the structure transition watchpoint to fire after this object has switched
+ // structure. This allows adaptive watchpoints to observe if the new structure is the one
+ // we want.
+ DeferredStructureTransitionWatchpointFire deferredWatchpointFire;
+
+ newStructure = Structure::addPropertyTransition(
+ vm, structure, propertyName, attributes, offset, slot.context(), &deferredWatchpointFire);
+ newStructure->willStoreValueForNewTransition(
+ vm, propertyName, value, slot.context() == PutPropertySlot::PutById);
validateOffset(offset);
- ASSERT(structure->isValidOffset(offset));
- setStructureAndReallocateStorageIfNecessary(vm, structure);
+ ASSERT(newStructure->isValidOffset(offset));
+ setStructureAndReallocateStorageIfNecessary(vm, newStructure);
putDirect(vm, offset, value);
- // This is a new property; transitions with specific values are not currently cachable,
- // so leave the slot in an uncachable state.
- if (!specificFunction)
- slot.setNewProperty(this, offset);
+ slot.setNewProperty(this, offset);
if (attributes & ReadOnly)
- structure->setContainsReadOnlyProperties();
+ newStructure->setContainsReadOnlyProperties();
return true;
}
@@ -1414,7 +1376,7 @@ inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM& vm, unsign
inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM& vm, Structure* newStructure)
{
setStructureAndReallocateStorageIfNecessary(
- vm, structure()->outOfLineCapacity(), newStructure);
+ vm, structure(vm)->outOfLineCapacity(), newStructure);
}
inline bool JSObject::putOwnDataProperty(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
@@ -1422,32 +1384,39 @@ inline bool JSObject::putOwnDataProperty(VM& vm, PropertyName propertyName, JSVa
ASSERT(value);
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
ASSERT(!structure()->hasGetterSetterProperties());
+ ASSERT(!structure()->hasCustomGetterSetterProperties());
- return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value));
+ return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot);
}
inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
{
ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
+ ASSERT(!value.isCustomGetterSetter());
PutPropertySlot slot(this);
- putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot, getCallableObject(value));
+ putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
}
inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
{
ASSERT(!value.isGetterSetter());
- putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, 0, slot, getCallableObject(value));
+ ASSERT(!value.isCustomGetterSetter());
+ putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, 0, slot);
}
inline void JSObject::putDirectWithoutTransition(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
{
DeferGC deferGC(vm.heap);
ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
- Butterfly* newButterfly = m_butterfly.get();
+ ASSERT(!value.isCustomGetterSetter());
+ Butterfly* newButterfly = m_butterfly.get(this);
if (structure()->putWillGrowOutOfLineStorage())
newButterfly = growOutOfLineStorage(vm, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
- PropertyOffset offset = structure()->addPropertyWithoutTransition(vm, propertyName, attributes, getCallableObject(value));
- setStructureAndButterfly(vm, structure(), newButterfly);
+ Structure* structure = this->structure();
+ PropertyOffset offset = structure->addPropertyWithoutTransition(vm, propertyName, attributes);
+ bool shouldOptimize = false;
+ structure->willStoreValueForNewTransition(vm, propertyName, value, shouldOptimize);
+ setStructureAndButterfly(vm, structure, newButterfly);
putDirect(vm, offset, value);
}
@@ -1456,18 +1425,15 @@ inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType pre
return methodTable()->defaultValue(this, exec, preferredType);
}
-ALWAYS_INLINE JSObject* Register::function() const
+ALWAYS_INLINE JSObject* Register::object() const
{
- if (!jsValue())
- return 0;
return asObject(jsValue());
}
-ALWAYS_INLINE Register Register::withCallee(JSObject* callee)
+ALWAYS_INLINE Register& Register::operator=(JSObject* object)
{
- Register r;
- r = JSValue(callee);
- return r;
+ u.value = JSValue::encode(JSValue(object));
+ return *this;
}
inline size_t offsetInButterfly(PropertyOffset offset)
@@ -1475,26 +1441,30 @@ inline size_t offsetInButterfly(PropertyOffset offset)
return offsetInOutOfLineStorage(offset) + Butterfly::indexOfPropertyStorage();
}
-// Helpers for patching code where you want to emit a load or store and
-// the base is:
-// For inline offsets: a pointer to the out-of-line storage pointer.
-// For out-of-line offsets: the base of the out-of-line storage.
-inline size_t offsetRelativeToPatchedStorage(PropertyOffset offset)
+inline size_t JSObject::butterflyPreCapacity()
{
- if (isOutOfLineOffset(offset))
- return sizeof(EncodedJSValue) * offsetInButterfly(offset);
- return JSObject::offsetOfInlineStorage() - JSObject::butterflyOffset() + sizeof(EncodedJSValue) * offsetInInlineStorage(offset);
+ if (UNLIKELY(hasIndexingHeader()))
+ return butterfly()->indexingHeader()->preCapacity(structure());
+ return 0;
}
-// Returns the maximum offset (away from zero) a load instruction will encode.
-inline size_t maxOffsetRelativeToPatchedStorage(PropertyOffset offset)
+inline size_t JSObject::butterflyTotalSize()
{
- ptrdiff_t addressOffset = static_cast<ptrdiff_t>(offsetRelativeToPatchedStorage(offset));
-#if USE(JSVALUE32_64)
- if (addressOffset >= 0)
- return static_cast<size_t>(addressOffset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag);
-#endif
- return static_cast<size_t>(addressOffset);
+ Structure* structure = this->structure();
+ Butterfly* butterfly = this->butterfly();
+ size_t preCapacity;
+ size_t indexingPayloadSizeInBytes;
+ bool hasIndexingHeader = this->hasIndexingHeader();
+
+ if (UNLIKELY(hasIndexingHeader)) {
+ preCapacity = butterfly->indexingHeader()->preCapacity(structure);
+ indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure);
+ } else {
+ preCapacity = 0;
+ indexingPayloadSizeInBytes = 0;
+ }
+
+ return Butterfly::totalSize(preCapacity, structure->outOfLineCapacity(), hasIndexingHeader, indexingPayloadSizeInBytes);
}
inline int indexRelativeToBase(PropertyOffset offset)
@@ -1512,11 +1482,22 @@ inline int offsetRelativeToBase(PropertyOffset offset)
return JSObject::offsetOfInlineStorage() + offsetInInlineStorage(offset) * sizeof(EncodedJSValue);
}
+// Returns the maximum offset (away from zero) a load instruction will encode.
+inline size_t maxOffsetRelativeToBase(PropertyOffset offset)
+{
+ ptrdiff_t addressOffset = offsetRelativeToBase(offset);
+#if USE(JSVALUE32_64)
+ if (addressOffset >= 0)
+ return static_cast<size_t>(addressOffset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag);
+#endif
+ return static_cast<size_t>(addressOffset);
+}
+
COMPILE_ASSERT(!(sizeof(JSObject) % sizeof(WriteBarrierBase<Unknown>)), JSObject_inline_storage_has_correct_alignment);
ALWAYS_INLINE Identifier makeIdentifier(VM& vm, const char* name)
{
- return Identifier(&vm, name);
+ return Identifier::fromString(&vm, name);
}
ALWAYS_INLINE Identifier makeIdentifier(VM&, const Identifier& name)
@@ -1524,6 +1505,9 @@ ALWAYS_INLINE Identifier makeIdentifier(VM&, const Identifier& name)
return name;
}
+bool validateAndApplyPropertyDescriptor(ExecState*, JSObject*, PropertyName, bool isExtensible,
+ const PropertyDescriptor& descriptor, bool isCurrentDefined, const PropertyDescriptor& current, bool throwException);
+
// Helper for defining native functions, if you're not using a static hash table.
// Use this macro from within finishCreation() methods in prototypes. This assumes
// you've defined variables called exec, globalObject, and vm, and they
@@ -1533,32 +1517,38 @@ ALWAYS_INLINE Identifier makeIdentifier(VM&, const Identifier& name)
vm, globalObject, makeIdentifier(vm, (jsName)), (length), cppName, \
(intrinsic), (attributes))
+#define JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(jsName, cppName, attributes, length, intrinsic) \
+ putDirectNativeFunctionWithoutTransition(\
+ vm, globalObject, makeIdentifier(vm, (jsName)), (length), cppName, \
+ (intrinsic), (attributes))
+
// As above, but this assumes that the function you're defining doesn't have an
// intrinsic.
#define JSC_NATIVE_FUNCTION(jsName, cppName, attributes, length) \
JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, (attributes), (length), NoIntrinsic)
-ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, PropertyName propertyName) const
-{
- if (m_propertyType == TypeValue)
- return JSValue::decode(m_data.value);
- if (m_propertyType == TypeCustomIndex)
- return JSValue::decode(m_data.customIndex.getIndexValue(exec, JSValue::encode(slotBase()), JSValue::encode(m_thisValue), m_data.customIndex.index));
- if (m_propertyType == TypeGetter)
- return functionGetter(exec);
- return JSValue::decode(m_data.custom.getValue(exec, JSValue::encode(slotBase()), JSValue::encode(m_thisValue), propertyName));
-}
+#define JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(jsName, cppName, attributes, length) \
+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(jsName, cppName, (attributes), (length), NoIntrinsic)
+
+// Identical helpers but for builtins. Note that currently, we don't support builtins that are
+// also intrinsics, but we probably will do that eventually.
+#define JSC_BUILTIN_FUNCTION(jsName, generatorName, attributes) \
+ putDirectBuiltinFunction(\
+ vm, globalObject, makeIdentifier(vm, (jsName)), (generatorName)(vm), (attributes))
+
+#define JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(jsName, generatorName, attributes) \
+ putDirectBuiltinFunctionWithoutTransition(\
+ vm, globalObject, makeIdentifier(vm, (jsName)), (generatorName)(vm), (attributes))
+
+// Helper for defining native getters on properties.
+#define JSC_NATIVE_INTRINSIC_GETTER(jsName, cppName, attributes, intrinsic) \
+ putDirectNativeIntrinsicGetter(\
+ vm, globalObject, makeIdentifier(vm, (jsName)), (cppName), \
+ (intrinsic), ((attributes) | Accessor))
+
+#define JSC_NATIVE_GETTER(jsName, cppName, attributes) \
+ JSC_NATIVE_INTRINSIC_GETTER((jsName), (cppName), (attributes), NoIntrinsic)
-ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, unsigned propertyName) const
-{
- if (m_propertyType == TypeValue)
- return JSValue::decode(m_data.value);
- if (m_propertyType == TypeCustomIndex)
- return JSValue::decode(m_data.customIndex.getIndexValue(exec, JSValue::encode(slotBase()), JSValue::encode(m_thisValue), m_data.customIndex.index));
- if (m_propertyType == TypeGetter)
- return functionGetter(exec);
- return JSValue::decode(m_data.custom.getValue(exec, JSValue::encode(slotBase()), JSValue::encode(m_thisValue), Identifier::from(exec, propertyName)));
-}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSObjectInlines.h b/Source/JavaScriptCore/runtime/JSObjectInlines.h
new file mode 100644
index 000000000..0469f60b7
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSObjectInlines.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003-2006, 2008, 2009, 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel (eric@webkit.org)
+ *
+ * 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 JSObjectInlines_h
+#define JSObjectInlines_h
+
+#include "Error.h"
+#include "JSObject.h"
+#include "Lookup.h"
+
+namespace JSC {
+
+// ECMA 8.6.2.2
+ALWAYS_INLINE void JSObject::putInline(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
+ JSObject* thisObject = jsCast<JSObject*>(cell);
+ ASSERT(value);
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
+ VM& vm = exec->vm();
+
+ // Try indexed put first. This is required for correctness, since loads on property names that appear like
+ // valid indices will never look in the named property storage.
+ if (Optional<uint32_t> index = parseIndex(propertyName)) {
+ putByIndex(thisObject, exec, index.value(), value, slot.isStrictMode());
+ return;
+ }
+
+ // Check if there are any setters or getters in the prototype chain
+ JSValue prototype;
+ if (propertyName != exec->propertyNames().underscoreProto) {
+ for (JSObject* obj = thisObject; !obj->structure(vm)->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
+ prototype = obj->prototype();
+ if (prototype.isNull()) {
+ ASSERT(!thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName));
+ if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot)
+ && slot.isStrictMode())
+ throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
+ return;
+ }
+ }
+ }
+
+ thisObject->putInlineSlow(exec, propertyName, value, slot);
+}
+
+} // namespace JSC
+
+#endif // JSObjectInlines_h
+
diff --git a/Source/JavaScriptCore/runtime/JSPromise.cpp b/Source/JavaScriptCore/runtime/JSPromise.cpp
index 9f182c954..22f40f029 100644
--- a/Source/JavaScriptCore/runtime/JSPromise.cpp
+++ b/Source/JavaScriptCore/runtime/JSPromise.cpp
@@ -26,27 +26,22 @@
#include "config.h"
#include "JSPromise.h"
-#if ENABLE(PROMISES)
-
#include "Error.h"
#include "JSCJSValueInlines.h"
#include "JSCellInlines.h"
#include "JSPromiseConstructor.h"
-#include "JSPromiseReaction.h"
#include "Microtask.h"
#include "SlotVisitorInlines.h"
#include "StructureInlines.h"
namespace JSC {
-static void triggerPromiseReactions(VM&, JSGlobalObject*, Vector<WriteBarrier<JSPromiseReaction>>&, JSValue);
-
-const ClassInfo JSPromise::s_info = { "Promise", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSPromise) };
+const ClassInfo JSPromise::s_info = { "Promise", &Base::s_info, 0, CREATE_METHOD_TABLE(JSPromise) };
-JSPromise* JSPromise::create(VM& vm, JSGlobalObject* globalObject, JSPromiseConstructor* constructor)
+JSPromise* JSPromise::create(VM& vm, Structure* structure)
{
- JSPromise* promise = new (NotNull, allocateCell<JSPromise>(vm.heap)) JSPromise(vm, globalObject->promiseStructure());
- promise->finishCreation(vm, constructor);
+ JSPromise* promise = new (NotNull, allocateCell<JSPromise>(vm.heap)) JSPromise(vm, structure);
+ promise->finishCreation(vm);
return promise;
}
@@ -56,116 +51,41 @@ Structure* JSPromise::createStructure(VM& vm, JSGlobalObject* globalObject, JSVa
}
JSPromise::JSPromise(VM& vm, Structure* structure)
- : JSDestructibleObject(vm, structure)
- , m_status(Status::Unresolved)
+ : Base(vm, structure)
{
}
-void JSPromise::finishCreation(VM& vm, JSPromiseConstructor* constructor)
+void JSPromise::finishCreation(VM& vm)
{
Base::finishCreation(vm);
- ASSERT(inherits(info()));
-
- m_constructor.set(vm, this, constructor);
-}
-
-void JSPromise::destroy(JSCell* cell)
-{
- static_cast<JSPromise*>(cell)->JSPromise::~JSPromise();
-}
-
-void JSPromise::visitChildren(JSCell* cell, SlotVisitor& visitor)
-{
- JSPromise* thisObject = jsCast<JSPromise*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
- Base::visitChildren(thisObject, visitor);
-
- visitor.append(&thisObject->m_result);
- visitor.append(&thisObject->m_constructor);
- visitor.append(thisObject->m_resolveReactions.begin(), thisObject->m_resolveReactions.end());
- visitor.append(thisObject->m_rejectReactions.begin(), thisObject->m_rejectReactions.end());
-}
-
-void JSPromise::reject(VM& vm, JSValue reason)
-{
- // 1. If the value of promise's internal slot [[PromiseStatus]] is not "unresolved", return.
- if (m_status != Status::Unresolved)
- return;
-
- DeferGC deferGC(vm.heap);
-
- // 2. Let 'reactions' be the value of promise's [[RejectReactions]] internal slot.
- Vector<WriteBarrier<JSPromiseReaction>> reactions;
- reactions.swap(m_rejectReactions);
-
- // 3. Set the value of promise's [[Result]] internal slot to reason.
- m_result.set(vm, this, reason);
-
- // 4. Set the value of promise's [[ResolveReactions]] internal slot to undefined.
- m_resolveReactions.clear();
-
- // 5. Set the value of promise's [[RejectReactions]] internal slot to undefined.
- // NOTE: Handled by the swap above.
-
- // 6. Set the value of promise's [[PromiseStatus]] internal slot to "has-rejection".
- m_status = Status::HasRejection;
-
- // 7. Return the result of calling TriggerPromiseReactions(reactions, reason).
- triggerPromiseReactions(vm, globalObject(), reactions, reason);
+ putDirect(vm, vm.propertyNames->promiseStatePrivateName, jsNumber(static_cast<unsigned>(Status::Pending)));
+ putDirect(vm, vm.propertyNames->promiseFulfillReactionsPrivateName, jsUndefined());
+ putDirect(vm, vm.propertyNames->promiseRejectReactionsPrivateName, jsUndefined());
+ putDirect(vm, vm.propertyNames->promiseResultPrivateName, jsUndefined());
}
-void JSPromise::resolve(VM& vm, JSValue resolution)
+void JSPromise::initialize(ExecState* exec, JSGlobalObject* globalObject, JSValue executor)
{
- // 1. If the value of promise's internal slot [[PromiseStatus]] is not "unresolved", return.
- if (m_status != Status::Unresolved)
- return;
-
- DeferGC deferGC(vm.heap);
-
- // 2. Let 'reactions' be the value of promise's [[ResolveReactions]] internal slot.
- Vector<WriteBarrier<JSPromiseReaction>> reactions;
- reactions.swap(m_resolveReactions);
-
- // 3. Set the value of promise's [[Result]] internal slot to resolution.
- m_result.set(vm, this, resolution);
-
- // 4. Set the value of promise's [[ResolveReactions]] internal slot to undefined.
- // NOTE: Handled by the swap above.
-
- // 5. Set the value of promise's [[RejectReactions]] internal slot to undefined.
- m_rejectReactions.clear();
-
- // 6. Set the value of promise's [[PromiseStatus]] internal slot to "has-resolution".
- m_status = Status::HasResolution;
-
- // 7. Return the result of calling TriggerPromiseReactions(reactions, resolution).
- triggerPromiseReactions(vm, globalObject(), reactions, resolution);
+ JSFunction* initializePromise = globalObject->initializePromiseFunction();
+ CallData callData;
+ CallType callType = JSC::getCallData(initializePromise, callData);
+ ASSERT(callType != CallTypeNone);
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(executor);
+ call(exec, initializePromise, callType, callData, this, arguments);
}
-void JSPromise::appendResolveReaction(VM& vm, JSPromiseReaction* reaction)
+auto JSPromise::status(VM& vm) const -> Status
{
- m_resolveReactions.append(WriteBarrier<JSPromiseReaction>(vm, this, reaction));
+ JSValue value = getDirect(vm, vm.propertyNames->promiseStatePrivateName);
+ ASSERT(value.isUInt32());
+ return static_cast<Status>(value.asUInt32());
}
-void JSPromise::appendRejectReaction(VM& vm, JSPromiseReaction* reaction)
+JSValue JSPromise::result(VM& vm) const
{
- m_rejectReactions.append(WriteBarrier<JSPromiseReaction>(vm, this, reaction));
-}
-
-void triggerPromiseReactions(VM& vm, JSGlobalObject* globalObject, Vector<WriteBarrier<JSPromiseReaction>>& reactions, JSValue argument)
-{
- // 1. Repeat for each reaction in reactions, in original insertion order
- for (auto& reaction : reactions) {
- // i. Call QueueMicrotask(ExecutePromiseReaction, (reaction, argument)).
- globalObject->queueMicrotask(createExecutePromiseReactionMicrotask(vm, reaction.get(), argument));
- }
-
- // 2. Return.
+ return getDirect(vm, vm.propertyNames->promiseResultPrivateName);
}
} // namespace JSC
-
-#endif // ENABLE(PROMISES)
diff --git a/Source/JavaScriptCore/runtime/JSPromise.h b/Source/JavaScriptCore/runtime/JSPromise.h
index d1d1854d9..662b1cdf6 100644
--- a/Source/JavaScriptCore/runtime/JSPromise.h
+++ b/Source/JavaScriptCore/runtime/JSPromise.h
@@ -26,68 +26,37 @@
#ifndef JSPromise_h
#define JSPromise_h
-#if ENABLE(PROMISES)
-
-#include "JSDestructibleObject.h"
+#include "JSObject.h"
namespace JSC {
-class JSPromiseReaction;
-class JSPromiseConstructor;
-
-class JSPromise : public JSDestructibleObject {
+class JSPromise : public JSNonFinalObject {
public:
- typedef JSDestructibleObject Base;
+ typedef JSNonFinalObject Base;
- static JSPromise* create(VM&, JSGlobalObject*, JSPromiseConstructor*);
+ static JSPromise* create(VM&, Structure*);
static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
- DECLARE_INFO;
+ DECLARE_EXPORT_INFO;
- enum class Status {
- Unresolved,
- HasResolution,
- HasRejection
+ enum class Status : unsigned {
+ Pending = 1,
+ Fulfilled,
+ Rejected
};
- Status status() const
- {
- return m_status;
- }
-
- JSValue result() const
- {
- ASSERT(m_status != Status::Unresolved);
- return m_result.get();
- }
-
- JSPromiseConstructor* constructor() const
- {
- return m_constructor.get();
- }
+ Status status(VM&) const;
+ JSValue result(VM&) const;
- void reject(VM&, JSValue);
- void resolve(VM&, JSValue);
+ // Initialize the promise with the executor.
+ // This may raise a JS exception.
+ void initialize(ExecState*, JSGlobalObject*, JSValue executor);
- void appendResolveReaction(VM&, JSPromiseReaction*);
- void appendRejectReaction(VM&, JSPromiseReaction*);
-
-private:
+protected:
JSPromise(VM&, Structure*);
- void finishCreation(VM&, JSPromiseConstructor*);
- static const unsigned StructureFlags = OverridesVisitChildren | JSObject::StructureFlags;
- static void destroy(JSCell*);
- static void visitChildren(JSCell*, SlotVisitor&);
-
- Status m_status;
- WriteBarrier<Unknown> m_result;
- WriteBarrier<JSPromiseConstructor> m_constructor;
- Vector<WriteBarrier<JSPromiseReaction>> m_resolveReactions;
- Vector<WriteBarrier<JSPromiseReaction>> m_rejectReactions;
+ void finishCreation(VM&);
};
} // namespace JSC
-#endif // ENABLE(PROMISES)
-
#endif // JSPromise_h
diff --git a/Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp b/Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp
index 402619633..354c7de8b 100644
--- a/Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/JSPromiseConstructor.cpp
@@ -26,14 +26,16 @@
#include "config.h"
#include "JSPromiseConstructor.h"
-#if ENABLE(PROMISES)
-
+#include "BuiltinNames.h"
#include "Error.h"
+#include "Exception.h"
+#include "GetterSetter.h"
+#include "IteratorOperations.h"
+#include "JSCBuiltins.h"
#include "JSCJSValueInlines.h"
#include "JSCellInlines.h"
+#include "JSFunction.h"
#include "JSPromise.h"
-#include "JSPromiseDeferred.h"
-#include "JSPromiseFunctions.h"
#include "JSPromisePrototype.h"
#include "Lookup.h"
#include "NumberObject.h"
@@ -43,33 +45,28 @@ namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSPromiseConstructor);
-static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncCast(ExecState*);
-static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncResolve(ExecState*);
-static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncReject(ExecState*);
-static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState*);
-static EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncAll(ExecState*);
}
#include "JSPromiseConstructor.lut.h"
namespace JSC {
-const ClassInfo JSPromiseConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::promiseConstructorTable, CREATE_METHOD_TABLE(JSPromiseConstructor) };
+const ClassInfo JSPromiseConstructor::s_info = { "Function", &Base::s_info, &promiseConstructorTable, CREATE_METHOD_TABLE(JSPromiseConstructor) };
/* Source for JSPromiseConstructor.lut.h
@begin promiseConstructorTable
- cast JSPromiseConstructorFuncCast DontEnum|Function 1
- resolve JSPromiseConstructorFuncResolve DontEnum|Function 1
- reject JSPromiseConstructorFuncReject DontEnum|Function 1
- race JSPromiseConstructorFuncRace DontEnum|Function 1
- all JSPromiseConstructorFuncAll DontEnum|Function 1
+ resolve JSBuiltin DontEnum|Function 1
+ reject JSBuiltin DontEnum|Function 1
+ race JSBuiltin DontEnum|Function 1
+ all JSBuiltin DontEnum|Function 1
@end
*/
-JSPromiseConstructor* JSPromiseConstructor::create(VM& vm, Structure* structure, JSPromisePrototype* promisePrototype)
+JSPromiseConstructor* JSPromiseConstructor::create(VM& vm, Structure* structure, JSPromisePrototype* promisePrototype, GetterSetter* speciesSymbol)
{
JSPromiseConstructor* constructor = new (NotNull, allocateCell<JSPromiseConstructor>(vm.heap)) JSPromiseConstructor(vm, structure);
- constructor->finishCreation(vm, promisePrototype);
+ constructor->finishCreation(vm, promisePrototype, speciesSymbol);
+ constructor->addOwnInternalSlots(vm, structure->globalObject());
return constructor;
}
@@ -79,74 +76,45 @@ Structure* JSPromiseConstructor::createStructure(VM& vm, JSGlobalObject* globalO
}
JSPromiseConstructor::JSPromiseConstructor(VM& vm, Structure* structure)
- : InternalFunction(vm, structure)
+ : Base(vm, structure)
{
}
-void JSPromiseConstructor::finishCreation(VM& vm, JSPromisePrototype* promisePrototype)
+void JSPromiseConstructor::finishCreation(VM& vm, JSPromisePrototype* promisePrototype, GetterSetter* speciesSymbol)
{
- Base::finishCreation(vm, "Promise");
+ Base::finishCreation(vm, ASCIILiteral("Promise"));
putDirectWithoutTransition(vm, vm.propertyNames->prototype, promisePrototype, DontEnum | DontDelete | ReadOnly);
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
+ putDirectNonIndexAccessor(vm, vm.propertyNames->speciesSymbol, speciesSymbol, Accessor | ReadOnly | DontEnum);
}
-static EncodedJSValue JSC_HOST_CALL constructPromise(ExecState* exec)
+void JSPromiseConstructor::addOwnInternalSlots(VM& vm, JSGlobalObject* globalObject)
{
- // NOTE: We ignore steps 1-4 as they only matter if you support subclassing, which we do not yet.
- // 1. Let promise be the this value.
- // 2. If Type(promise) is not Object, then throw a TypeError exception.
- // 3. If promise does not have a [[PromiseStatus]] internal slot, then throw a TypeError exception.
- // 4. If promise's [[PromiseStatus]] internal slot is not undefined, then throw a TypeError exception.
-
- JSValue resolver = exec->argument(0);
-
- // 5. IsCallable(resolver) is false, then throw a TypeError exception
- CallData callData;
- CallType callType = getCallData(resolver, callData);
- if (callType == CallTypeNone)
- return JSValue::encode(throwTypeError(exec, ASCIILiteral("Promise constructor takes a function argument")));
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().resolvePrivateName(), promiseConstructorResolveCodeGenerator, DontEnum | DontDelete | ReadOnly);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().rejectPrivateName(), promiseConstructorRejectCodeGenerator, DontEnum | DontDelete | ReadOnly);
+}
- VM& vm = exec->vm();
+static EncodedJSValue JSC_HOST_CALL constructPromise(ExecState* exec)
+{
JSGlobalObject* globalObject = exec->callee()->globalObject();
+ VM& vm = exec->vm();
- JSPromise* promise = JSPromise::create(vm, globalObject, jsCast<JSPromiseConstructor*>(exec->callee()));
-
- // NOTE: Steps 6-8 are handled by JSPromise::create().
- // 6. Set promise's [[PromiseStatus]] internal slot to "unresolved".
- // 7. Set promise's [[ResolveReactions]] internal slot to a new empty List.
- // 8. Set promise's [[RejectReactions]] internal slot to a new empty List.
-
- // 9. Let 'resolve' be a new built-in function object as defined in Resolve Promise Functions.
- JSFunction* resolve = createResolvePromiseFunction(vm, globalObject);
-
- // 10. Set the [[Promise]] internal slot of 'resolve' to 'promise'.
- resolve->putDirect(vm, vm.propertyNames->promisePrivateName, promise);
-
- // 11. Let 'reject' be a new built-in function object as defined in Reject Promise Functions
- JSFunction* reject = createRejectPromiseFunction(vm, globalObject);
-
- // 12. Set the [[Promise]] internal slot of 'reject' to 'promise'.
- reject->putDirect(vm, vm.propertyNames->promisePrivateName, promise);
-
- // 13. Let 'result' be the result of calling the [[Call]] internal method of resolver with
- // undefined as thisArgument and a List containing resolve and reject as argumentsList.
- MarkedArgumentBuffer arguments;
- arguments.append(resolve);
- arguments.append(reject);
- call(exec, resolver, callType, callData, jsUndefined(), arguments);
-
- // 14. If result is an abrupt completion, call PromiseReject(promise, result.[[value]]).
- if (exec->hadException()) {
- JSValue exception = exec->exception();
- exec->clearException();
+ JSValue newTarget = exec->newTarget();
+ if (newTarget.isUndefined())
+ return throwVMTypeError(exec);
- promise->reject(vm, exception);
- }
+ Structure* promiseStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), globalObject->promiseStructure());
+ JSPromise* promise = JSPromise::create(vm, promiseStructure);
+ promise->initialize(exec, globalObject, exec->argument(0));
- // 15. Return promise.
return JSValue::encode(promise);
}
+static EncodedJSValue JSC_HOST_CALL callPromise(ExecState* exec)
+{
+ return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(exec, "Promise"));
+}
+
ConstructType JSPromiseConstructor::getConstructData(JSCell*, ConstructData& constructData)
{
constructData.native.function = constructPromise;
@@ -155,402 +123,17 @@ ConstructType JSPromiseConstructor::getConstructData(JSCell*, ConstructData& con
CallType JSPromiseConstructor::getCallData(JSCell*, CallData& callData)
{
- callData.native.function = constructPromise;
+ // FIXME: This is workaround. Since JSC does not expose @isConstructor to JS builtins,
+ // we use typeof function === "function" now. And since typeof constructorWithoutCallability
+ // returns "object", we need to define [[Call]] for now.
+ // https://bugs.webkit.org/show_bug.cgi?id=144093
+ callData.native.function = callPromise;
return CallTypeHost;
}
bool JSPromiseConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
- return getStaticFunctionSlot<InternalFunction>(exec, ExecState::promiseConstructorTable(exec->vm()), jsCast<JSPromiseConstructor*>(object), propertyName, slot);
-}
-
-EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncCast(ExecState* exec)
-{
- // -- Promise.cast(x) --
- JSValue x = exec->argument(0);
-
- // 1. Let 'C' be the this value.
- JSValue C = exec->thisValue();
-
- // 2. If IsPromise(x) is true,
- JSPromise* promise = jsDynamicCast<JSPromise*>(x);
- if (promise) {
- // i. Let 'constructor' be the value of x's [[PromiseConstructor]] internal slot.
- JSValue constructor = promise->constructor();
- // ii. If SameValue(constructor, C) is true, return x.
- if (sameValue(exec, constructor, C))
- return JSValue::encode(x);
- }
-
- // 3. Let 'deferred' be the result of calling GetDeferred(C).
- JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);
-
- // 4. ReturnIfAbrupt(deferred).
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);
-
- // 5. Let 'resolveResult' be the result of calling the [[Call]] internal method
- // of deferred.[[Resolve]] with undefined as thisArgument and a List containing x
- // as argumentsList.
- performDeferredResolve(exec, deferred, x);
-
- // 6. ReturnIfAbrupt(resolveResult).
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- // 7. Return deferred.[[Promise]].
- return JSValue::encode(deferred->promise());
-}
-
-EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncResolve(ExecState* exec)
-{
- // -- Promise.resolve(x) --
- JSValue x = exec->argument(0);
-
- // 1. Let 'C' be the this value.
- JSValue C = exec->thisValue();
-
- // 2. Let 'deferred' be the result of calling GetDeferred(C).
- JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);
-
- // 3. ReturnIfAbrupt(deferred).
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);
-
- // 4. Let 'resolveResult' be the result of calling the [[Call]] internal method
- // of deferred.[[Resolve]] with undefined as thisArgument and a List containing x
- // as argumentsList.
- performDeferredResolve(exec, deferred, x);
-
- // 5. ReturnIfAbrupt(resolveResult).
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- // 6. Return deferred.[[Promise]].
- return JSValue::encode(deferred->promise());
-}
-
-EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncReject(ExecState* exec)
-{
- // -- Promise.reject(x) --
- JSValue r = exec->argument(0);
-
- // 1. Let 'C' be the this value.
- JSValue C = exec->thisValue();
-
- // 2. Let 'deferred' be the result of calling GetDeferred(C).
- JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);
-
- // 3. ReturnIfAbrupt(deferred).
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);
-
- // 4. Let 'rejectResult' be the result of calling the [[Call]] internal method
- // of deferred.[[Reject]] with undefined as thisArgument and a List containing r
- // as argumentsList.
- performDeferredReject(exec, deferred, r);
-
- // 5. ReturnIfAbrupt(resolveResult).
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- // 6. Return deferred.[[Promise]].
- return JSValue::encode(deferred->promise());
-}
-
-EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState* exec)
-{
- // -- Promise.race(iterable) --
- JSValue iterable = exec->argument(0);
- VM& vm = exec->vm();
-
- // 1. Let 'C' be the this value.
- JSValue C = exec->thisValue();
-
- // 2. Let 'deferred' be the result of calling GetDeferred(C).
- JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);
-
- // 3. ReturnIfAbrupt(deferred).
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);
-
- // 4. Let 'iterator' be the result of calling GetIterator(iterable).
- JSValue iteratorFunction = iterable.get(exec, vm.propertyNames->iteratorPrivateName);
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- CallData iteratorFunctionCallData;
- CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData);
- if (iteratorFunctionCallType == CallTypeNone) {
- throwTypeError(exec);
- return JSValue::encode(abruptRejection(exec, deferred));
- }
-
- ArgList iteratorFunctionArguments;
- JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments);
-
- // 5. RejectIfAbrupt(iterator, deferred).
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- // 6. Repeat
- do {
- // i. Let 'next' be the result of calling IteratorStep(iterator).
- JSValue nextFunction = iterator.get(exec, exec->vm().propertyNames->iteratorNextPrivateName);
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- CallData nextFunctionCallData;
- CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData);
- if (nextFunctionCallType == CallTypeNone) {
- throwTypeError(exec);
- return JSValue::encode(abruptRejection(exec, deferred));
- }
-
- MarkedArgumentBuffer nextFunctionArguments;
- nextFunctionArguments.append(jsUndefined());
- JSValue next = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments);
-
- // ii. RejectIfAbrupt(next, deferred).
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- // iii. If 'next' is false, return deferred.[[Promise]].
- // Note: We implement this as an iterationTerminator
- if (next == vm.iterationTerminator.get())
- return JSValue::encode(deferred->promise());
-
- // iv. Let 'nextValue' be the result of calling IteratorValue(next).
- // v. RejectIfAbrupt(nextValue, deferred).
- // Note: 'next' is already the value, so there is nothing to do here.
-
- // vi. Let 'nextPromise' be the result of calling Invoke(C, "cast", (nextValue)).
- JSValue castFunction = C.get(exec, vm.propertyNames->cast);
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- CallData castFunctionCallData;
- CallType castFunctionCallType = getCallData(castFunction, castFunctionCallData);
- if (castFunctionCallType == CallTypeNone) {
- throwTypeError(exec);
- return JSValue::encode(abruptRejection(exec, deferred));
- }
-
- MarkedArgumentBuffer castFunctionArguments;
- castFunctionArguments.append(next);
- JSValue nextPromise = call(exec, castFunction, castFunctionCallType, castFunctionCallData, C, castFunctionArguments);
-
- // vii. RejectIfAbrupt(nextPromise, deferred).
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- // viii. Let 'result' be the result of calling Invoke(nextPromise, "then", (deferred.[[Resolve]], deferred.[[Reject]])).
- JSValue thenFunction = nextPromise.get(exec, vm.propertyNames->then);
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- CallData thenFunctionCallData;
- CallType thenFunctionCallType = getCallData(thenFunction, thenFunctionCallData);
- if (thenFunctionCallType == CallTypeNone) {
- throwTypeError(exec);
- return JSValue::encode(abruptRejection(exec, deferred));
- }
-
- MarkedArgumentBuffer thenFunctionArguments;
- thenFunctionArguments.append(deferred->resolve());
- thenFunctionArguments.append(deferred->reject());
-
- call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments);
-
- // ix. RejectIfAbrupt(result, deferred).
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
- } while (true);
-}
-
-EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncAll(ExecState* exec)
-{
- // -- Promise.all(iterable) --
-
- JSValue iterable = exec->argument(0);
- VM& vm = exec->vm();
-
- // 1. Let 'C' be the this value.
- JSValue C = exec->thisValue();
-
- // 2. Let 'deferred' be the result of calling GetDeferred(C).
- JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);
-
- // 3. ReturnIfAbrupt(deferred).
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- // NOTE: A non-abrupt completion of createJSPromiseDeferredFromConstructor implies that
- // C and deferredValue are objects.
- JSObject* thisObject = asObject(C);
- JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);
-
- // 4. Let 'iterator' be the result of calling GetIterator(iterable).
- JSValue iteratorFunction = iterable.get(exec, vm.propertyNames->iteratorPrivateName);
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- CallData iteratorFunctionCallData;
- CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData);
- if (iteratorFunctionCallType == CallTypeNone) {
- throwTypeError(exec);
- return JSValue::encode(abruptRejection(exec, deferred));
- }
-
- ArgList iteratorFunctionArguments;
- JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments);
-
- // 5. RejectIfAbrupt(iterator, deferred).
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- // 6. Let 'values' be the result of calling ArrayCreate(0).
- JSArray* values = constructEmptyArray(exec, nullptr, thisObject->globalObject());
-
- // 7. Let 'countdownHolder' be Record { [[Countdown]]: 0 }.
- NumberObject* countdownHolder = constructNumber(exec, thisObject->globalObject(), JSValue(0));
-
- // 8. Let 'index' be 0.
- unsigned index = 0;
-
- // 9. Repeat.
- do {
- // i. Let 'next' be the result of calling IteratorStep(iterator).
- JSValue nextFunction = iterator.get(exec, exec->vm().propertyNames->iteratorNextPrivateName);
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- CallData nextFunctionCallData;
- CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData);
- if (nextFunctionCallType == CallTypeNone) {
- throwTypeError(exec);
- return JSValue::encode(abruptRejection(exec, deferred));
- }
-
- MarkedArgumentBuffer nextFunctionArguments;
- nextFunctionArguments.append(jsUndefined());
- JSValue next = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments);
-
- // ii. RejectIfAbrupt(next, deferred).
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- // iii. If 'next' is false,
- // Note: We implement this as an iterationTerminator
- if (next == vm.iterationTerminator.get()) {
- // a. If 'index' is 0,
- if (!index) {
- // a. Let 'resolveResult' be the result of calling the [[Call]] internal method
- // of deferred.[[Resolve]] with undefined as thisArgument and a List containing
- // values as argumentsList.
- performDeferredResolve(exec, deferred, values);
-
- // b. ReturnIfAbrupt(resolveResult).
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
- }
-
- // b. Return deferred.[[Promise]].
- return JSValue::encode(deferred->promise());
- }
-
- // iv. Let 'nextValue' be the result of calling IteratorValue(next).
- // v. RejectIfAbrupt(nextValue, deferred).
- // Note: 'next' is already the value, so there is nothing to do here.
-
- // vi. Let 'nextPromise' be the result of calling Invoke(C, "cast", (nextValue)).
- JSValue castFunction = C.get(exec, vm.propertyNames->cast);
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- CallData castFunctionCallData;
- CallType castFunctionCallType = getCallData(castFunction, castFunctionCallData);
- if (castFunctionCallType == CallTypeNone) {
- throwTypeError(exec);
- return JSValue::encode(abruptRejection(exec, deferred));
- }
-
- MarkedArgumentBuffer castFunctionArguments;
- castFunctionArguments.append(next);
- JSValue nextPromise = call(exec, castFunction, castFunctionCallType, castFunctionCallData, C, castFunctionArguments);
-
- // vii. RejectIfAbrupt(nextPromise, deferred).
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- // viii. Let 'countdownFunction' be a new built-in function object as defined in Promise.all Countdown Functions.
- JSFunction* countdownFunction = createPromiseAllCountdownFunction(vm, thisObject->globalObject());
-
- // ix. Set the [[Index]] internal slot of 'countdownFunction' to 'index'.
- countdownFunction->putDirect(vm, vm.propertyNames->indexPrivateName, JSValue(index));
-
- // x. Set the [[Values]] internal slot of 'countdownFunction' to 'values'.
- countdownFunction->putDirect(vm, vm.propertyNames->valuesPrivateName, values);
-
- // xi. Set the [[Deferred]] internal slot of 'countdownFunction' to 'deferred'.
- countdownFunction->putDirect(vm, vm.propertyNames->deferredPrivateName, deferred);
-
- // xii. Set the [[CountdownHolder]] internal slot of 'countdownFunction' to 'countdownHolder'.
- countdownFunction->putDirect(vm, vm.propertyNames->countdownHolderPrivateName, countdownHolder);
-
- // xiii. Let 'result' be the result of calling Invoke(nextPromise, "then", (countdownFunction, deferred.[[Reject]])).
- JSValue thenFunction = nextPromise.get(exec, vm.propertyNames->then);
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- CallData thenFunctionCallData;
- CallType thenFunctionCallType = getCallData(thenFunction, thenFunctionCallData);
- if (thenFunctionCallType == CallTypeNone) {
- throwTypeError(exec);
- return JSValue::encode(abruptRejection(exec, deferred));
- }
-
- MarkedArgumentBuffer thenFunctionArguments;
- thenFunctionArguments.append(countdownFunction);
- thenFunctionArguments.append(deferred->reject());
-
- call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments);
-
- // xiv. RejectIfAbrupt(result, deferred).
- if (exec->hadException())
- return JSValue::encode(abruptRejection(exec, deferred));
-
- // xv. Set index to index + 1.
- index++;
-
- // xvi. Set countdownHolder.[[Countdown]] to countdownHolder.[[Countdown]] + 1.
- uint32_t newCountdownValue = countdownHolder->internalValue().asUInt32() + 1;
- countdownHolder->setInternalValue(vm, JSValue(newCountdownValue));
- } while (true);
-}
-
-JSPromise* constructPromise(ExecState* exec, JSGlobalObject* globalObject, JSFunction* resolver)
-{
- JSPromiseConstructor* promiseConstructor = globalObject->promiseConstructor();
-
- ConstructData constructData;
- ConstructType constructType = getConstructData(promiseConstructor, constructData);
- ASSERT(constructType != ConstructTypeNone);
-
- MarkedArgumentBuffer arguments;
- arguments.append(resolver);
-
- return jsCast<JSPromise*>(construct(exec, promiseConstructor, constructType, constructData, arguments));
+ return getStaticFunctionSlot<Base>(exec, promiseConstructorTable, jsCast<JSPromiseConstructor*>(object), propertyName, slot);
}
} // namespace JSC
-
-#endif // ENABLE(PROMISES)
diff --git a/Source/JavaScriptCore/runtime/JSPromiseConstructor.h b/Source/JavaScriptCore/runtime/JSPromiseConstructor.h
index 498bb8b56..92c1d9025 100644
--- a/Source/JavaScriptCore/runtime/JSPromiseConstructor.h
+++ b/Source/JavaScriptCore/runtime/JSPromiseConstructor.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -26,39 +26,37 @@
#ifndef JSPromiseConstructor_h
#define JSPromiseConstructor_h
-#if ENABLE(PROMISES)
-
#include "InternalFunction.h"
namespace JSC {
class JSPromise;
class JSPromisePrototype;
+class GetterSetter;
class JSPromiseConstructor : public InternalFunction {
public:
typedef InternalFunction Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
- static JSPromiseConstructor* create(VM&, Structure*, JSPromisePrototype*);
+ static JSPromiseConstructor* create(VM&, Structure*, JSPromisePrototype*, GetterSetter* speciesSymbol);
static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
DECLARE_INFO;
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+
protected:
- void finishCreation(VM&, JSPromisePrototype*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
+ JSPromiseConstructor(VM&, Structure*);
+ void finishCreation(VM&, JSPromisePrototype*, GetterSetter*);
private:
- JSPromiseConstructor(VM&, Structure*);
static ConstructType getConstructData(JSCell*, ConstructData&);
static CallType getCallData(JSCell*, CallData&);
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
-};
-JSPromise* constructPromise(ExecState*, JSGlobalObject*, JSFunction*);
+ void addOwnInternalSlots(VM&, JSGlobalObject*);
+};
} // namespace JSC
-#endif // ENABLE(PROMISES)
-
#endif // JSPromiseConstructor_h
diff --git a/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp b/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp
index cbc42eb9f..ba7697344 100644
--- a/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp
+++ b/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp
@@ -26,29 +26,45 @@
#include "config.h"
#include "JSPromiseDeferred.h"
+#include "BuiltinNames.h"
#include "Error.h"
+#include "Exception.h"
#include "JSCJSValueInlines.h"
#include "JSCellInlines.h"
#include "JSPromise.h"
#include "JSPromiseConstructor.h"
-#include "JSPromiseFunctions.h"
#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
namespace JSC {
-const ClassInfo JSPromiseDeferred::s_info = { "JSPromiseDeferred", 0, 0, 0, CREATE_METHOD_TABLE(JSPromiseDeferred) };
+const ClassInfo JSPromiseDeferred::s_info = { "JSPromiseDeferred", 0, 0, CREATE_METHOD_TABLE(JSPromiseDeferred) };
+
+JSValue newPromiseCapability(ExecState* exec, JSGlobalObject* globalObject, JSPromiseConstructor* promiseConstructor)
+{
+ JSFunction* newPromiseCapabilityFunction = globalObject->newPromiseCapabilityFunction();
+ CallData callData;
+ CallType callType = JSC::getCallData(newPromiseCapabilityFunction, callData);
+ ASSERT(callType != CallTypeNone);
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(promiseConstructor);
+ return call(exec, newPromiseCapabilityFunction, callType, callData, jsUndefined(), arguments);
+}
+
JSPromiseDeferred* JSPromiseDeferred::create(ExecState* exec, JSGlobalObject* globalObject)
{
VM& vm = exec->vm();
-
- JSFunction* resolver = createDeferredConstructionFunction(vm, globalObject);
- JSPromise* promise = constructPromise(exec, globalObject, resolver);
- JSValue resolve = resolver->get(exec, vm.propertyNames->resolvePrivateName);
- JSValue reject = resolver->get(exec, vm.propertyNames->rejectPrivateName);
+ JSValue deferred = newPromiseCapability(exec, globalObject, globalObject->promiseConstructor());
+
+ JSValue promise = deferred.get(exec, vm.propertyNames->promisePrivateName);
+ ASSERT(promise.inherits(JSPromise::info()));
+ JSValue resolve = deferred.get(exec, vm.propertyNames->builtinNames().resolvePrivateName());
+ JSValue reject = deferred.get(exec, vm.propertyNames->builtinNames().rejectPrivateName());
- return JSPromiseDeferred::create(vm, promise, resolve, reject);
+ return JSPromiseDeferred::create(vm, jsCast<JSPromise*>(promise), resolve, reject);
}
JSPromiseDeferred* JSPromiseDeferred::create(VM& vm, JSObject* promise, JSValue resolve, JSValue reject)
@@ -59,188 +75,55 @@ JSPromiseDeferred* JSPromiseDeferred::create(VM& vm, JSObject* promise, JSValue
}
JSPromiseDeferred::JSPromiseDeferred(VM& vm)
- : Base(vm, vm.promiseDeferredStructure.get())
+ : JSPromiseDeferred(vm, vm.promiseDeferredStructure.get())
{
}
-void JSPromiseDeferred::finishCreation(VM& vm, JSObject* promise, JSValue resolve, JSValue reject)
-{
- Base::finishCreation(vm);
- m_promise.set(vm, this, promise);
- m_resolve.set(vm, this, resolve);
- m_reject.set(vm, this, reject);
-}
-
-void JSPromiseDeferred::visitChildren(JSCell* cell, SlotVisitor& visitor)
+JSPromiseDeferred::JSPromiseDeferred(VM& vm, Structure* structure)
+ : Base(vm, structure)
{
- JSPromiseDeferred* thisObject = jsCast<JSPromiseDeferred*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
- Base::visitChildren(thisObject, visitor);
-
- visitor.append(&thisObject->m_promise);
- visitor.append(&thisObject->m_resolve);
- visitor.append(&thisObject->m_reject);
}
-JSValue createJSPromiseDeferredFromConstructor(ExecState* exec, JSValue C)
+static inline void callFunction(ExecState* exec, JSValue function, JSValue value)
{
- // -- This implements the GetDeferred(C) abstract operation --
-
- // 1. If IsConstructor(C) is false, throw a TypeError.
- if (!C.isObject())
- return throwTypeError(exec);
-
- ConstructData constructData;
- ConstructType constructType = getConstructData(C, constructData);
- if (constructType == ConstructTypeNone)
- return throwTypeError(exec);
-
- VM& vm = exec->vm();
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ ASSERT(callType != CallTypeNone);
- // 2. Let 'resolver' be a new built-in function object as defined in Deferred Construction Functions.
- JSFunction* resolver = createDeferredConstructionFunction(vm, asObject(C)->globalObject());
-
- // 3. Let 'promise' be the result of calling the [[Construct]] internal method of 'C' with
- // an argument list containing the single item resolver.
- MarkedArgumentBuffer constructArguments;
- constructArguments.append(resolver);
- JSObject* promise = construct(exec, C, constructType, constructData, constructArguments);
-
- // 4. ReturnIfAbrupt(promise).
- if (exec->hadException())
- return jsUndefined();
-
- // 5. Let 'resolve' be the value of resolver's [[Resolve]] internal slot.
- JSValue resolve = resolver->get(exec, vm.propertyNames->resolvePrivateName);
-
- // 6. If IsCallable(resolve) is false, throw a TypeError.
- CallData resolveCallData;
- CallType resolveCallType = getCallData(resolve, resolveCallData);
- if (resolveCallType == CallTypeNone)
- return throwTypeError(exec);
-
- // 7. Let 'reject' be the value of resolver's [[Reject]] internal slot.
- JSValue reject = resolver->get(exec, vm.propertyNames->rejectPrivateName);
-
- // 8. If IsCallable(reject) is false, throw a TypeError.
- CallData rejectCallData;
- CallType rejectCallType = getCallData(reject, rejectCallData);
- if (rejectCallType == CallTypeNone)
- return throwTypeError(exec);
+ MarkedArgumentBuffer arguments;
+ arguments.append(value);
- // 9. Return the Deferred { [[Promise]]: promise, [[Resolve]]: resolve, [[Reject]]: reject }.
- return JSPromiseDeferred::create(exec->vm(), promise, resolve, reject);
+ call(exec, function, callType, callData, jsUndefined(), arguments);
}
-ThenableStatus updateDeferredFromPotentialThenable(ExecState* exec, JSValue x, JSPromiseDeferred* deferred)
+void JSPromiseDeferred::resolve(ExecState* exec, JSValue value)
{
- // 1. If Type(x) is not Object, return "not a thenable".
- if (!x.isObject())
- return NotAThenable;
-
- // 2. Let 'then' be the result of calling Get(x, "then").
- JSValue thenValue = x.get(exec, exec->vm().propertyNames->then);
-
- // 3. If then is an abrupt completion,
- if (exec->hadException()) {
- // i. Let 'rejectResult' be the result of calling the [[Call]] internal method of
- // deferred.[[Reject]] with undefined as thisArgument and a List containing
- // then.[[value]] as argumentsList.
- JSValue exception = exec->exception();
- exec->clearException();
-
- performDeferredReject(exec, deferred, exception);
-
- // ii. ReturnIfAbrupt(rejectResult).
- // NOTE: Nothing to do.
-
- // iii. Return.
- return WasAThenable;
- }
-
- // 4. Let 'then' be then.[[value]].
- // Note: Nothing to do.
-
- // 5. If IsCallable(then) is false, return "not a thenable".
- CallData thenCallData;
- CallType thenCallType = getCallData(thenValue, thenCallData);
- if (thenCallType == CallTypeNone)
- return NotAThenable;
-
- // 6. Let 'thenCallResult' be the result of calling the [[Call]] internal method of
- // 'then' passing x as thisArgument and a List containing deferred.[[Resolve]] and
- // deferred.[[Reject]] as argumentsList.
- MarkedArgumentBuffer thenArguments;
- thenArguments.append(deferred->resolve());
- thenArguments.append(deferred->reject());
-
- call(exec, thenValue, thenCallType, thenCallData, x, thenArguments);
-
- // 7. If 'thenCallResult' is an abrupt completion,
- if (exec->hadException()) {
- // i. Let 'rejectResult' be the result of calling the [[Call]] internal method of
- // deferred.[[Reject]] with undefined as thisArgument and a List containing
- // thenCallResult.[[value]] as argumentsList.
- JSValue exception = exec->exception();
- exec->clearException();
-
- performDeferredReject(exec, deferred, exception);
-
- // ii. ReturnIfAbrupt(rejectResult).
- // NOTE: Nothing to do.
- }
-
- return WasAThenable;
+ callFunction(exec, m_resolve.get(), value);
}
-void performDeferredResolve(ExecState* exec, JSPromiseDeferred* deferred, JSValue argument)
+void JSPromiseDeferred::reject(ExecState* exec, JSValue reason)
{
- JSValue deferredResolve = deferred->resolve();
-
- CallData resolveCallData;
- CallType resolveCallType = getCallData(deferredResolve, resolveCallData);
- ASSERT(resolveCallType != CallTypeNone);
-
- MarkedArgumentBuffer arguments;
- arguments.append(argument);
-
- call(exec, deferredResolve, resolveCallType, resolveCallData, jsUndefined(), arguments);
+ callFunction(exec, m_reject.get(), reason);
}
-void performDeferredReject(ExecState* exec, JSPromiseDeferred* deferred, JSValue argument)
+void JSPromiseDeferred::finishCreation(VM& vm, JSObject* promise, JSValue resolve, JSValue reject)
{
- JSValue deferredReject = deferred->reject();
-
- CallData rejectCallData;
- CallType rejectCallType = getCallData(deferredReject, rejectCallData);
- ASSERT(rejectCallType != CallTypeNone);
-
- MarkedArgumentBuffer arguments;
- arguments.append(argument);
-
- call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), arguments);
+ Base::finishCreation(vm);
+ m_promise.set(vm, this, promise);
+ m_resolve.set(vm, this, resolve);
+ m_reject.set(vm, this, reject);
}
-JSValue abruptRejection(ExecState* exec, JSPromiseDeferred* deferred)
+void JSPromiseDeferred::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
- ASSERT(exec->hadException());
- JSValue argument = exec->exception();
- exec->clearException();
-
- // i. Let 'rejectResult' be the result of calling the [[Call]] internal method
- // of deferred.[[Reject]] with undefined as thisArgument and a List containing
- // argument.[[value]] as argumentsList.
- performDeferredReject(exec, deferred, argument);
+ JSPromiseDeferred* thisObject = jsCast<JSPromiseDeferred*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- // ii. ReturnIfAbrupt(rejectResult).
- if (exec->hadException())
- return jsUndefined();
+ Base::visitChildren(thisObject, visitor);
- // iii. Return deferred.[[Promise]].
- return deferred->promise();
+ visitor.append(&thisObject->m_promise);
+ visitor.append(&thisObject->m_resolve);
+ visitor.append(&thisObject->m_reject);
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSPromiseDeferred.h b/Source/JavaScriptCore/runtime/JSPromiseDeferred.h
index ff509d77a..db7dc55d9 100644
--- a/Source/JavaScriptCore/runtime/JSPromiseDeferred.h
+++ b/Source/JavaScriptCore/runtime/JSPromiseDeferred.h
@@ -31,49 +31,44 @@
namespace JSC {
+class JSPromiseConstructor;
+
class JSPromiseDeferred : public JSCell {
public:
typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
JS_EXPORT_PRIVATE static JSPromiseDeferred* create(ExecState*, JSGlobalObject*);
JS_EXPORT_PRIVATE static JSPromiseDeferred* create(VM&, JSObject* promise, JSValue resolve, JSValue reject);
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), info());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
}
- static const bool hasImmortalStructure = true;
-
DECLARE_EXPORT_INFO;
JSObject* promise() const { return m_promise.get(); }
JSValue resolve() const { return m_resolve.get(); }
JSValue reject() const { return m_reject.get(); }
-private:
- JSPromiseDeferred(VM&);
+ JS_EXPORT_PRIVATE void resolve(ExecState*, JSValue);
+ JS_EXPORT_PRIVATE void reject(ExecState*, JSValue);
+
+protected:
+ JSPromiseDeferred(VM&, Structure*);
void finishCreation(VM&, JSObject*, JSValue, JSValue);
- static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
static void visitChildren(JSCell*, SlotVisitor&);
+private:
+ JSPromiseDeferred(VM&);
+
WriteBarrier<JSObject> m_promise;
WriteBarrier<Unknown> m_resolve;
WriteBarrier<Unknown> m_reject;
};
-enum ThenableStatus {
- WasAThenable,
- NotAThenable
-};
-
-JSValue createJSPromiseDeferredFromConstructor(ExecState*, JSValue constructor);
-ThenableStatus updateDeferredFromPotentialThenable(ExecState*, JSValue, JSPromiseDeferred*);
-
-void performDeferredResolve(ExecState*, JSPromiseDeferred*, JSValue argument);
-void performDeferredReject(ExecState*, JSPromiseDeferred*, JSValue argument);
-
-JSValue abruptRejection(ExecState*, JSPromiseDeferred*);
+JSValue newPromiseCapability(ExecState*, JSGlobalObject*, JSPromiseConstructor*);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSPromiseFunctions.cpp b/Source/JavaScriptCore/runtime/JSPromiseFunctions.cpp
deleted file mode 100644
index 139d280e8..000000000
--- a/Source/JavaScriptCore/runtime/JSPromiseFunctions.cpp
+++ /dev/null
@@ -1,274 +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. 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 "JSPromiseFunctions.h"
-
-#if ENABLE(PROMISES)
-
-#include "Error.h"
-#include "JSCJSValueInlines.h"
-#include "JSCellInlines.h"
-#include "JSPromise.h"
-#include "JSPromiseConstructor.h"
-#include "JSPromiseDeferred.h"
-#include "NumberObject.h"
-
-namespace JSC {
-
-// Deferred Construction Functions
-static EncodedJSValue JSC_HOST_CALL deferredConstructionFunction(ExecState* exec)
-{
- JSObject* F = exec->callee();
-
- VM& vm = exec->vm();
-
- // 1. Set F's [[Resolve]] internal slot to resolve.
- F->putDirect(vm, vm.propertyNames->resolvePrivateName, exec->argument(0));
-
- // 2. Set F's [[Reject]] internal slot to reject.
- F->putDirect(vm, vm.propertyNames->rejectPrivateName, exec->argument(1));
-
- // 3. Return.
- return JSValue::encode(jsUndefined());
-}
-
-JSFunction* createDeferredConstructionFunction(VM& vm, JSGlobalObject* globalObject)
-{
- return JSFunction::create(vm, globalObject, 2, ASCIILiteral("DeferredConstructionFunction"), deferredConstructionFunction);
-}
-
-// Identity Functions
-
-static EncodedJSValue JSC_HOST_CALL identifyFunction(ExecState* exec)
-{
- return JSValue::encode(exec->argument(0));
-}
-
-JSFunction* createIdentifyFunction(VM& vm, JSGlobalObject* globalObject)
-{
- return JSFunction::create(vm, globalObject, 1, ASCIILiteral("IdentityFunction"), identifyFunction);
-}
-
-// Promise.All Countdown Functions
-
-static EncodedJSValue JSC_HOST_CALL promiseAllCountdownFunction(ExecState* exec)
-{
- JSValue x = exec->argument(0);
- VM& vm = exec->vm();
- JSObject* F = exec->callee();
-
- // 1. Let 'index' be the value of F's [[Index]] internal slot.
- uint32_t index = F->get(exec, vm.propertyNames->indexPrivateName).asUInt32();
-
- // 2. Let 'values' be the value of F's [[Values]] internal slot..
- JSArray* values = jsCast<JSArray*>(F->get(exec, vm.propertyNames->valuesPrivateName));
-
- // 3. Let 'deferred' be the value of F's [[Deferred]] internal slot.
- JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(F->get(exec, vm.propertyNames->deferredPrivateName));
-
- // 4. Let 'countdownHolder' be the value of F's [[CountdownHolder]] internal slot.
- NumberObject* countdownHolder = jsCast<NumberObject*>(F->get(exec, vm.propertyNames->countdownHolderPrivateName));
-
- // 5. Let 'result' be the result of calling the [[DefineOwnProperty]] internal method
- // of 'values' with arguments 'index' and Property Descriptor { [[Value]]: x,
- // [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true }.
- values->putDirectIndex(exec, index, x);
-
- // 6. RejectIfAbrupt(result, deferred).
- if (exec->hadException())
- abruptRejection(exec, deferred);
-
- // 7. Set countdownHolder.[[Countdown]] to countdownHolder.[[Countdown]] - 1.
- uint32_t newCountdownValue = countdownHolder->internalValue().asUInt32() - 1;
- countdownHolder->setInternalValue(vm, JSValue(newCountdownValue));
-
- // 8. If countdownHolder.[[Countdown]] is 0,
- if (!newCountdownValue) {
- // i. Return the result of calling the [[Call]] internal method of deferred.[[Resolve]]
- // with undefined as thisArgument and a List containing 'values' as argumentsList.
- performDeferredResolve(exec, deferred, values);
- }
-
- // 9. Return.
- return JSValue::encode(jsUndefined());
-}
-
-JSFunction* createPromiseAllCountdownFunction(VM& vm, JSGlobalObject* globalObject)
-{
- return JSFunction::create(vm, globalObject, 1, ASCIILiteral("PromiseAllCountdownFunction"), promiseAllCountdownFunction);
-}
-
-// Promise Resolution Handler Functions
-
-static EncodedJSValue JSC_HOST_CALL promiseResolutionHandlerFunction(ExecState* exec)
-{
- JSValue x = exec->argument(0);
- VM& vm = exec->vm();
- JSObject* F = exec->callee();
-
- // 1. Let 'promise' be the value of F's [[Promise]] internal slot
- JSPromise* promise = jsCast<JSPromise*>(F->get(exec, vm.propertyNames->promisePrivateName));
-
- // 2. Let 'fulfillmentHandler' be the value of F's [[FulfillmentHandler]] internal slot.
- JSValue fulfillmentHandler = F->get(exec, vm.propertyNames->fulfillmentHandlerPrivateName);
-
- // 3. Let 'rejectionHandler' be the value of F's [[RejectionHandler]] internal slot.
- JSValue rejectionHandler = F->get(exec, vm.propertyNames->rejectionHandlerPrivateName);
-
- // 4. If SameValue(x, promise) is true,
- if (sameValue(exec, x, promise)) {
- // i. Let 'selfResolutionError' be a newly-created TypeError object.
- JSObject* selfResolutionError = createTypeError(exec, ASCIILiteral("Resolve a promise with itself"));
- // ii. Return the result of calling the [[Call]] internal method of rejectionHandler with
- // undefined as thisArgument and a List containing selfResolutionError as argumentsList.
- CallData rejectCallData;
- CallType rejectCallType = getCallData(rejectionHandler, rejectCallData);
- ASSERT(rejectCallType != CallTypeNone);
-
- MarkedArgumentBuffer rejectArguments;
- rejectArguments.append(selfResolutionError);
-
- return JSValue::encode(call(exec, rejectionHandler, rejectCallType, rejectCallData, jsUndefined(), rejectArguments));
- }
-
- // 5. Let 'C' be the value of promise's [[PromiseConstructor]] internal slot.
- JSValue C = promise->constructor();
-
- // 6. Let 'deferred' be the result of calling GetDeferred(C)
- JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C);
-
- // 7. ReturnIfAbrupt(deferred).
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue);
-
- // 8. Let 'updateResult' be the result of calling UpdateDeferredFromPotentialThenable(x, deferred).
- ThenableStatus updateResult = updateDeferredFromPotentialThenable(exec, x, deferred);
-
- // 9. ReturnIfAbrupt(updateResult).
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- // 10. If 'updateResult' is not "not a thenable", return the result of calling
- // Invoke(deferred.[[Promise]], "then", (fulfillmentHandler, rejectionHandler)).
- // NOTE: Invoke does not seem to be defined anywhere, so I am guessing here.
- if (updateResult != NotAThenable) {
- JSObject* deferredPromise = deferred->promise();
-
- JSValue thenValue = deferredPromise->get(exec, exec->vm().propertyNames->then);
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- CallData thenCallData;
- CallType thenCallType = getCallData(thenValue, thenCallData);
- if (thenCallType == CallTypeNone)
- return JSValue::encode(throwTypeError(exec));
-
- MarkedArgumentBuffer arguments;
- arguments.append(fulfillmentHandler);
- arguments.append(rejectionHandler);
-
- return JSValue::encode(call(exec, thenValue, thenCallType, thenCallData, deferredPromise, arguments));
- }
-
- // 11. Return the result of calling the [[Call]] internal method of fulfillmentHandler
- // with undefined as thisArgument and a List containing x as argumentsList.
- CallData fulfillmentHandlerCallData;
- CallType fulfillmentHandlerCallType = getCallData(fulfillmentHandler, fulfillmentHandlerCallData);
- ASSERT(fulfillmentHandlerCallType != CallTypeNone);
-
- MarkedArgumentBuffer fulfillmentHandlerArguments;
- fulfillmentHandlerArguments.append(x);
-
- return JSValue::encode(call(exec, fulfillmentHandler, fulfillmentHandlerCallType, fulfillmentHandlerCallData, jsUndefined(), fulfillmentHandlerArguments));
-}
-
-JSFunction* createPromiseResolutionHandlerFunction(VM& vm, JSGlobalObject* globalObject)
-{
- return JSFunction::create(vm, globalObject, 1, ASCIILiteral("PromiseResolutionHandlerFunction"), promiseResolutionHandlerFunction);
-}
-
-// Reject Promise Functions
-
-static EncodedJSValue JSC_HOST_CALL rejectPromiseFunction(ExecState* exec)
-{
- JSValue reason = exec->argument(0);
- JSObject* F = exec->callee();
- VM& vm = exec->vm();
-
- // 1. Let 'promise' be the value of F's [[Promise]] internal slot.
- JSPromise* promise = jsCast<JSPromise*>(F->get(exec, exec->vm().propertyNames->promisePrivateName));
-
- // 2. Return the result of calling PromiseReject(promise, reason);
- promise->reject(vm, reason);
-
- return JSValue::encode(jsUndefined());
-}
-
-JSFunction* createRejectPromiseFunction(VM& vm, JSGlobalObject* globalObject)
-{
- return JSFunction::create(vm, globalObject, 1, ASCIILiteral("RejectPromiseFunction"), rejectPromiseFunction);
-}
-
-// Resolve Promise Functions
-
-static EncodedJSValue JSC_HOST_CALL resolvePromiseFunction(ExecState* exec)
-{
- JSValue resolution = exec->argument(0);
- JSObject* F = exec->callee();
- VM& vm = exec->vm();
-
- // 1. Let 'promise' be the value of F's [[Promise]] internal slot.
- JSPromise* promise = jsCast<JSPromise*>(F->get(exec, vm.propertyNames->promisePrivateName));
-
- // 2. Return the result of calling PromiseResolve(promise, resolution);
- promise->resolve(vm, resolution);
-
- return JSValue::encode(jsUndefined());
-}
-
-JSFunction* createResolvePromiseFunction(VM& vm, JSGlobalObject* globalObject)
-{
- return JSFunction::create(vm, globalObject, 1, ASCIILiteral("ResolvePromiseFunction"), resolvePromiseFunction);
-}
-
-// Thrower Functions
-
-static EncodedJSValue JSC_HOST_CALL throwerFunction(ExecState* exec)
-{
- return JSValue::encode(exec->vm().throwException(exec, exec->argument(0)));
-}
-
-JSFunction* createThrowerFunction(VM& vm, JSGlobalObject* globalObject)
-{
- return JSFunction::create(vm, globalObject, 1, ASCIILiteral("ThrowerFunction"), throwerFunction);
-}
-
-
-} // namespace JSC
-
-#endif // ENABLE(PROMISES)
diff --git a/Source/JavaScriptCore/runtime/JSPromisePrototype.cpp b/Source/JavaScriptCore/runtime/JSPromisePrototype.cpp
index 9df457817..bac304d7d 100644
--- a/Source/JavaScriptCore/runtime/JSPromisePrototype.cpp
+++ b/Source/JavaScriptCore/runtime/JSPromisePrototype.cpp
@@ -26,16 +26,14 @@
#include "config.h"
#include "JSPromisePrototype.h"
-#if ENABLE(PROMISES)
-
+#include "BuiltinNames.h"
#include "Error.h"
+#include "JSCBuiltins.h"
#include "JSCJSValueInlines.h"
#include "JSCellInlines.h"
+#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "JSPromise.h"
-#include "JSPromiseDeferred.h"
-#include "JSPromiseFunctions.h"
-#include "JSPromiseReaction.h"
#include "Microtask.h"
#include "StructureInlines.h"
@@ -43,29 +41,26 @@ namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSPromisePrototype);
-static EncodedJSValue JSC_HOST_CALL JSPromisePrototypeFuncThen(ExecState*);
-static EncodedJSValue JSC_HOST_CALL JSPromisePrototypeFuncCatch(ExecState*);
-
}
#include "JSPromisePrototype.lut.h"
namespace JSC {
-const ClassInfo JSPromisePrototype::s_info = { "PromisePrototype", &JSNonFinalObject::s_info, 0, ExecState::promisePrototypeTable, CREATE_METHOD_TABLE(JSPromisePrototype) };
+const ClassInfo JSPromisePrototype::s_info = { "PromisePrototype", &Base::s_info, &promisePrototypeTable, CREATE_METHOD_TABLE(JSPromisePrototype) };
/* Source for JSPromisePrototype.lut.h
@begin promisePrototypeTable
- then JSPromisePrototypeFuncThen DontEnum|Function 2
- catch JSPromisePrototypeFuncCatch DontEnum|Function 1
+ then JSBuiltin DontEnum|Function 2
+ catch JSBuiltin DontEnum|Function 1
@end
*/
-JSPromisePrototype* JSPromisePrototype::create(ExecState* exec, JSGlobalObject*, Structure* structure)
+JSPromisePrototype* JSPromisePrototype::create(VM& vm, JSGlobalObject*, Structure* structure)
{
- VM& vm = exec->vm();
- JSPromisePrototype* object = new (NotNull, allocateCell<JSPromisePrototype>(vm.heap)) JSPromisePrototype(exec, structure);
+ JSPromisePrototype* object = new (NotNull, allocateCell<JSPromisePrototype>(vm.heap)) JSPromisePrototype(vm, structure);
object->finishCreation(vm, structure);
+ object->addOwnInternalSlots(vm, structure->globalObject());
return object;
}
@@ -74,144 +69,25 @@ Structure* JSPromisePrototype::createStructure(VM& vm, JSGlobalObject* globalObj
return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}
-JSPromisePrototype::JSPromisePrototype(ExecState* exec, Structure* structure)
- : JSNonFinalObject(exec->vm(), structure)
+JSPromisePrototype::JSPromisePrototype(VM& vm, Structure* structure)
+ : JSNonFinalObject(vm, structure)
{
}
void JSPromisePrototype::finishCreation(VM& vm, Structure*)
{
Base::finishCreation(vm);
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Promise"), DontEnum | ReadOnly);
}
-bool JSPromisePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
-{
- return getStaticFunctionSlot<JSObject>(exec, ExecState::promisePrototypeTable(exec->vm()), jsCast<JSPromisePrototype*>(object), propertyName, slot);
-}
-
-EncodedJSValue JSC_HOST_CALL JSPromisePrototypeFuncThen(ExecState* exec)
+void JSPromisePrototype::addOwnInternalSlots(VM& vm, JSGlobalObject* globalObject)
{
- // -- Promise.prototype.then(onFulfilled, onRejected) --
-
- // 1. Let promise be the this value.
- // 2. If IsPromise(promise) is false, throw a TypeError exception.
- JSPromise* promise = jsDynamicCast<JSPromise*>(exec->thisValue());
- if (!promise)
- return JSValue::encode(throwTypeError(exec));
-
- // 3. Let 'C' be the result of calling Get(promise, "constructor").
- JSValue C = promise->get(exec, exec->propertyNames().constructor);
-
- // 4. ReturnIfAbrupt(C).
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- // 5. Let 'deferred' be the result of calling GetDeferred(C).
- JSValue deferred = createJSPromiseDeferredFromConstructor(exec, C);
-
- // 6. ReturnIfAbrupt(deferred).
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- VM& vm = exec->vm();
- JSGlobalObject* globalObject = promise->globalObject();
-
- // 7. Let 'rejectionHandler' be a new built-in function object as defined in Thrower Functions
- // 8. If IsCallable(onRejected), set rejectionHandler to onRejected.
- JSValue onRejected = exec->argument(1);
- CallData onRejectedCallData;
- CallType onRejectedCallType = getCallData(onRejected, onRejectedCallData);
- JSObject* rejectionHandler = (onRejectedCallType == CallTypeNone) ? createThrowerFunction(vm, globalObject) : asObject(onRejected);
-
- // 9. Let 'fulfillmentHandler' be a new built-in function object as defined in Identity Functions
- // 10. If IsCallable(onFulfilled), set fulfillmentHandler to onFulfilled
- JSValue onFulfilled = exec->argument(0);
- CallData onFulfilledCallData;
- CallType onFulfilledCallType = getCallData(onFulfilled, onFulfilledCallData);
- JSObject* fulfillmentHandler = (onFulfilledCallType == CallTypeNone) ? createIdentifyFunction(vm, globalObject) : asObject(onFulfilled);
-
- // 11. Let 'resolutionHandler' be a new built-in function object as defined in Promise Resolution Handler Functions
- JSObject* resolutionHandler = createPromiseResolutionHandlerFunction(vm, globalObject);
-
- // 12. Set the [[Promise]] internal slot of resolutionHandler to promise.
- resolutionHandler->putDirect(vm, vm.propertyNames->promisePrivateName, promise);
-
- // 13. Set the [[FulfillmentHandler]] internal slot of resolutionHandler to fulfillmentHandler.
- resolutionHandler->putDirect(vm, vm.propertyNames->fulfillmentHandlerPrivateName, fulfillmentHandler);
-
- // 14. Set the [[RejectionHandler]] internal slot of resolutionHandler to rejectionHandler.
- resolutionHandler->putDirect(vm, vm.propertyNames->rejectionHandlerPrivateName, rejectionHandler);
-
- // 15. Let 'resolveReaction' be the PromiseReaction { [[Deferred]]: deferred, [[Handler]]: resolutionHandler }.
- JSPromiseReaction* resolveReaction = JSPromiseReaction::create(vm, jsCast<JSPromiseDeferred*>(deferred), resolutionHandler);
-
- // 16. Let 'rejectReaction' be the PromiseReaction { [[Deferred]]: deferred, [[Handler]]: rejectionHandler }.
- JSPromiseReaction* rejectReaction = JSPromiseReaction::create(vm, jsCast<JSPromiseDeferred*>(deferred), rejectionHandler);
-
- switch (promise->status()) {
- case JSPromise::Status::Unresolved: {
- // 17. If the value of promise's [[PromiseStatus]] internal slot is "unresolved",
-
- // i. Append resolveReaction as the last element of promise's [[ResolveReactions]] internal slot.
- promise->appendResolveReaction(vm, resolveReaction);
-
- // ii. Append rejectReaction as the last element of promise's [[RejectReactions]] internal slot.
- promise->appendRejectReaction(vm, rejectReaction);
- break;
- }
-
- case JSPromise::Status::HasResolution: {
- // 18. If the value of promise's [[PromiseStatus]] internal slot is "has-resolution",
-
- // i. Let 'resolution' be the value of promise's [[Result]] internal slot.
- JSValue resolution = promise->result();
-
- // ii. Call QueueMicrotask(ExecutePromiseReaction, (resolveReaction, resolution)).
- globalObject->queueMicrotask(createExecutePromiseReactionMicrotask(vm, resolveReaction, resolution));
- break;
- }
-
- case JSPromise::Status::HasRejection: {
- // 19. If the value of promise's [[PromiseStatus]] internal slot is "has-rejection",
-
- // i. Let reason be the value of promise's [[Result]] internal slot.
- JSValue reason = promise->result();
-
- // ii. Call QueueMicrotask(ExecutePromiseReaction, (rejectReaction, reason)).
- globalObject->queueMicrotask(createExecutePromiseReactionMicrotask(vm, rejectReaction, reason));
- break;
- }
- }
-
- // 20. Return deferred.[[Promise]].
- return JSValue::encode(jsCast<JSPromiseDeferred*>(deferred)->promise());
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().thenPrivateName(), promisePrototypeThenCodeGenerator, DontEnum | DontDelete | ReadOnly);
}
-EncodedJSValue JSC_HOST_CALL JSPromisePrototypeFuncCatch(ExecState* exec)
+bool JSPromisePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
- // -- Promise.prototype.catch(onRejected) --
-
- // 1. Let 'promise' be the this value.
- JSValue promise = exec->thisValue();
-
- // 2. Return the result of calling Invoke(promise, "then", (undefined, onRejected)).
- // NOTE: Invoke does not seem to be defined anywhere, so I am guessing here.
- JSValue thenValue = promise.get(exec, exec->vm().propertyNames->then);
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
-
- CallData thenCallData;
- CallType thenCallType = getCallData(thenValue, thenCallData);
- if (thenCallType == CallTypeNone)
- return JSValue::encode(throwTypeError(exec));
-
- MarkedArgumentBuffer arguments;
- arguments.append(jsUndefined());
- arguments.append(exec->argument(0));
-
- return JSValue::encode(call(exec, thenValue, thenCallType, thenCallData, promise, arguments));
+ return getStaticFunctionSlot<Base>(exec, promisePrototypeTable, jsCast<JSPromisePrototype*>(object), propertyName, slot);
}
} // namespace JSC
-
-#endif // ENABLE(PROMISES)
diff --git a/Source/JavaScriptCore/runtime/JSPromisePrototype.h b/Source/JavaScriptCore/runtime/JSPromisePrototype.h
index 893fc4afc..3128d30ff 100644
--- a/Source/JavaScriptCore/runtime/JSPromisePrototype.h
+++ b/Source/JavaScriptCore/runtime/JSPromisePrototype.h
@@ -26,8 +26,6 @@
#ifndef JSPromisePrototype_h
#define JSPromisePrototype_h
-#if ENABLE(PROMISES)
-
#include "JSObject.h"
namespace JSC {
@@ -35,23 +33,23 @@ namespace JSC {
class JSPromisePrototype : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
- static JSPromisePrototype* create(ExecState*, JSGlobalObject*, Structure*);
+ static JSPromisePrototype* create(VM&, JSGlobalObject*, Structure*);
static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
DECLARE_INFO;
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+
protected:
void finishCreation(VM&, Structure*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags;
+ JSPromisePrototype(VM&, Structure*);
private:
- JSPromisePrototype(ExecState*, Structure*);
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ void addOwnInternalSlots(VM&, JSGlobalObject*);
};
} // namespace JSC
-#endif // ENABLE(PROMISES)
-
#endif // JSPromisePrototype_h
diff --git a/Source/JavaScriptCore/runtime/JSPromiseReaction.cpp b/Source/JavaScriptCore/runtime/JSPromiseReaction.cpp
deleted file mode 100644
index 62578e121..000000000
--- a/Source/JavaScriptCore/runtime/JSPromiseReaction.cpp
+++ /dev/null
@@ -1,158 +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. 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 "JSPromiseReaction.h"
-
-#include "Error.h"
-#include "JSCJSValueInlines.h"
-#include "JSCellInlines.h"
-#include "JSGlobalObject.h"
-#include "JSPromiseDeferred.h"
-#include "Microtask.h"
-#include "SlotVisitorInlines.h"
-#include "StrongInlines.h"
-
-namespace JSC {
-
-class ExecutePromiseReactionMicrotask final : public Microtask {
-public:
- ExecutePromiseReactionMicrotask(VM& vm, JSPromiseReaction* reaction, JSValue argument)
- {
- m_reaction.set(vm, reaction);
- m_argument.set(vm, argument);
- }
-
- virtual ~ExecutePromiseReactionMicrotask()
- {
- }
-
-private:
- virtual void run(ExecState*) override;
-
- Strong<JSPromiseReaction> m_reaction;
- Strong<Unknown> m_argument;
-};
-
-PassRefPtr<Microtask> createExecutePromiseReactionMicrotask(VM& vm, JSPromiseReaction* reaction, JSValue argument)
-{
- return adoptRef(new ExecutePromiseReactionMicrotask(vm, reaction, argument));
-}
-
-void ExecutePromiseReactionMicrotask::run(ExecState* exec)
-{
- // 1. Let 'deferred' be reaction.[[Deferred]].
- JSPromiseDeferred* deferred = m_reaction->deferred();
-
- // 2. Let 'handler' be reaction.[[Handler]].
- JSValue handler = m_reaction->handler();
-
- // 3. Let 'handlerResult' be the result of calling the [[Call]] internal method of
- // handler passing undefined as thisArgument and a List containing argument as
- // argumentsList.
-
- CallData handlerCallData;
- CallType handlerCallType = getCallData(handler, handlerCallData);
- ASSERT(handlerCallType != CallTypeNone);
-
- MarkedArgumentBuffer handlerArguments;
- handlerArguments.append(m_argument.get());
-
- JSValue handlerResult = call(exec, handler, handlerCallType, handlerCallData, jsUndefined(), handlerArguments);
-
- // 4. If handlerResult is an abrupt completion, return the result of calling the
- // [[Call]] internal method of deferred.[[Reject]] passing undefined as thisArgument
- // and a List containing handlerResult.[[value]] as argumentsList.
- if (exec->hadException()) {
- JSValue exception = exec->exception();
- exec->clearException();
-
- performDeferredReject(exec, deferred, exception);
- }
-
- // 5. Let 'handlerResult' be handlerResult.[[value]].
- // Note: Nothing to do.
-
- // 6. If SameValue(handlerResult, deferred.[[Promise]]) is true,
- if (sameValue(exec, handlerResult, deferred->promise())) {
- // i. Let 'selfResolutionError' be a newly-created TypeError object.
- JSObject* selfResolutionError = createTypeError(exec, ASCIILiteral("Resolve a promise with itself"));
-
- // ii. Return the result of calling the [[Call]] internal method of deferred.[[Reject]] passing
- // undefined as thisArgument and a List containing selfResolutionError as argumentsList.
- performDeferredReject(exec, deferred, selfResolutionError);
- }
-
- // 7. Let 'updateResult' be the result of calling UpdateDeferredFromPotentialThenable(handlerResult, deferred).
- ThenableStatus updateResult = updateDeferredFromPotentialThenable(exec, handlerResult, deferred);
-
- // 8. ReturnIfAbrupt(updateResult).
- if (exec->hadException())
- return;
-
- // 9. If 'updateResult' is "not a thenable",
- if (updateResult == NotAThenable) {
- // i. Return the result of calling the [[Call]] internal method of deferred.[[Resolve]]
- // passing undefined as thisArgument and a List containing handlerResult as argumentsList.
- performDeferredResolve(exec, deferred, handlerResult);
- }
-}
-
-
-const ClassInfo JSPromiseReaction::s_info = { "JSPromiseReaction", 0, 0, 0, CREATE_METHOD_TABLE(JSPromiseReaction) };
-
-JSPromiseReaction* JSPromiseReaction::create(VM& vm, JSPromiseDeferred* deferred, JSValue handler)
-{
- JSPromiseReaction* promiseReaction = new (NotNull, allocateCell<JSPromiseReaction>(vm.heap)) JSPromiseReaction(vm);
- promiseReaction->finishCreation(vm, deferred, handler);
- return promiseReaction;
-}
-
-JSPromiseReaction::JSPromiseReaction(VM& vm)
- : Base(vm, vm.promiseReactionStructure.get())
-{
-}
-
-void JSPromiseReaction::finishCreation(VM& vm, JSPromiseDeferred* deferred, JSValue handler)
-{
- Base::finishCreation(vm);
- m_deferred.set(vm, this, deferred);
- m_handler.set(vm, this, handler);
-}
-
-void JSPromiseReaction::visitChildren(JSCell* cell, SlotVisitor& visitor)
-{
- JSPromiseReaction* thisObject = jsCast<JSPromiseReaction*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
- Base::visitChildren(thisObject, visitor);
-
- visitor.append(&thisObject->m_deferred);
- visitor.append(&thisObject->m_handler);
-}
-
-} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp b/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp
new file mode 100644
index 000000000..690920f0c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 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. 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 "JSPropertyNameEnumerator.h"
+
+#include "JSCInlines.h"
+#include "StrongInlines.h"
+
+namespace JSC {
+
+const ClassInfo JSPropertyNameEnumerator::s_info = { "JSPropertyNameEnumerator", 0, 0, CREATE_METHOD_TABLE(JSPropertyNameEnumerator) };
+
+JSPropertyNameEnumerator* JSPropertyNameEnumerator::create(VM& vm)
+{
+ if (!vm.emptyPropertyNameEnumerator.get()) {
+ PropertyNameArray propertyNames(&vm, PropertyNameMode::Strings);
+ vm.emptyPropertyNameEnumerator = Strong<JSCell>(vm, create(vm, 0, 0, 0, propertyNames));
+ }
+ return jsCast<JSPropertyNameEnumerator*>(vm.emptyPropertyNameEnumerator.get());
+}
+
+JSPropertyNameEnumerator* JSPropertyNameEnumerator::create(VM& vm, Structure* structure, uint32_t indexedLength, uint32_t numberStructureProperties, PropertyNameArray& propertyNames)
+{
+ StructureID structureID = structure ? structure->id() : 0;
+ uint32_t inlineCapacity = structure ? structure->inlineCapacity() : 0;
+ JSPropertyNameEnumerator* enumerator = new (NotNull,
+ allocateCell<JSPropertyNameEnumerator>(vm.heap)) JSPropertyNameEnumerator(vm, structureID, inlineCapacity);
+ enumerator->finishCreation(vm, indexedLength, numberStructureProperties, propertyNames.data());
+ return enumerator;
+}
+
+JSPropertyNameEnumerator::JSPropertyNameEnumerator(VM& vm, StructureID structureID, uint32_t inlineCapacity)
+ : JSCell(vm, vm.propertyNameEnumeratorStructure.get())
+ , m_cachedStructureID(structureID)
+ , m_cachedInlineCapacity(inlineCapacity)
+{
+}
+
+void JSPropertyNameEnumerator::finishCreation(VM& vm, uint32_t indexedLength, uint32_t endStructurePropertyIndex, PassRefPtr<PropertyNameArrayData> idents)
+{
+ Base::finishCreation(vm);
+
+ RefPtr<PropertyNameArrayData> identifiers = idents;
+ PropertyNameArrayData::PropertyNameVector& vector = identifiers->propertyNameVector();
+
+ m_indexedLength = indexedLength;
+ m_endStructurePropertyIndex = endStructurePropertyIndex;
+ m_endGenericPropertyIndex = vector.size();
+
+ m_propertyNames.resizeToFit(vector.size());
+ for (unsigned i = 0; i < vector.size(); ++i) {
+ const Identifier& identifier = vector[i];
+ m_propertyNames[i].set(vm, this, jsString(&vm, identifier.string()));
+ }
+}
+
+void JSPropertyNameEnumerator::destroy(JSCell* cell)
+{
+ jsCast<JSPropertyNameEnumerator*>(cell)->JSPropertyNameEnumerator::~JSPropertyNameEnumerator();
+}
+
+void JSPropertyNameEnumerator::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ Base::visitChildren(cell, visitor);
+ JSPropertyNameEnumerator* thisObject = jsCast<JSPropertyNameEnumerator*>(cell);
+ for (unsigned i = 0; i < thisObject->m_propertyNames.size(); ++i)
+ visitor.append(&thisObject->m_propertyNames[i]);
+ visitor.append(&thisObject->m_prototypeChain);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h b/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h
new file mode 100644
index 000000000..8406c4602
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 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. 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.
+ */
+
+#ifndef JSPropertyNameEnumerator_h
+#define JSPropertyNameEnumerator_h
+
+#include "JSCell.h"
+#include "Operations.h"
+#include "PropertyNameArray.h"
+#include "Structure.h"
+
+namespace JSC {
+
+class Identifier;
+
+class JSPropertyNameEnumerator final : public JSCell {
+public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+ static JSPropertyNameEnumerator* create(VM&);
+ static JSPropertyNameEnumerator* create(VM&, Structure*, uint32_t, uint32_t, PropertyNameArray&);
+
+ static const bool needsDestruction = true;
+ static void destroy(JSCell*);
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+ }
+
+ DECLARE_EXPORT_INFO;
+
+ JSString* propertyNameAtIndex(uint32_t index) const
+ {
+ if (index >= m_propertyNames.size())
+ return nullptr;
+ return m_propertyNames[index].get();
+ }
+
+ StructureChain* cachedPrototypeChain() const { return m_prototypeChain.get(); }
+ void setCachedPrototypeChain(VM& vm, StructureChain* prototypeChain) { return m_prototypeChain.set(vm, this, prototypeChain); }
+
+ Structure* cachedStructure(VM& vm) const
+ {
+ if (!m_cachedStructureID)
+ return nullptr;
+ return vm.heap.structureIDTable().get(m_cachedStructureID);
+ }
+ StructureID cachedStructureID() const { return m_cachedStructureID; }
+ uint32_t indexedLength() const { return m_indexedLength; }
+ uint32_t endStructurePropertyIndex() const { return m_endStructurePropertyIndex; }
+ uint32_t endGenericPropertyIndex() const { return m_endGenericPropertyIndex; }
+ uint32_t cachedInlineCapacity() const { return m_cachedInlineCapacity; }
+ static ptrdiff_t cachedStructureIDOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_cachedStructureID); }
+ static ptrdiff_t indexedLengthOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_indexedLength); }
+ static ptrdiff_t endStructurePropertyIndexOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_endStructurePropertyIndex); }
+ static ptrdiff_t endGenericPropertyIndexOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_endGenericPropertyIndex); }
+ static ptrdiff_t cachedInlineCapacityOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_cachedInlineCapacity); }
+ static ptrdiff_t cachedPropertyNamesVectorOffset()
+ {
+ return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_propertyNames) + Vector<WriteBarrier<JSString>>::dataMemoryOffset();
+ }
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+private:
+ JSPropertyNameEnumerator(VM&, StructureID, uint32_t);
+ void finishCreation(VM&, uint32_t, uint32_t, PassRefPtr<PropertyNameArrayData>);
+
+ Vector<WriteBarrier<JSString>> m_propertyNames;
+ StructureID m_cachedStructureID;
+ WriteBarrier<StructureChain> m_prototypeChain;
+ uint32_t m_indexedLength;
+ uint32_t m_endStructurePropertyIndex;
+ uint32_t m_endGenericPropertyIndex;
+ uint32_t m_cachedInlineCapacity;
+};
+
+inline JSPropertyNameEnumerator* propertyNameEnumerator(ExecState* exec, JSObject* base)
+{
+ VM& vm = exec->vm();
+
+ uint32_t indexedLength = base->methodTable(vm)->getEnumerableLength(exec, base);
+
+ JSPropertyNameEnumerator* enumerator = nullptr;
+
+ Structure* structure = base->structure(vm);
+ if (!indexedLength
+ && (enumerator = structure->cachedPropertyNameEnumerator())
+ && enumerator->cachedPrototypeChain() == structure->prototypeChain(exec))
+ return enumerator;
+
+ uint32_t numberStructureProperties = 0;
+
+ PropertyNameArray propertyNames(exec, PropertyNameMode::Strings);
+
+ if (structure->canAccessPropertiesQuickly() && indexedLength == base->getArrayLength()) {
+ base->methodTable(vm)->getStructurePropertyNames(base, exec, propertyNames, EnumerationMode());
+
+ numberStructureProperties = propertyNames.size();
+
+ base->methodTable(vm)->getGenericPropertyNames(base, exec, propertyNames, EnumerationMode());
+ } else {
+ // Generic property names vector contains all indexed property names.
+ // So disable indexed property enumeration phase by setting |indexedLength| to 0.
+ indexedLength = 0;
+ base->methodTable(vm)->getPropertyNames(base, exec, propertyNames, EnumerationMode());
+ }
+
+ ASSERT(propertyNames.size() < UINT32_MAX);
+
+ normalizePrototypeChain(exec, structure);
+
+ enumerator = JSPropertyNameEnumerator::create(vm, structure, indexedLength, numberStructureProperties, propertyNames);
+ enumerator->setCachedPrototypeChain(vm, structure->prototypeChain(exec));
+ if (!indexedLength && structure->canCachePropertyNameEnumerator())
+ structure->setCachedPropertyNameEnumerator(vm, enumerator);
+ return enumerator;
+}
+
+} // namespace JSC
+
+#endif // JSPropertyNameEnumerator_h
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
index 68a8bd87d..a9749a524 100644
--- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
+++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
@@ -1,113 +1,153 @@
/*
- * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * 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.
*
- * 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.
- * 3. Neither the name of Apple Computer, 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ * 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 "JSPropertyNameIterator.h"
-#include "JSGlobalObject.h"
-#include <wtf/StdLibExtras.h>
+#include "IdentifierInlines.h"
+#include "IteratorOperations.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSPropertyNameEnumerator.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
namespace JSC {
-const ClassInfo JSPropertyNameIterator::s_info = { "JSPropertyNameIterator", 0, 0, 0, CREATE_METHOD_TABLE(JSPropertyNameIterator) };
+static EncodedJSValue JSC_HOST_CALL propertyNameIteratorFuncNext(ExecState*);
+
+const ClassInfo JSPropertyNameIterator::s_info = { "PropertyName Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(JSPropertyNameIterator) };
-inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlots)
- : JSCell(exec->vm(), exec->vm().propertyNameIteratorStructure.get())
- , m_numCacheableSlots(numCacheableSlots)
- , m_jsStringsSize(propertyNameArrayData->propertyNameVector().size())
- , m_jsStrings(m_jsStringsSize ? std::make_unique<WriteBarrier<Unknown>[]>(m_jsStringsSize) : nullptr)
+JSPropertyNameIterator::JSPropertyNameIterator(VM& vm, Structure* structure, JSObject* object, JSPropertyNameEnumerator* enumerator)
+ : Base(vm, structure)
+ , m_iteratedObject(vm, this, object)
+ , m_propertyNameEnumerator(vm, this, enumerator)
+ , m_enumerationPhase(EnumerationPhase::IndexedNames)
+ , m_cursor(0)
{
}
-JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject* o)
+JSPropertyNameIterator* JSPropertyNameIterator::clone(ExecState* exec)
{
- ASSERT(!o->structure()->enumerationCache() ||
- o->structure()->enumerationCache()->cachedStructure() != o->structure() ||
- o->structure()->enumerationCache()->cachedPrototypeChain() != o->structure()->prototypeChain(exec));
-
- VM& vm = exec->vm();
-
- PropertyNameArray propertyNames(exec);
- o->methodTable()->getPropertyNames(o, exec, propertyNames, ExcludeDontEnumProperties);
- size_t numCacheableSlots = 0;
- if (!o->structure()->hasNonEnumerableProperties() && !o->structure()->hasGetterSetterProperties()
- && !o->structure()->isUncacheableDictionary() && !o->structure()->typeInfo().overridesGetPropertyNames())
- numCacheableSlots = propertyNames.numCacheableSlots();
-
- JSPropertyNameIterator* jsPropertyNameIterator = new (NotNull, allocateCell<JSPropertyNameIterator>(vm.heap)) JSPropertyNameIterator(exec, propertyNames.data(), numCacheableSlots);
- jsPropertyNameIterator->finishCreation(vm, propertyNames.data(), o);
-
- if (o->structure()->isDictionary())
- return jsPropertyNameIterator;
-
- if (o->structure()->typeInfo().overridesGetPropertyNames())
- return jsPropertyNameIterator;
-
- if (hasIndexedProperties(o->structure()->indexingType()))
- return jsPropertyNameIterator;
-
- size_t count = normalizePrototypeChain(exec, o);
- StructureChain* structureChain = o->structure()->prototypeChain(exec);
- WriteBarrier<Structure>* structure = structureChain->head();
- for (size_t i = 0; i < count; ++i) {
- if (structure[i]->typeInfo().overridesGetPropertyNames())
- return jsPropertyNameIterator;
- }
-
- jsPropertyNameIterator->setCachedPrototypeChain(vm, structureChain);
- jsPropertyNameIterator->setCachedStructure(vm, o->structure());
- o->structure()->setEnumerationCache(vm, jsPropertyNameIterator);
- return jsPropertyNameIterator;
+ auto iterator = JSPropertyNameIterator::create(exec, exec->callee()->globalObject()->propertyNameIteratorStructure(), m_iteratedObject.get(), m_propertyNameEnumerator.get());
+ iterator->m_enumerationPhase = m_enumerationPhase;
+ iterator->m_cursor = m_cursor;
+ return iterator;
}
-void JSPropertyNameIterator::destroy(JSCell* cell)
+JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, Structure* structure, JSObject* iteratedObject)
{
- static_cast<JSPropertyNameIterator*>(cell)->JSPropertyNameIterator::~JSPropertyNameIterator();
+ return JSPropertyNameIterator::create(exec, structure, iteratedObject, propertyNameEnumerator(exec, iteratedObject));
}
-JSValue JSPropertyNameIterator::get(ExecState* exec, JSObject* base, size_t i)
+JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, Structure* structure, JSObject* iteratedObject, JSPropertyNameEnumerator* enumerator)
{
- JSValue identifier = m_jsStrings[i].get();
- if (m_cachedStructure.get() == base->structure() && m_cachedPrototypeChain.get() == base->structure()->prototypeChain(exec))
- return identifier;
+ VM& vm = exec->vm();
+ JSPropertyNameIterator* instance = new (NotNull, allocateCell<JSPropertyNameIterator>(vm.heap)) JSPropertyNameIterator(vm, structure, iteratedObject, enumerator);
+ instance->finishCreation(vm, structure->globalObject());
+ return instance;
+}
- if (!base->hasProperty(exec, Identifier(exec, asString(identifier)->value(exec))))
- return JSValue();
- return identifier;
+void JSPropertyNameIterator::finishCreation(VM& vm, JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+ JSC_NATIVE_FUNCTION(vm.propertyNames->next, propertyNameIteratorFuncNext, DontEnum, 0);
}
void JSPropertyNameIterator::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSPropertyNameIterator* thisObject = jsCast<JSPropertyNameIterator*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
- visitor.appendValues(thisObject->m_jsStrings.get(), thisObject->m_jsStringsSize);
- visitor.append(&thisObject->m_cachedPrototypeChain);
+ Base::visitChildren(thisObject, visitor);
+ visitor.append(&thisObject->m_iteratedObject);
+ visitor.append(&thisObject->m_propertyNameEnumerator);
+}
+
+bool JSPropertyNameIterator::next(ExecState* exec, JSValue& output)
+{
+ if (m_enumerationPhase == EnumerationPhase::IndexedNames) {
+ for (; m_cursor < m_propertyNameEnumerator->indexedLength();) {
+ uint32_t index = m_cursor++;
+ if (m_iteratedObject->hasProperty(exec, index)) {
+ output = jsString(exec, Identifier::from(exec, index).string());
+ return true;
+ }
+ }
+ m_cursor = 0;
+ m_enumerationPhase = EnumerationPhase::StructureNames;
+ }
+
+ if (m_enumerationPhase == EnumerationPhase::StructureNames) {
+ for (; m_cursor < m_propertyNameEnumerator->endStructurePropertyIndex();) {
+ uint32_t index = m_cursor++;
+ JSString* propertyName = m_propertyNameEnumerator->propertyNameAtIndex(index);
+ ASSERT(propertyName);
+ if (m_iteratedObject->structure(exec->vm())->id() == m_propertyNameEnumerator->cachedStructureID()) {
+ output = propertyName;
+ return true;
+ }
+
+ if (m_iteratedObject->hasProperty(exec, propertyName->toIdentifier(exec))) {
+ output = propertyName;
+ return true;
+ }
+ }
+ ASSERT(m_cursor >= m_propertyNameEnumerator->endStructurePropertyIndex());
+ // Use the same m_cursor in the GenericNames phase.
+ m_enumerationPhase = EnumerationPhase::GenericNames;
+ }
+
+ if (m_enumerationPhase == EnumerationPhase::GenericNames) {
+ for (; m_cursor < m_propertyNameEnumerator->endGenericPropertyIndex();) {
+ uint32_t index = m_cursor++;
+ JSString* propertyName = m_propertyNameEnumerator->propertyNameAtIndex(index);
+ ASSERT(propertyName);
+ if (m_iteratedObject->hasProperty(exec, propertyName->toIdentifier(exec))) {
+ output = propertyName;
+ return true;
+ }
+ }
+ m_enumerationPhase = EnumerationPhase::Done;
+ }
+
+ return false;
+}
+
+// ------------------------------ PropertyNameIterator Functions ----------------------------
+
+EncodedJSValue JSC_HOST_CALL propertyNameIteratorFuncNext(ExecState* exec)
+{
+ JSPropertyNameIterator* iterator = jsDynamicCast<JSPropertyNameIterator*>(exec->thisValue());
+ if (!iterator)
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Cannot call PropertyNameIterator.next() on a non-PropertyNameIterator object")));
+
+ JSValue result;
+ if (iterator->next(exec, result))
+ return JSValue::encode(createIteratorResultObject(exec, result, false));
+ return JSValue::encode(createIteratorResultObject(exec, jsUndefined(), true));
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
index f4362ff35..bf0dc10f3 100644
--- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
+++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
@@ -1,119 +1,76 @@
/*
- * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * 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.
*
- * 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.
- * 3. Neither the name of Apple Computer, 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ * 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 JSPropertyNameIterator_h
#define JSPropertyNameIterator_h
#include "JSObject.h"
-#include "JSString.h"
-#include "Operations.h"
-#include "PropertyNameArray.h"
-#include <memory>
+#include "JSPropertyNameEnumerator.h"
namespace JSC {
- class Identifier;
- class JSObject;
- class LLIntOffsetsExtractor;
-
- class JSPropertyNameIterator : public JSCell {
- friend class JIT;
-
- public:
- typedef JSCell Base;
-
- static JSPropertyNameIterator* create(ExecState*, JSObject*);
-
- static const bool needsDestruction = true;
- static const bool hasImmortalStructure = true;
- static void destroy(JSCell*);
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), info());
- }
-
- static void visitChildren(JSCell*, SlotVisitor&);
-
- JSValue get(ExecState*, JSObject*, size_t i);
- size_t size() { return m_jsStringsSize; }
-
- void setCachedStructure(VM& vm, Structure* structure)
- {
- ASSERT(!m_cachedStructure);
- ASSERT(structure);
- m_cachedStructure.set(vm, this, structure);
- }
- Structure* cachedStructure() { return m_cachedStructure.get(); }
-
- void setCachedPrototypeChain(VM& vm, StructureChain* cachedPrototypeChain) { m_cachedPrototypeChain.set(vm, this, cachedPrototypeChain); }
- StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); }
-
- DECLARE_EXPORT_INFO;
-
- protected:
- void finishCreation(VM& vm, PropertyNameArrayData* propertyNameArrayData, JSObject* object)
- {
- Base::finishCreation(vm);
- PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector();
- for (size_t i = 0; i < m_jsStringsSize; ++i)
- m_jsStrings[i].set(vm, this, jsOwnedString(&vm, propertyNameVector[i].string()));
- m_cachedStructureInlineCapacity = object->structure()->inlineCapacity();
- }
-
- private:
- friend class LLIntOffsetsExtractor;
-
- JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlot);
-
- WriteBarrier<Structure> m_cachedStructure;
- WriteBarrier<StructureChain> m_cachedPrototypeChain;
- uint32_t m_numCacheableSlots;
- uint32_t m_jsStringsSize;
- unsigned m_cachedStructureInlineCapacity;
- std::unique_ptr<WriteBarrier<Unknown>[]> m_jsStrings;
+class JSPropertyNameIterator : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+
+ enum class EnumerationPhase : uint32_t {
+ IndexedNames,
+ StructureNames,
+ GenericNames,
+ Done
};
- ALWAYS_INLINE JSPropertyNameIterator* Register::propertyNameIterator() const
- {
- return jsCast<JSPropertyNameIterator*>(jsValue().asCell());
- }
+ DECLARE_EXPORT_INFO;
- inline JSPropertyNameIterator* StructureRareData::enumerationCache()
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return m_enumerationCache.get();
- }
-
- inline void StructureRareData::setEnumerationCache(VM& vm, const Structure*, JSPropertyNameIterator* value)
- {
- m_enumerationCache.set(vm, this, value);
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}
-} // namespace JSC
+ static JSPropertyNameIterator* create(ExecState*, Structure*, JSObject*);
+
+ JSPropertyNameIterator* clone(ExecState*);
+ bool next(ExecState*, JSValue&);
+
+ JSValue iteratedValue() const { return m_iteratedObject.get(); }
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+private:
+ JSPropertyNameIterator(VM&, Structure*, JSObject*, JSPropertyNameEnumerator*);
+
+ void finishCreation(VM&, JSGlobalObject*);
+
+ static JSPropertyNameIterator* create(ExecState*, Structure*, JSObject*, JSPropertyNameEnumerator*);
+
+ WriteBarrier<JSObject> m_iteratedObject;
+ WriteBarrier<JSPropertyNameEnumerator> m_propertyNameEnumerator;
+ EnumerationPhase m_enumerationPhase;
+ uint32_t m_cursor;
+};
+
+}
#endif // JSPropertyNameIterator_h
diff --git a/Source/JavaScriptCore/runtime/JSProxy.cpp b/Source/JavaScriptCore/runtime/JSProxy.cpp
index ced8cc41f..f4c6829e0 100644
--- a/Source/JavaScriptCore/runtime/JSProxy.cpp
+++ b/Source/JavaScriptCore/runtime/JSProxy.cpp
@@ -27,22 +27,18 @@
#include "JSProxy.h"
#include "JSGlobalObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSProxy);
-const ClassInfo JSProxy::s_info = { "JSProxy", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSProxy) };
+const ClassInfo JSProxy::s_info = { "JSProxy", &Base::s_info, 0, CREATE_METHOD_TABLE(JSProxy) };
void JSProxy::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSProxy* thisObject = jsCast<JSProxy*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
-
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
Base::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_target);
}
@@ -73,55 +69,74 @@ String JSProxy::className(const JSObject* object)
bool JSProxy::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
JSProxy* thisObject = jsCast<JSProxy*>(object);
- return thisObject->target()->methodTable()->getOwnPropertySlot(thisObject->target(), exec, propertyName, slot);
+ return thisObject->target()->methodTable(exec->vm())->getOwnPropertySlot(thisObject->target(), exec, propertyName, slot);
}
bool JSProxy::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned propertyName, PropertySlot& slot)
{
JSProxy* thisObject = jsCast<JSProxy*>(object);
- return thisObject->target()->methodTable()->getOwnPropertySlotByIndex(thisObject->target(), exec, propertyName, slot);
+ return thisObject->target()->methodTable(exec->vm())->getOwnPropertySlotByIndex(thisObject->target(), exec, propertyName, slot);
}
void JSProxy::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
{
JSProxy* thisObject = jsCast<JSProxy*>(cell);
- thisObject->target()->methodTable()->put(thisObject->target(), exec, propertyName, value, slot);
+ thisObject->target()->methodTable(exec->vm())->put(thisObject->target(), exec, propertyName, value, slot);
}
void JSProxy::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
{
JSProxy* thisObject = jsCast<JSProxy*>(cell);
- thisObject->target()->methodTable()->putByIndex(thisObject->target(), exec, propertyName, value, shouldThrow);
+ thisObject->target()->methodTable(exec->vm())->putByIndex(thisObject->target(), exec, propertyName, value, shouldThrow);
}
bool JSProxy::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
{
JSProxy* thisObject = jsCast<JSProxy*>(object);
- return thisObject->target()->methodTable()->defineOwnProperty(thisObject->target(), exec, propertyName, descriptor, shouldThrow);
+ return thisObject->target()->methodTable(exec->vm())->defineOwnProperty(thisObject->target(), exec, propertyName, descriptor, shouldThrow);
}
bool JSProxy::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
{
JSProxy* thisObject = jsCast<JSProxy*>(cell);
- return thisObject->target()->methodTable()->deleteProperty(thisObject->target(), exec, propertyName);
+ return thisObject->target()->methodTable(exec->vm())->deleteProperty(thisObject->target(), exec, propertyName);
}
bool JSProxy::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
{
JSProxy* thisObject = jsCast<JSProxy*>(cell);
- return thisObject->target()->methodTable()->deletePropertyByIndex(thisObject->target(), exec, propertyName);
+ return thisObject->target()->methodTable(exec->vm())->deletePropertyByIndex(thisObject->target(), exec, propertyName);
}
void JSProxy::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
JSProxy* thisObject = jsCast<JSProxy*>(object);
- thisObject->target()->methodTable()->getPropertyNames(thisObject->target(), exec, propertyNames, mode);
+ thisObject->target()->methodTable(exec->vm())->getPropertyNames(thisObject->target(), exec, propertyNames, mode);
+}
+
+uint32_t JSProxy::getEnumerableLength(ExecState* exec, JSObject* object)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(object);
+ return thisObject->target()->methodTable(exec->vm())->getEnumerableLength(exec, thisObject->target());
+}
+
+void JSProxy::getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
+{
+ // Skip the structure loop, since it is invalid for proxies.
+}
+
+void JSProxy::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(object);
+ // Get *all* of the property names, not just the generic ones, since we skipped the structure
+ // ones above.
+ thisObject->target()->methodTable(exec->vm())->getPropertyNames(thisObject->target(), exec, propertyNames, mode);
}
void JSProxy::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
JSProxy* thisObject = jsCast<JSProxy*>(object);
- thisObject->target()->methodTable()->getOwnPropertyNames(thisObject->target(), exec, propertyNames, mode);
+ thisObject->target()->methodTable(exec->vm())->getOwnPropertyNames(thisObject->target(), exec, propertyNames, mode);
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSProxy.h b/Source/JavaScriptCore/runtime/JSProxy.h
index ea941a275..2bdcd1b72 100644
--- a/Source/JavaScriptCore/runtime/JSProxy.h
+++ b/Source/JavaScriptCore/runtime/JSProxy.h
@@ -33,6 +33,7 @@ namespace JSC {
class JSProxy : public JSDestructibleObject {
public:
typedef JSDestructibleObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
static JSProxy* create(VM& vm, Structure* structure, JSObject* target)
{
@@ -41,14 +42,15 @@ public:
return proxy;
}
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, JSType proxyType = ImpureProxyType)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(ProxyType, StructureFlags), info());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(proxyType, StructureFlags), info());
}
DECLARE_EXPORT_INFO;
JSObject* target() const { return m_target.get(); }
+ static ptrdiff_t targetOffset() { return OBJECT_OFFSETOF(JSProxy, m_target); }
protected:
JSProxy(VM& vm, Structure* structure)
@@ -67,8 +69,6 @@ protected:
m_target.set(vm, this, target);
}
- static const unsigned StructureFlags = OverridesVisitChildren | OverridesGetOwnPropertySlot | OverridesGetPropertyNames | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | Base::StructureFlags;
-
JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
JS_EXPORT_PRIVATE void setTarget(VM&, JSGlobalObject*);
@@ -82,6 +82,9 @@ protected:
JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned);
JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static uint32_t getEnumerableLength(ExecState*, JSObject*);
+ JS_EXPORT_PRIVATE static void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
private:
diff --git a/Source/JavaScriptCore/runtime/JSScope.cpp b/Source/JavaScriptCore/runtime/JSScope.cpp
index 3440bc610..b13f3ff4a 100644
--- a/Source/JavaScriptCore/runtime/JSScope.cpp
+++ b/Source/JavaScriptCore/runtime/JSScope.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2012-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
@@ -26,11 +26,12 @@
#include "config.h"
#include "JSScope.h"
-#include "JSActivation.h"
#include "JSGlobalObject.h"
-#include "JSNameScope.h"
+#include "JSLexicalEnvironment.h"
+#include "JSModuleEnvironment.h"
+#include "JSModuleRecord.h"
#include "JSWithScope.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
@@ -40,40 +41,77 @@ void JSScope::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSScope* thisObject = jsCast<JSScope*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
Base::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_next);
}
// Returns true if we found enough information to terminate optimization.
-static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, size_t depth, bool& needsVarInjectionChecks, ResolveOp& op)
+static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, size_t depth, bool& needsVarInjectionChecks, ResolveOp& op, InitializationMode initializationMode)
{
- if (JSActivation* activation = jsDynamicCast<JSActivation*>(scope)) {
+ if (JSLexicalEnvironment* lexicalEnvironment = jsDynamicCast<JSLexicalEnvironment*>(scope)) {
if (ident == exec->propertyNames().arguments) {
- // We know the property will be at this activation scope, but we don't know how to cache it.
+ // We know the property will be at this lexical environment scope, but we don't know how to cache it.
op = ResolveOp(Dynamic, 0, 0, 0, 0, 0);
return true;
}
- SymbolTableEntry entry = activation->symbolTable()->get(ident.impl());
+ SymbolTableEntry entry = lexicalEnvironment->symbolTable()->get(ident.impl());
if (entry.isReadOnly() && getOrPut == Put) {
- // We know the property will be at this activation scope, but we don't know how to cache it.
+ // We know the property will be at this lexical environment scope, but we don't know how to cache it.
op = ResolveOp(Dynamic, 0, 0, 0, 0, 0);
return true;
}
if (!entry.isNull()) {
- op = ResolveOp(makeType(ClosureVar, needsVarInjectionChecks), depth, 0, activation, entry.watchpointSet(), entry.getIndex());
+ op = ResolveOp(makeType(ClosureVar, needsVarInjectionChecks), depth, 0, lexicalEnvironment, entry.watchpointSet(), entry.scopeOffset().offset());
return true;
}
- if (activation->symbolTable()->usesNonStrictEval())
+ if (JSModuleEnvironment* moduleEnvironment = jsDynamicCast<JSModuleEnvironment*>(scope)) {
+ JSModuleRecord* moduleRecord = moduleEnvironment->moduleRecord();
+ JSModuleRecord::Resolution resolution = moduleRecord->resolveImport(exec, ident);
+ if (resolution.type == JSModuleRecord::Resolution::Type::Resolved) {
+ JSModuleRecord* importedRecord = resolution.moduleRecord;
+ JSModuleEnvironment* importedEnvironment = importedRecord->moduleEnvironment();
+ SymbolTableEntry entry = importedEnvironment->symbolTable()->get(resolution.localName.impl());
+ ASSERT(!entry.isNull());
+ op = ResolveOp(makeType(ModuleVar, needsVarInjectionChecks), depth, 0, importedEnvironment, entry.watchpointSet(), entry.scopeOffset().offset(), resolution.localName.impl());
+ return true;
+ }
+ }
+
+ if (lexicalEnvironment->symbolTable()->usesNonStrictEval())
needsVarInjectionChecks = true;
return false;
}
+ if (JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsDynamicCast<JSGlobalLexicalEnvironment*>(scope)) {
+ SymbolTableEntry entry = globalLexicalEnvironment->symbolTable()->get(ident.impl());
+ if (!entry.isNull()) {
+ if (getOrPut == Put && entry.isReadOnly() && initializationMode != Initialization) {
+ // We know the property will be at global lexical environment, but we don't know how to cache it.
+ op = ResolveOp(Dynamic, 0, 0, 0, 0, 0);
+ return true;
+ }
+
+ // We can try to force const Initialization to always go down the fast path. It is provably impossible to construct
+ // a program that needs a var injection check here. You can convince yourself of this as follows:
+ // Any other let/const/class would be a duplicate of this in the global scope, so we would never get here in that situation.
+ // Also, if we had an eval in the global scope that defined a const, it would also be a duplicate of this const, and so it would
+ // also throw an error. Therefore, we're *the only* thing that can assign to this "const" slot for the first (and only) time. Also,
+ // we will never have a Dynamic ResolveType here because if we were inside a "with" statement, that would mean the "const" definition
+ // isn't a global, it would be a local to the "with" block.
+ // We still need to make the slow path correct for when we need to fire a watchpoint.
+ ResolveType resolveType = initializationMode == Initialization ? GlobalLexicalVar : makeType(GlobalLexicalVar, needsVarInjectionChecks);
+ op = ResolveOp(
+ resolveType, depth, 0, 0, entry.watchpointSet(),
+ reinterpret_cast<uintptr_t>(globalLexicalEnvironment->variableAt(entry.scopeOffset()).slot()));
+ return true;
+ }
+
+ return false;
+ }
+
if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(scope)) {
SymbolTableEntry entry = globalObject->symbolTable()->get(ident.impl());
if (!entry.isNull()) {
@@ -85,22 +123,39 @@ static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identif
op = ResolveOp(
makeType(GlobalVar, needsVarInjectionChecks), depth, 0, 0, entry.watchpointSet(),
- reinterpret_cast<uintptr_t>(globalObject->registerAt(entry.getIndex()).slot()));
+ reinterpret_cast<uintptr_t>(globalObject->variableAt(entry.scopeOffset()).slot()));
return true;
}
- PropertySlot slot(globalObject);
- if (!globalObject->getOwnPropertySlot(globalObject, exec, ident, slot)
- || !slot.isCacheableValue()
+ PropertySlot slot(globalObject, PropertySlot::InternalMethodType::VMInquiry);
+ bool hasOwnProperty = globalObject->getOwnPropertySlot(globalObject, exec, ident, slot);
+ if (!hasOwnProperty) {
+ op = ResolveOp(makeType(UnresolvedProperty, needsVarInjectionChecks), 0, 0, 0, 0, 0);
+ return true;
+ }
+
+ if (!slot.isCacheableValue()
|| !globalObject->structure()->propertyAccessesAreCacheable()
|| (globalObject->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto() && getOrPut == Put)) {
// We know the property will be at global scope, but we don't know how to cache it.
ASSERT(!scope->next());
- op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, 0, 0, 0, 0);
+ op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), 0, 0, 0, 0, 0);
return true;
}
- op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, globalObject->structure(), 0, 0, slot.cachedOffset());
+
+ WatchpointState state = globalObject->structure()->ensurePropertyReplacementWatchpointSet(exec->vm(), slot.cachedOffset())->state();
+ if (state == IsWatched && getOrPut == Put) {
+ // The field exists, but because the replacement watchpoint is still intact. This is
+ // kind of dangerous. We have two options:
+ // 1) Invalidate the watchpoint set. That would work, but it's possible that this code
+ // path never executes - in which case this would be unwise.
+ // 2) Have the invalidation happen at run-time. All we have to do is leave the code
+ // uncached. The only downside is slightly more work when this does execute.
+ // We go with option (2) here because it seems less evil.
+ op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, 0, 0, 0, 0);
+ } else
+ op = ResolveOp(makeType(GlobalProperty, needsVarInjectionChecks), depth, globalObject->structure(), 0, 0, slot.cachedOffset());
return true;
}
@@ -111,18 +166,28 @@ static inline bool abstractAccess(ExecState* exec, JSScope* scope, const Identif
JSObject* JSScope::objectAtScope(JSScope* scope)
{
JSObject* object = scope;
- if (object->structure()->typeInfo().type() == WithScopeType)
+ if (object->type() == WithScopeType)
return jsCast<JSWithScope*>(object)->object();
return object;
}
-int JSScope::depth()
+// When an exception occurs, the result of isUnscopable becomes false.
+static inline bool isUnscopable(ExecState* exec, JSScope* scope, JSObject* object, const Identifier& ident)
{
- int depth = 0;
- for (JSScope* scope = this; scope; scope = scope->next())
- ++depth;
- return depth;
+ if (scope->type() != WithScopeType)
+ return false;
+
+ JSValue unscopables = object->get(exec, exec->propertyNames().unscopablesSymbol);
+ if (exec->hadException())
+ return false;
+ if (!unscopables.isObject())
+ return false;
+ JSValue blocked = jsCast<JSObject*>(unscopables)->get(exec, ident);
+ if (exec->hadException())
+ return false;
+
+ return blocked.toBoolean(exec);
}
JSValue JSScope::resolve(ExecState* exec, JSScope* scope, const Identifier& ident)
@@ -130,26 +195,30 @@ JSValue JSScope::resolve(ExecState* exec, JSScope* scope, const Identifier& iden
ScopeChainIterator end = scope->end();
ScopeChainIterator it = scope->begin();
while (1) {
+ JSScope* scope = it.scope();
JSObject* object = it.get();
if (++it == end) // Global scope.
return object;
- if (object->hasProperty(exec, ident))
- return object;
+ if (object->hasProperty(exec, ident)) {
+ if (!isUnscopable(exec, scope, object, ident))
+ return object;
+ ASSERT_WITH_MESSAGE(!exec->hadException(), "When an exception occurs, the result of isUnscopable becomes false");
+ }
}
}
-ResolveOp JSScope::abstractResolve(ExecState* exec, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, ResolveType unlinkedType)
+ResolveOp JSScope::abstractResolve(ExecState* exec, size_t depthOffset, JSScope* scope, const Identifier& ident, GetOrPut getOrPut, ResolveType unlinkedType, InitializationMode initializationMode)
{
ResolveOp op(Dynamic, 0, 0, 0, 0, 0);
if (unlinkedType == Dynamic)
return op;
- size_t depth = 0;
bool needsVarInjectionChecks = JSC::needsVarInjectionChecks(unlinkedType);
+ size_t depth = depthOffset;
for (; scope; scope = scope->next()) {
- if (abstractAccess(exec, scope, ident, getOrPut, depth, needsVarInjectionChecks, op))
+ if (abstractAccess(exec, scope, ident, getOrPut, depth, needsVarInjectionChecks, op, initializationMode))
break;
++depth;
}
@@ -157,4 +226,90 @@ ResolveOp JSScope::abstractResolve(ExecState* exec, JSScope* scope, const Identi
return op;
}
+void JSScope::collectVariablesUnderTDZ(JSScope* scope, VariableEnvironment& result)
+{
+ for (; scope; scope = scope->next()) {
+ if (!scope->isLexicalScope() && !scope->isGlobalLexicalEnvironment())
+ continue;
+
+ if (scope->isModuleScope()) {
+ JSModuleRecord* moduleRecord = jsCast<JSModuleEnvironment*>(scope)->moduleRecord();
+ for (const auto& pair : moduleRecord->importEntries())
+ result.add(pair.key);
+ }
+
+ SymbolTable* symbolTable = jsCast<JSSymbolTableObject*>(scope)->symbolTable();
+ ASSERT(symbolTable->scopeType() == SymbolTable::ScopeType::LexicalScope || symbolTable->scopeType() == SymbolTable::ScopeType::GlobalLexicalScope);
+ ConcurrentJITLocker locker(symbolTable->m_lock);
+ for (auto end = symbolTable->end(locker), iter = symbolTable->begin(locker); iter != end; ++iter)
+ result.add(iter->key);
+ }
+}
+
+template <typename EnvironmentType, SymbolTable::ScopeType scopeType>
+inline static bool isScopeType(JSScope* scope)
+{
+ EnvironmentType* environment = jsDynamicCast<EnvironmentType*>(scope);
+ if (!environment)
+ return false;
+
+ return environment->symbolTable()->scopeType() == scopeType;
+}
+
+bool JSScope::isVarScope()
+{
+ return isScopeType<JSLexicalEnvironment, SymbolTable::ScopeType::VarScope>(this);
+}
+
+bool JSScope::isLexicalScope()
+{
+ return isScopeType<JSLexicalEnvironment, SymbolTable::ScopeType::LexicalScope>(this);
+}
+
+bool JSScope::isModuleScope()
+{
+ return isScopeType<JSModuleEnvironment, SymbolTable::ScopeType::LexicalScope>(this);
+}
+
+bool JSScope::isCatchScope()
+{
+ return isScopeType<JSLexicalEnvironment, SymbolTable::ScopeType::CatchScope>(this);
+}
+
+bool JSScope::isFunctionNameScopeObject()
+{
+ return isScopeType<JSLexicalEnvironment, SymbolTable::ScopeType::FunctionNameScope>(this);
+}
+
+bool JSScope::isGlobalLexicalEnvironment()
+{
+ return isScopeType<JSGlobalLexicalEnvironment, SymbolTable::ScopeType::GlobalLexicalScope>(this);
+}
+
+bool JSScope::isNestedLexicalScope()
+{
+ if (JSLexicalEnvironment* environment = jsDynamicCast<JSLexicalEnvironment*>(this))
+ return environment->symbolTable()->isNestedLexicalScope();
+ return false;
+}
+
+JSScope* JSScope::constantScopeForCodeBlock(ResolveType type, CodeBlock* codeBlock)
+{
+ switch (type) {
+ case GlobalProperty:
+ case GlobalVar:
+ case GlobalPropertyWithVarInjectionChecks:
+ case GlobalVarWithVarInjectionChecks:
+ return codeBlock->globalObject();
+ case GlobalLexicalVarWithVarInjectionChecks:
+ case GlobalLexicalVar:
+ return codeBlock->globalObject()->globalLexicalEnvironment();
+ default:
+ return nullptr;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSScope.h b/Source/JavaScriptCore/runtime/JSScope.h
index 3f62a45ac..4b17972c2 100644
--- a/Source/JavaScriptCore/runtime/JSScope.h
+++ b/Source/JavaScriptCore/runtime/JSScope.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2012-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
@@ -26,138 +26,47 @@
#ifndef JSScope_h
#define JSScope_h
+#include "GetPutInfo.h"
#include "JSObject.h"
+#include "VariableEnvironment.h"
namespace JSC {
class ScopeChainIterator;
-class VariableWatchpointSet;
-
-enum ResolveMode {
- ThrowIfNotFound,
- DoNotThrowIfNotFound
-};
-
-enum ResolveType {
- // Lexical scope guaranteed a certain type of variable access.
- GlobalProperty,
- GlobalVar,
- ClosureVar,
-
- // Ditto, but at least one intervening scope used non-strict eval, which
- // can inject an intercepting var delcaration at runtime.
- GlobalPropertyWithVarInjectionChecks,
- GlobalVarWithVarInjectionChecks,
- ClosureVarWithVarInjectionChecks,
-
- // Lexical scope didn't prove anything -- probably because of a 'with' scope.
- Dynamic
-};
-
-inline ResolveType makeType(ResolveType type, bool needsVarInjectionChecks)
-{
- if (!needsVarInjectionChecks)
- return type;
-
- switch (type) {
- case GlobalProperty:
- return GlobalPropertyWithVarInjectionChecks;
- case GlobalVar:
- return GlobalVarWithVarInjectionChecks;
- case ClosureVar:
- return ClosureVarWithVarInjectionChecks;
- case GlobalPropertyWithVarInjectionChecks:
- case GlobalVarWithVarInjectionChecks:
- case ClosureVarWithVarInjectionChecks:
- case Dynamic:
- return type;
- }
-
- RELEASE_ASSERT_NOT_REACHED();
- return type;
-}
-
-inline bool needsVarInjectionChecks(ResolveType type)
-{
- switch (type) {
- case GlobalProperty:
- case GlobalVar:
- case ClosureVar:
- return false;
- case GlobalPropertyWithVarInjectionChecks:
- case GlobalVarWithVarInjectionChecks:
- case ClosureVarWithVarInjectionChecks:
- case Dynamic:
- return true;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- return true;
- }
-}
-
-struct ResolveOp {
- ResolveOp(ResolveType type, size_t depth, Structure* structure, JSActivation* activation, VariableWatchpointSet* watchpointSet, uintptr_t operand)
- : type(type)
- , depth(depth)
- , structure(structure)
- , activation(activation)
- , watchpointSet(watchpointSet)
- , operand(operand)
- {
- }
-
- ResolveType type;
- size_t depth;
- Structure* structure;
- JSActivation* activation;
- VariableWatchpointSet* watchpointSet;
- uintptr_t operand;
-};
-
-class ResolveModeAndType {
- typedef unsigned Operand;
-public:
- static const size_t shift = sizeof(Operand) * 8 / 2;
- static const unsigned mask = (1 << shift) - 1;
-
- ResolveModeAndType(ResolveMode resolveMode, ResolveType resolveType)
- : m_operand((resolveMode << shift) | resolveType)
- {
- }
-
- explicit ResolveModeAndType(unsigned operand)
- : m_operand(operand)
- {
- }
-
- ResolveMode mode() { return static_cast<ResolveMode>(m_operand >> shift); }
- ResolveType type() { return static_cast<ResolveType>(m_operand & mask); }
- unsigned operand() { return m_operand; }
-
-private:
- Operand m_operand;
-};
-
-enum GetOrPut { Get, Put };
+class WatchpointSet;
class JSScope : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags;
friend class LLIntOffsetsExtractor;
static size_t offsetOfNext();
- JS_EXPORT_PRIVATE static JSObject* objectAtScope(JSScope*);
+ static JSObject* objectAtScope(JSScope*);
static JSValue resolve(ExecState*, JSScope*, const Identifier&);
- static ResolveOp abstractResolve(ExecState*, JSScope*, const Identifier&, GetOrPut, ResolveType);
+ static ResolveOp abstractResolve(ExecState*, size_t depthOffset, JSScope*, const Identifier&, GetOrPut, ResolveType, InitializationMode);
+
+ static bool hasConstantScope(ResolveType);
+ static JSScope* constantScopeForCodeBlock(ResolveType, CodeBlock*);
+
+ static void collectVariablesUnderTDZ(JSScope*, VariableEnvironment& result);
static void visitChildren(JSCell*, SlotVisitor&);
+ bool isVarScope();
+ bool isLexicalScope();
+ bool isModuleScope();
+ bool isGlobalLexicalEnvironment();
+ bool isCatchScope();
+ bool isFunctionNameScopeObject();
+
+ bool isNestedLexicalScope();
+
ScopeChainIterator begin();
ScopeChainIterator end();
JSScope* next();
- int depth();
JSGlobalObject* globalObject();
VM* vm();
@@ -165,7 +74,6 @@ public:
protected:
JSScope(VM&, Structure*, JSScope* next);
- static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
private:
WriteBarrier<JSScope> m_next;
@@ -186,6 +94,7 @@ public:
JSObject* get() const { return JSScope::objectAtScope(m_node); }
JSObject* operator->() const { return JSScope::objectAtScope(m_node); }
+ JSScope* scope() const { return m_node; }
ScopeChainIterator& operator++() { m_node = m_node->next(); return *this; }
@@ -234,20 +143,9 @@ inline JSScope* Register::scope() const
return jsCast<JSScope*>(jsValue());
}
-inline VM& ExecState::vm() const
-{
- ASSERT(scope()->vm());
- return *scope()->vm();
-}
-
inline JSGlobalObject* ExecState::lexicalGlobalObject() const
{
- return scope()->globalObject();
-}
-
-inline JSObject* ExecState::globalThisValue() const
-{
- return scope()->globalThis();
+ return callee()->globalObject();
}
inline size_t JSScope::offsetOfNext()
diff --git a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp
index fedb8711b..15f19f55b 100644
--- a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 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
@@ -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.
*
@@ -29,48 +29,44 @@
#include "config.h"
#include "JSSegmentedVariableObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
-int JSSegmentedVariableObject::findRegisterIndex(void* registerAddress)
+ScopeOffset JSSegmentedVariableObject::findVariableIndex(void* variableAddress)
{
ConcurrentJITLocker locker(m_lock);
- for (int i = m_registers.size(); i--;) {
- if (&m_registers[i] != registerAddress)
+ for (unsigned i = m_variables.size(); i--;) {
+ if (&m_variables[i] != variableAddress)
continue;
- return i;
+ return ScopeOffset(i);
}
CRASH();
- return -1;
+ return ScopeOffset();
}
-int JSSegmentedVariableObject::addRegisters(int numberOfRegistersToAdd)
+ScopeOffset JSSegmentedVariableObject::addVariables(unsigned numberOfVariablesToAdd, JSValue initialValue)
{
ConcurrentJITLocker locker(m_lock);
- ASSERT(numberOfRegistersToAdd >= 0);
+ size_t oldSize = m_variables.size();
+ m_variables.grow(oldSize + numberOfVariablesToAdd);
- size_t oldSize = m_registers.size();
- m_registers.grow(oldSize + numberOfRegistersToAdd);
+ for (size_t i = numberOfVariablesToAdd; i--;)
+ m_variables[oldSize + i].setWithoutWriteBarrier(initialValue);
- for (size_t i = numberOfRegistersToAdd; i--;)
- m_registers[oldSize + i].setWithoutWriteBarrier(jsUndefined());
-
- return static_cast<int>(oldSize);
+ return ScopeOffset(oldSize);
}
void JSSegmentedVariableObject::visitChildren(JSCell* cell, SlotVisitor& slotVisitor)
{
JSSegmentedVariableObject* thisObject = jsCast<JSSegmentedVariableObject*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
JSSymbolTableObject::visitChildren(thisObject, slotVisitor);
- for (unsigned i = thisObject->m_registers.size(); i--;)
- slotVisitor.append(&thisObject->m_registers[i]);
+ for (unsigned i = thisObject->m_variables.size(); i--;)
+ slotVisitor.append(&thisObject->m_variables[i]);
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h
index 70f877f3e..476c288f1 100644
--- a/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h
+++ b/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 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
@@ -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.
*
@@ -41,11 +41,11 @@ namespace JSC {
class LLIntOffsetsExtractor;
class Register;
-// This is a mostly drop-in replacement for JSVariableObject, except that it preserves
+// This is a mostly drop-in replacement for JSEnvironmentRecord, except that it preserves
// the invariant that after a variable is created, its address in memory will not change
// so long as the JSSegmentedVariableObject is alive. This allows optimizations based
// on getting the address of the variable and remembering it. As well, unlike a
-// JSVariableObject, this will manage the memory for the registers itself and neither
+// JSEnvironmentRecord, this will manage the memory for the registers itself and neither
// requires nor allows for the subclasses to manage that memory. Finally,
// JSSegmentedVariableObject has its own GC tracing functionality, since it knows the
// exact dimensions of the variables array at all times.
@@ -57,30 +57,36 @@ class JSSegmentedVariableObject : public JSSymbolTableObject {
public:
typedef JSSymbolTableObject Base;
- WriteBarrier<Unknown>& registerAt(int index) { return m_registers[index]; }
+ bool isValidScopeOffset(ScopeOffset offset)
+ {
+ return !!offset && offset.offset() < m_variables.size();
+ }
+
+ // This is not thread-safe, since m_variables is a segmented vector, and its spine can resize with
+ // malloc/free if new variables - unrelated to the one you are accessing - are added. You can get
+ // around this by grabbing m_lock, or finding some other way to get to the variable pointer (global
+ // variable access bytecode instructions will have a direct pointer already).
+ WriteBarrier<Unknown>& variableAt(ScopeOffset offset) { return m_variables[offset.offset()]; }
// This is a slow method call, which searches the register bank to find the index
// given a pointer. It will CRASH() if it does not find the register. Only use this
// in debug code (like bytecode dumping).
- JS_EXPORT_PRIVATE int findRegisterIndex(void*);
+ JS_EXPORT_PRIVATE ScopeOffset findVariableIndex(void*);
- WriteBarrier<Unknown>* assertRegisterIsInThisObject(WriteBarrier<Unknown>* registerPointer)
+ WriteBarrier<Unknown>* assertVariableIsInThisObject(WriteBarrier<Unknown>* variablePointer)
{
-#if !ASSERT_DISABLED
- findRegisterIndex(registerPointer);
-#endif
- return registerPointer;
+ if (!ASSERT_DISABLED)
+ findVariableIndex(variablePointer);
+ return variablePointer;
}
// Adds numberOfRegistersToAdd registers, initializes them to Undefined, and returns
// the index of the first one added.
- JS_EXPORT_PRIVATE int addRegisters(int numberOfRegistersToAdd);
+ JS_EXPORT_PRIVATE ScopeOffset addVariables(unsigned numberOfVariablesToAdd, JSValue);
JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
protected:
- static const unsigned StructureFlags = OverridesVisitChildren | JSSymbolTableObject::StructureFlags;
-
JSSegmentedVariableObject(VM& vm, Structure* structure, JSScope* scope)
: JSSymbolTableObject(vm, structure, scope)
{
@@ -89,9 +95,10 @@ protected:
void finishCreation(VM& vm)
{
Base::finishCreation(vm);
+ setSymbolTable(vm, SymbolTable::create(vm));
}
- SegmentedVector<WriteBarrier<Unknown>, 16> m_registers;
+ SegmentedVector<WriteBarrier<Unknown>, 16> m_variables;
ConcurrentJITLock m_lock;
};
diff --git a/Source/JavaScriptCore/runtime/JSSet.cpp b/Source/JavaScriptCore/runtime/JSSet.cpp
index fdb6df548..46aaf3841 100644
--- a/Source/JavaScriptCore/runtime/JSSet.cpp
+++ b/Source/JavaScriptCore/runtime/JSSet.cpp
@@ -26,25 +26,65 @@
#include "config.h"
#include "JSSet.h"
+#include "CopiedBlockInlines.h"
#include "JSCJSValueInlines.h"
-#include "MapData.h"
+#include "JSSetIterator.h"
+#include "MapDataInlines.h"
#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
namespace JSC {
-const ClassInfo JSSet::s_info = { "Set", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSSet) };
+const ClassInfo JSSet::s_info = { "Set", &Base::s_info, 0, CREATE_METHOD_TABLE(JSSet) };
+
+void JSSet::destroy(JSCell* cell)
+{
+ JSSet* thisObject = jsCast<JSSet*>(cell);
+ thisObject->JSSet::~JSSet();
+}
+
+size_t JSSet::estimatedSize(JSCell* cell)
+{
+ JSSet* thisObject = jsCast<JSSet*>(cell);
+ size_t setDataSize = thisObject->m_setData.capacityInBytes();
+ return Base::estimatedSize(cell) + setDataSize;
+}
void JSSet::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
Base::visitChildren(cell, visitor);
- JSSet* thisObject = jsCast<JSSet*>(cell);
- visitor.append(&thisObject->m_mapData);
+ jsCast<JSSet*>(cell)->m_setData.visitChildren(cell, visitor);
+}
+
+void JSSet::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token)
+{
+ Base::copyBackingStore(cell, visitor, token);
+ jsCast<JSSet*>(cell)->m_setData.copyBackingStore(visitor, token);
+}
+
+bool JSSet::has(ExecState* exec, JSValue value)
+{
+ return m_setData.contains(exec, value);
+}
+
+size_t JSSet::size(ExecState* exec)
+{
+ return m_setData.size(exec);
+}
+
+void JSSet::add(ExecState* exec, JSValue value)
+{
+ m_setData.set(exec, this, value, value);
+}
+
+void JSSet::clear(ExecState*)
+{
+ m_setData.clear();
}
-void JSSet::finishCreation(VM& vm)
+bool JSSet::remove(ExecState* exec, JSValue value)
{
- Base::finishCreation(vm);
- m_mapData.set(vm, this, MapData::create(vm));
+ return m_setData.remove(exec, value);
}
}
diff --git a/Source/JavaScriptCore/runtime/JSSet.h b/Source/JavaScriptCore/runtime/JSSet.h
index 22c5d860b..c4d4b385e 100644
--- a/Source/JavaScriptCore/runtime/JSSet.h
+++ b/Source/JavaScriptCore/runtime/JSSet.h
@@ -26,15 +26,63 @@
#ifndef JSSet_h
#define JSSet_h
+#include "JSDestructibleObject.h"
#include "JSObject.h"
+#include "MapData.h"
namespace JSC {
-class MapData;
+class JSSetIterator;
-class JSSet : public JSNonFinalObject {
+class JSSet : public JSDestructibleObject {
public:
- typedef JSNonFinalObject Base;
+ typedef JSDestructibleObject Base;
+
+ friend class JSSetIterator;
+
+ // Our marking functions expect Entry to maintain this layout, and have all
+ // fields be WriteBarrier<Unknown>
+ class Entry {
+ private:
+ WriteBarrier<Unknown> m_key;
+
+ public:
+ const WriteBarrier<Unknown>& key() const
+ {
+ return m_key;
+ }
+
+ const WriteBarrier<Unknown>& value() const
+ {
+ return m_key;
+ }
+
+ void visitChildren(SlotVisitor& visitor)
+ {
+ visitor.append(&m_key);
+ }
+
+ void setKey(VM& vm, const JSCell* owner, JSValue key)
+ {
+ m_key.set(vm, owner, key);
+ }
+
+ void setKeyWithoutWriteBarrier(JSValue key)
+ {
+ m_key.setWithoutWriteBarrier(key);
+ }
+
+ void setValue(VM&, const JSCell*, JSValue)
+ {
+ }
+
+ void clear()
+ {
+ m_key.clear();
+ }
+ };
+
+ typedef MapDataImpl<Entry, JSSetIterator> SetData;
DECLARE_EXPORT_INFO;
@@ -55,22 +103,25 @@ public:
return create(exec->vm(), structure);
}
- MapData* mapData() { return m_mapData.get(); }
+ bool has(ExecState*, JSValue);
+ size_t size(ExecState*);
+ JS_EXPORT_PRIVATE void add(ExecState*, JSValue);
+ void clear(ExecState*);
+ bool remove(ExecState*, JSValue);
private:
-
- static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
-
JSSet(VM& vm, Structure* structure)
: Base(vm, structure)
+ , m_setData(vm, this)
{
}
- JS_EXPORT_PRIVATE void finishCreation(VM&);
-
+ static void destroy(JSCell*);
+ static size_t estimatedSize(JSCell*);
static void visitChildren(JSCell*, SlotVisitor&);
-
- WriteBarrier<MapData> m_mapData;
+ static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
+
+ SetData m_setData;
};
}
diff --git a/Source/JavaScriptCore/runtime/JSSetIterator.cpp b/Source/JavaScriptCore/runtime/JSSetIterator.cpp
index b1d8a6512..634c2ace1 100644
--- a/Source/JavaScriptCore/runtime/JSSetIterator.cpp
+++ b/Source/JavaScriptCore/runtime/JSSetIterator.cpp
@@ -29,27 +29,26 @@
#include "JSCJSValueInlines.h"
#include "JSCellInlines.h"
#include "JSSet.h"
+#include "MapDataInlines.h"
#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
namespace JSC {
-const ClassInfo JSSetIterator::s_info = { "Set Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSSetIterator) };
+const ClassInfo JSSetIterator::s_info = { "Set Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(JSSetIterator) };
void JSSetIterator::finishCreation(VM& vm, JSSet* iteratedObject)
{
Base::finishCreation(vm);
- m_iteratedObjectData.set(vm, this, iteratedObject->mapData());
+ m_set.set(vm, this, iteratedObject);
}
void JSSetIterator::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSSetIterator* thisObject = jsCast<JSSetIterator*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
Base::visitChildren(thisObject, visitor);
- visitor.append(&thisObject->m_iteratedObjectData);
+ visitor.append(&thisObject->m_set);
}
JSValue JSSetIterator::createPair(CallFrame* callFrame, JSValue key, JSValue value)
@@ -61,4 +60,11 @@ JSValue JSSetIterator::createPair(CallFrame* callFrame, JSValue key, JSValue val
return constructArray(callFrame, 0, globalObject, args);
}
+JSSetIterator* JSSetIterator::clone(ExecState* exec)
+{
+ auto clone = JSSetIterator::create(exec->vm(), exec->callee()->globalObject()->setIteratorStructure(), m_set.get(), m_kind);
+ clone->m_iterator = m_iterator;
+ return clone;
+}
+
}
diff --git a/Source/JavaScriptCore/runtime/JSSetIterator.h b/Source/JavaScriptCore/runtime/JSSetIterator.h
index edf3bfbf9..b9121de75 100644
--- a/Source/JavaScriptCore/runtime/JSSetIterator.h
+++ b/Source/JavaScriptCore/runtime/JSSetIterator.h
@@ -26,7 +26,7 @@
#ifndef JSSetIterator_h
#define JSSetIterator_h
-#include "JSDestructibleObject.h"
+#include "JSObject.h"
#include "JSSet.h"
#include "MapData.h"
@@ -38,9 +38,9 @@ enum SetIterationKind : uint32_t {
SetIterateKeyValue,
};
-class JSSetIterator : public JSDestructibleObject {
+class JSSetIterator : public JSNonFinalObject {
public:
- typedef JSDestructibleObject Base;
+ typedef JSNonFinalObject Base;
DECLARE_EXPORT_INFO;
@@ -58,13 +58,13 @@ public:
bool next(CallFrame* callFrame, JSValue& value)
{
- if (!m_iterator.ensureSlot())
+ WTF::KeyValuePair<JSValue, JSValue> pair;
+ if (!m_iterator.next(pair))
return false;
if (m_kind == SetIterateValue || m_kind == SetIterateKey)
- value = m_iterator.key();
+ value = pair.key;
else
- value = createPair(callFrame, m_iterator.key(), m_iterator.key());
- ++m_iterator;
+ value = createPair(callFrame, pair.key, pair.key);
return true;
}
@@ -73,25 +73,32 @@ public:
m_iterator.finish();
}
-private:
+ SetIterationKind kind() const { return m_kind; }
+ JSValue iteratedValue() const { return m_set.get(); }
+ JSSetIterator* clone(ExecState*);
- static const unsigned StructureFlags = Base::StructureFlags | OverridesVisitChildren;
+ JSSet::SetData::IteratorData* iteratorData()
+ {
+ return &m_iterator;
+ }
+private:
JSSetIterator(VM& vm, Structure* structure, JSSet* iteratedObject, SetIterationKind kind)
: Base(vm, structure)
- , m_iterator(iteratedObject->mapData()->begin())
+ , m_iterator(iteratedObject->m_setData.createIteratorData(this))
, m_kind(kind)
{
}
- void finishCreation(VM&, JSSet*);
- JSValue createPair(CallFrame*, JSValue, JSValue);
+ JS_EXPORT_PRIVATE void finishCreation(VM&, JSSet*);
+ JS_EXPORT_PRIVATE JSValue createPair(CallFrame*, JSValue, JSValue);
static void visitChildren(JSCell*, SlotVisitor&);
- WriteBarrier<MapData> m_iteratedObjectData;
- MapData::const_iterator m_iterator;
+ WriteBarrier<JSSet> m_set;
+ JSSet::SetData::IteratorData m_iterator;
SetIterationKind m_kind;
};
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSSetIterator);
}
diff --git a/Source/JavaScriptCore/runtime/JSString.cpp b/Source/JavaScriptCore/runtime/JSString.cpp
index 3e4e3ffa1..ad8a67a45 100644
--- a/Source/JavaScriptCore/runtime/JSString.cpp
+++ b/Source/JavaScriptCore/runtime/JSString.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2007, 2008, 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 Library General Public
@@ -26,13 +26,19 @@
#include "JSGlobalObject.h"
#include "JSGlobalObjectFunctions.h"
#include "JSObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "StringObject.h"
#include "StringPrototype.h"
+#include "StrongInlines.h"
namespace JSC {
-const ClassInfo JSString::s_info = { "string", 0, 0, 0, CREATE_METHOD_TABLE(JSString) };
+const ClassInfo JSString::s_info = { "string", 0, 0, CREATE_METHOD_TABLE(JSString) };
+
+Structure* JSString::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+{
+ return Structure::create(vm, globalObject, proto, TypeInfo(StringType, StructureFlags), info());
+}
void JSRopeString::RopeBuilder::expand()
{
@@ -50,98 +56,226 @@ void JSString::destroy(JSCell* cell)
thisObject->JSString::~JSString();
}
-void JSString::visitChildren(JSCell* cell, SlotVisitor& visitor)
+void JSString::dumpToStream(const JSCell* cell, PrintStream& out)
{
- JSString* thisObject = jsCast<JSString*>(cell);
- Base::visitChildren(thisObject, visitor);
-
- MARK_LOG_MESSAGE1("[%u]: ", thisObject->length());
-
-#if ENABLE(OBJECT_MARK_LOGGING)
- if (!thisObject->isRope()) {
+ const JSString* thisObject = jsCast<const JSString*>(cell);
+ out.printf("<%p, %s, [%u], ", thisObject, thisObject->className(), thisObject->length());
+ if (thisObject->isRope())
+ out.printf("[rope]");
+ else {
WTF::StringImpl* ourImpl = thisObject->m_value.impl();
if (ourImpl->is8Bit())
- MARK_LOG_MESSAGE1("[8 %p]", ourImpl->characters8());
+ out.printf("[8 %p]", ourImpl->characters8());
else
- MARK_LOG_MESSAGE1("[16 %p]", ourImpl->characters16());
- } else
- MARK_LOG_MESSAGE0("[rope]: ");
-#endif
+ out.printf("[16 %p]", ourImpl->characters16());
+ }
+ out.printf(">");
+}
+
+size_t JSString::estimatedSize(JSCell* cell)
+{
+ JSString* thisObject = jsCast<JSString*>(cell);
+ if (thisObject->isRope())
+ return Base::estimatedSize(cell);
+ return Base::estimatedSize(cell) + thisObject->m_value.impl()->costDuringGC();
+}
+void JSString::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSString* thisObject = jsCast<JSString*>(cell);
+ Base::visitChildren(thisObject, visitor);
+
if (thisObject->isRope())
static_cast<JSRopeString*>(thisObject)->visitFibers(visitor);
else {
StringImpl* impl = thisObject->m_value.impl();
ASSERT(impl);
- visitor.reportExtraMemoryUsage(thisObject, impl->costDuringGC());
+ visitor.reportExtraMemoryVisited(impl->costDuringGC());
}
}
void JSRopeString::visitFibers(SlotVisitor& visitor)
{
- for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i)
- visitor.append(&m_fibers[i]);
+ if (isSubstring()) {
+ visitor.append(&substringBase());
+ return;
+ }
+ for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i)
+ visitor.append(&fiber(i));
+}
+
+static const unsigned maxLengthForOnStackResolve = 2048;
+
+void JSRopeString::resolveRopeInternal8(LChar* buffer) const
+{
+ if (isSubstring()) {
+ StringImpl::copyChars(
+ buffer, substringBase()->m_value.characters8() + substringOffset(), m_length);
+ return;
+ }
+
+ resolveRopeInternal8NoSubstring(buffer);
+}
+
+void JSRopeString::resolveRopeInternal8NoSubstring(LChar* buffer) const
+{
+ for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) {
+ if (fiber(i)->isRope()) {
+ resolveRopeSlowCase8(buffer);
+ return;
+ }
+ }
+
+ LChar* position = buffer;
+ for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) {
+ const StringImpl& fiberString = *fiber(i)->m_value.impl();
+ unsigned length = fiberString.length();
+ StringImpl::copyChars(position, fiberString.characters8(), length);
+ position += length;
+ }
+ ASSERT((buffer + m_length) == position);
+}
+
+void JSRopeString::resolveRopeInternal16(UChar* buffer) const
+{
+ if (isSubstring()) {
+ StringImpl::copyChars(
+ buffer, substringBase()->m_value.characters16() + substringOffset(), m_length);
+ return;
+ }
+
+ resolveRopeInternal16NoSubstring(buffer);
+}
+
+void JSRopeString::resolveRopeInternal16NoSubstring(UChar* buffer) const
+{
+ for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) {
+ if (fiber(i)->isRope()) {
+ resolveRopeSlowCase(buffer);
+ return;
+ }
+ }
+
+ UChar* position = buffer;
+ for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i) {
+ const StringImpl& fiberString = *fiber(i)->m_value.impl();
+ unsigned length = fiberString.length();
+ if (fiberString.is8Bit())
+ StringImpl::copyChars(position, fiberString.characters8(), length);
+ else
+ StringImpl::copyChars(position, fiberString.characters16(), length);
+ position += length;
+ }
+ ASSERT((buffer + m_length) == position);
+}
+
+void JSRopeString::resolveRopeToAtomicString(ExecState* exec) const
+{
+ if (m_length > maxLengthForOnStackResolve) {
+ resolveRope(exec);
+ m_value = AtomicString(m_value);
+ setIs8Bit(m_value.impl()->is8Bit());
+ return;
+ }
+
+ if (is8Bit()) {
+ LChar buffer[maxLengthForOnStackResolve];
+ resolveRopeInternal8(buffer);
+ m_value = AtomicString(buffer, m_length);
+ setIs8Bit(m_value.impl()->is8Bit());
+ } else {
+ UChar buffer[maxLengthForOnStackResolve];
+ resolveRopeInternal16(buffer);
+ m_value = AtomicString(buffer, m_length);
+ setIs8Bit(m_value.impl()->is8Bit());
+ }
+
+ clearFibers();
+
+ // If we resolved a string that didn't previously exist, notify the heap that we've grown.
+ if (m_value.impl()->hasOneRef())
+ Heap::heap(this)->reportExtraMemoryAllocated(m_value.impl()->cost());
+}
+
+void JSRopeString::clearFibers() const
+{
+ for (size_t i = 0; i < s_maxInternalRopeLength; ++i)
+ u[i].number = 0;
+}
+
+RefPtr<AtomicStringImpl> JSRopeString::resolveRopeToExistingAtomicString(ExecState* exec) const
+{
+ if (m_length > maxLengthForOnStackResolve) {
+ resolveRope(exec);
+ if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(m_value.impl())) {
+ m_value = *existingAtomicString;
+ setIs8Bit(m_value.impl()->is8Bit());
+ clearFibers();
+ return existingAtomicString;
+ }
+ return nullptr;
+ }
+
+ if (is8Bit()) {
+ LChar buffer[maxLengthForOnStackResolve];
+ resolveRopeInternal8(buffer);
+ if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(buffer, m_length)) {
+ m_value = *existingAtomicString;
+ setIs8Bit(m_value.impl()->is8Bit());
+ clearFibers();
+ return existingAtomicString;
+ }
+ } else {
+ UChar buffer[maxLengthForOnStackResolve];
+ resolveRopeInternal16(buffer);
+ if (RefPtr<AtomicStringImpl> existingAtomicString = AtomicStringImpl::lookUp(buffer, m_length)) {
+ m_value = *existingAtomicString;
+ setIs8Bit(m_value.impl()->is8Bit());
+ clearFibers();
+ return existingAtomicString;
+ }
+ }
+
+ return nullptr;
}
void JSRopeString::resolveRope(ExecState* exec) const
{
ASSERT(isRope());
-
+
+ if (isSubstring()) {
+ ASSERT(!substringBase()->isRope());
+ m_value = substringBase()->m_value.substringSharingImpl(substringOffset(), m_length);
+ substringBase().clear();
+ return;
+ }
+
if (is8Bit()) {
LChar* buffer;
if (RefPtr<StringImpl> newImpl = StringImpl::tryCreateUninitialized(m_length, buffer)) {
- Heap::heap(this)->reportExtraMemoryCost(newImpl->cost());
+ Heap::heap(this)->reportExtraMemoryAllocated(newImpl->cost());
m_value = newImpl.release();
} else {
outOfMemory(exec);
return;
}
-
- for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
- if (m_fibers[i]->isRope())
- return resolveRopeSlowCase8(buffer);
- }
-
- LChar* position = buffer;
- for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
- StringImpl* string = m_fibers[i]->m_value.impl();
- unsigned length = string->length();
- StringImpl::copyChars(position, string->characters8(), length);
- position += length;
- m_fibers[i].clear();
- }
- ASSERT((buffer + m_length) == position);
+ resolveRopeInternal8NoSubstring(buffer);
+ clearFibers();
ASSERT(!isRope());
-
return;
}
UChar* buffer;
if (RefPtr<StringImpl> newImpl = StringImpl::tryCreateUninitialized(m_length, buffer)) {
- Heap::heap(this)->reportExtraMemoryCost(newImpl->cost());
+ Heap::heap(this)->reportExtraMemoryAllocated(newImpl->cost());
m_value = newImpl.release();
} else {
outOfMemory(exec);
return;
}
- for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
- if (m_fibers[i]->isRope())
- return resolveRopeSlowCase(buffer);
- }
-
- UChar* position = buffer;
- for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
- StringImpl* string = m_fibers[i]->m_value.impl();
- unsigned length = string->length();
- if (string->is8Bit())
- StringImpl::copyChars(position, string->characters8(), length);
- else
- StringImpl::copyChars(position, string->characters16(), length);
- position += length;
- m_fibers[i].clear();
- }
- ASSERT((buffer + m_length) == position);
+ resolveRopeInternal16NoSubstring(buffer);
+ clearFibers();
ASSERT(!isRope());
}
@@ -160,31 +294,35 @@ void JSRopeString::resolveRopeSlowCase8(LChar* buffer) const
LChar* position = buffer + m_length; // We will be working backwards over the rope.
Vector<JSString*, 32, UnsafeVectorOverflow> workQueue; // Putting strings into a Vector is only OK because there are no GC points in this method.
- for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
- workQueue.append(m_fibers[i].get());
- // Clearing here works only because there are no GC points in this method.
- m_fibers[i].clear();
- }
+ for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i)
+ workQueue.append(fiber(i).get());
while (!workQueue.isEmpty()) {
JSString* currentFiber = workQueue.last();
workQueue.removeLast();
+ const LChar* characters;
+
if (currentFiber->isRope()) {
JSRopeString* currentFiberAsRope = static_cast<JSRopeString*>(currentFiber);
- for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->m_fibers[i]; ++i)
- workQueue.append(currentFiberAsRope->m_fibers[i].get());
- continue;
- }
-
- StringImpl* string = static_cast<StringImpl*>(currentFiber->m_value.impl());
- unsigned length = string->length();
+ if (!currentFiberAsRope->isSubstring()) {
+ for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->fiber(i); ++i)
+ workQueue.append(currentFiberAsRope->fiber(i).get());
+ continue;
+ }
+ ASSERT(!currentFiberAsRope->substringBase()->isRope());
+ characters =
+ currentFiberAsRope->substringBase()->m_value.characters8() +
+ currentFiberAsRope->substringOffset();
+ } else
+ characters = currentFiber->m_value.characters8();
+
+ unsigned length = currentFiber->length();
position -= length;
- StringImpl::copyChars(position, string->characters8(), length);
+ StringImpl::copyChars(position, characters, length);
}
ASSERT(buffer == position);
- ASSERT(!isRope());
}
void JSRopeString::resolveRopeSlowCase(UChar* buffer) const
@@ -192,8 +330,8 @@ void JSRopeString::resolveRopeSlowCase(UChar* buffer) const
UChar* position = buffer + m_length; // We will be working backwards over the rope.
Vector<JSString*, 32, UnsafeVectorOverflow> workQueue; // These strings are kept alive by the parent rope, so using a Vector is OK.
- for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i)
- workQueue.append(m_fibers[i].get());
+ for (size_t i = 0; i < s_maxInternalRopeLength && fiber(i); ++i)
+ workQueue.append(fiber(i).get());
while (!workQueue.isEmpty()) {
JSString* currentFiber = workQueue.last();
@@ -201,8 +339,21 @@ void JSRopeString::resolveRopeSlowCase(UChar* buffer) const
if (currentFiber->isRope()) {
JSRopeString* currentFiberAsRope = static_cast<JSRopeString*>(currentFiber);
- for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->m_fibers[i]; ++i)
- workQueue.append(currentFiberAsRope->m_fibers[i].get());
+ if (currentFiberAsRope->isSubstring()) {
+ ASSERT(!currentFiberAsRope->substringBase()->isRope());
+ StringImpl* string = static_cast<StringImpl*>(
+ currentFiberAsRope->substringBase()->m_value.impl());
+ unsigned offset = currentFiberAsRope->substringOffset();
+ unsigned length = currentFiberAsRope->length();
+ position -= length;
+ if (string->is8Bit())
+ StringImpl::copyChars(position, string->characters8() + offset, length);
+ else
+ StringImpl::copyChars(position, string->characters16() + offset, length);
+ continue;
+ }
+ for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->fiber(i); ++i)
+ workQueue.append(currentFiberAsRope->fiber(i).get());
continue;
}
@@ -216,31 +367,17 @@ void JSRopeString::resolveRopeSlowCase(UChar* buffer) const
}
ASSERT(buffer == position);
- ASSERT(!isRope());
}
void JSRopeString::outOfMemory(ExecState* exec) const
{
- for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i)
- m_fibers[i].clear();
+ clearFibers();
ASSERT(isRope());
ASSERT(m_value.isNull());
if (exec)
throwOutOfMemoryError(exec);
}
-JSString* JSRopeString::getIndexSlowCase(ExecState* exec, unsigned i)
-{
- ASSERT(isRope());
- resolveRope(exec);
- // Return a safe no-value result, this should never be used, since the excetion will be thrown.
- if (exec->exception())
- return jsEmptyString(exec);
- ASSERT(!isRope());
- RELEASE_ASSERT(i < m_value.length());
- return jsSingleCharacterSubstring(exec, m_value, i);
-}
-
JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const
{
return const_cast<JSString*>(this);
@@ -249,18 +386,13 @@ JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const
bool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const
{
result = this;
- number = jsToNumber(value(exec));
+ number = jsToNumber(unsafeView(*exec));
return false;
}
-bool JSString::toBoolean() const
-{
- return m_length;
-}
-
double JSString::toNumber(ExecState* exec) const
{
- return jsToNumber(value(exec));
+ return jsToNumber(unsafeView(*exec));
}
inline StringObject* StringObject::create(VM& vm, JSGlobalObject* globalObject, JSString* string)
@@ -289,14 +421,23 @@ bool JSString::getStringPropertyDescriptor(ExecState* exec, PropertyName propert
return true;
}
- unsigned i = propertyName.asIndex();
- if (i < m_length) {
- ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail!
- descriptor.setDescriptor(getIndex(exec, i), DontDelete | ReadOnly);
+ Optional<uint32_t> index = parseIndex(propertyName);
+ if (index && index.value() < m_length) {
+ descriptor.setDescriptor(getIndex(exec, index.value()), DontDelete | ReadOnly);
return true;
}
return false;
}
+JSString* jsStringWithCacheSlowCase(VM& vm, StringImpl& stringImpl)
+{
+ if (JSString* string = vm.stringCache.get(&stringImpl))
+ return string;
+
+ JSString* string = jsString(&vm, String(stringImpl));
+ vm.lastCachedString.set(vm, string);
+ return string;
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h
index 448ffc484..6dba78621 100644
--- a/Source/JavaScriptCore/runtime/JSString.h
+++ b/Source/JavaScriptCore/runtime/JSString.h
@@ -30,537 +30,727 @@
#include "PropertySlot.h"
#include "Structure.h"
#include <array>
+#include <wtf/text/StringView.h>
namespace JSC {
- class JSString;
- class JSRopeString;
- class LLIntOffsetsExtractor;
-
- JSString* jsEmptyString(VM*);
- JSString* jsEmptyString(ExecState*);
- JSString* jsString(VM*, const String&); // returns empty string if passed null string
- JSString* jsString(ExecState*, const String&); // returns empty string if passed null string
-
- JSString* jsSingleCharacterString(VM*, UChar);
- JSString* jsSingleCharacterString(ExecState*, UChar);
- JSString* jsSingleCharacterSubstring(ExecState*, const String&, unsigned offset);
- JSString* jsSubstring(VM*, const String&, unsigned offset, unsigned length);
- JSString* jsSubstring(ExecState*, const String&, unsigned offset, unsigned length);
-
- // Non-trivial strings are two or more characters long.
- // These functions are faster than just calling jsString.
- JSString* jsNontrivialString(VM*, const String&);
- JSString* jsNontrivialString(ExecState*, const String&);
-
- // Should be used for strings that are owned by an object that will
- // likely outlive the JSValue this makes, such as the parse tree or a
- // DOM object that contains a String
- JSString* jsOwnedString(VM*, const String&);
- JSString* jsOwnedString(ExecState*, const String&);
-
- JSRopeString* jsStringBuilder(VM*);
-
- class JSString : public JSCell {
- public:
- friend class JIT;
- friend class VM;
- friend class SpecializedThunkJIT;
- friend class JSRopeString;
- friend class MarkStack;
- friend class SlotVisitor;
- friend struct ThunkHelpers;
+class JSString;
+class JSRopeString;
+class LLIntOffsetsExtractor;
+
+JSString* jsEmptyString(VM*);
+JSString* jsEmptyString(ExecState*);
+JSString* jsString(VM*, const String&); // returns empty string if passed null string
+JSString* jsString(ExecState*, const String&); // returns empty string if passed null string
+
+JSString* jsSingleCharacterString(VM*, UChar);
+JSString* jsSingleCharacterString(ExecState*, UChar);
+JSString* jsSubstring(VM*, const String&, unsigned offset, unsigned length);
+JSString* jsSubstring(ExecState*, const String&, unsigned offset, unsigned length);
+
+// Non-trivial strings are two or more characters long.
+// These functions are faster than just calling jsString.
+JSString* jsNontrivialString(VM*, const String&);
+JSString* jsNontrivialString(ExecState*, const String&);
+JSString* jsNontrivialString(ExecState*, String&&);
+
+// Should be used for strings that are owned by an object that will
+// likely outlive the JSValue this makes, such as the parse tree or a
+// DOM object that contains a String
+JSString* jsOwnedString(VM*, const String&);
+JSString* jsOwnedString(ExecState*, const String&);
+
+JSRopeString* jsStringBuilder(VM*);
+
+bool isJSString(JSCell*);
+bool isJSString(JSValue);
+JSString* asString(JSValue);
+
+struct StringViewWithUnderlyingString {
+ StringView view;
+ String underlyingString;
+};
+
+class JSString : public JSCell {
+public:
+ friend class JIT;
+ friend class VM;
+ friend class SpecializedThunkJIT;
+ friend class JSRopeString;
+ friend class MarkStack;
+ friend class SlotVisitor;
+ friend struct ThunkHelpers;
+
+ typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | StructureIsImmortal;
+
+ static const bool needsDestruction = true;
+ static void destroy(JSCell*);
+
+private:
+ JSString(VM& vm, PassRefPtr<StringImpl> value)
+ : JSCell(vm, vm.stringStructure.get())
+ , m_flags(0)
+ , m_value(value)
+ {
+ }
- typedef JSCell Base;
+ JSString(VM& vm)
+ : JSCell(vm, vm.stringStructure.get())
+ , m_flags(0)
+ {
+ }
- static const bool needsDestruction = true;
- static const bool hasImmortalStructure = true;
- static void destroy(JSCell*);
+ void finishCreation(VM& vm, size_t length)
+ {
+ ASSERT(!m_value.isNull());
+ Base::finishCreation(vm);
+ m_length = length;
+ setIs8Bit(m_value.impl()->is8Bit());
+ }
- private:
- JSString(VM& vm, PassRefPtr<StringImpl> value)
- : JSCell(vm, vm.stringStructure.get())
- , m_flags(0)
- , m_value(value)
- {
- }
+ void finishCreation(VM& vm, size_t length, size_t cost)
+ {
+ ASSERT(!m_value.isNull());
+ Base::finishCreation(vm);
+ m_length = length;
+ setIs8Bit(m_value.impl()->is8Bit());
+ Heap::heap(this)->reportExtraMemoryAllocated(cost);
+ }
- JSString(VM& vm)
- : JSCell(vm, vm.stringStructure.get())
- , m_flags(0)
- {
- }
+protected:
+ void finishCreation(VM& vm)
+ {
+ Base::finishCreation(vm);
+ m_length = 0;
+ setIs8Bit(true);
+ }
- void finishCreation(VM& vm, size_t length)
- {
- ASSERT(!m_value.isNull());
- Base::finishCreation(vm);
- m_length = length;
- setIs8Bit(m_value.impl()->is8Bit());
- vm.m_newStringsSinceLastHashCons++;
- }
+public:
+ static JSString* create(VM& vm, PassRefPtr<StringImpl> value)
+ {
+ ASSERT(value);
+ int32_t length = value->length();
+ RELEASE_ASSERT(length >= 0);
+ size_t cost = value->cost();
+ JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value);
+ newString->finishCreation(vm, length, cost);
+ return newString;
+ }
+ static JSString* createHasOtherOwner(VM& vm, PassRefPtr<StringImpl> value)
+ {
+ ASSERT(value);
+ size_t length = value->length();
+ JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value);
+ newString->finishCreation(vm, length);
+ return newString;
+ }
- void finishCreation(VM& vm, size_t length, size_t cost)
- {
- ASSERT(!m_value.isNull());
- Base::finishCreation(vm);
- m_length = length;
- setIs8Bit(m_value.impl()->is8Bit());
- Heap::heap(this)->reportExtraMemoryCost(cost);
- vm.m_newStringsSinceLastHashCons++;
- }
+ Identifier toIdentifier(ExecState*) const;
+ AtomicString toAtomicString(ExecState*) const;
+ RefPtr<AtomicStringImpl> toExistingAtomicString(ExecState*) const;
- protected:
- void finishCreation(VM& vm)
- {
- Base::finishCreation(vm);
- m_length = 0;
- setIs8Bit(true);
- vm.m_newStringsSinceLastHashCons++;
- }
-
- public:
- static JSString* create(VM& vm, PassRefPtr<StringImpl> value)
- {
- ASSERT(value);
- int32_t length = value->length();
- RELEASE_ASSERT(length >= 0);
- size_t cost = value->cost();
- JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value);
- newString->finishCreation(vm, length, cost);
- return newString;
- }
- static JSString* createHasOtherOwner(VM& vm, PassRefPtr<StringImpl> value)
- {
- ASSERT(value);
- size_t length = value->length();
- JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value);
- newString->finishCreation(vm, length);
- return newString;
- }
+ class SafeView;
+ SafeView view(ExecState*) const;
+ StringViewWithUnderlyingString viewWithUnderlyingString(ExecState&) const;
- const String& value(ExecState*) const;
- const String& tryGetValue() const;
- const StringImpl* tryGetValueImpl() const;
- unsigned length() { return m_length; }
-
- JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
- JS_EXPORT_PRIVATE bool toBoolean() const;
- bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
- JSObject* toObject(ExecState*, JSGlobalObject*) const;
- double toNumber(ExecState*) const;
-
- bool getStringPropertySlot(ExecState*, PropertyName, PropertySlot&);
- bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
- bool getStringPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&);
-
- bool canGetIndex(unsigned i) { return i < m_length; }
- JSString* getIndex(ExecState*, unsigned);
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
- {
- return Structure::create(vm, globalObject, proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero), info());
- }
+ const String& value(ExecState*) const;
+ const String& tryGetValue() const;
+ const StringImpl* tryGetValueImpl() const;
+ unsigned length() const { return m_length; }
- static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString, m_length); }
- static size_t offsetOfFlags() { return OBJECT_OFFSETOF(JSString, m_flags); }
- static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_value); }
+ JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
+ bool toBoolean() const { return !!m_length; }
+ bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
+ JSObject* toObject(ExecState*, JSGlobalObject*) const;
+ double toNumber(ExecState*) const;
- DECLARE_EXPORT_INFO;
+ bool getStringPropertySlot(ExecState*, PropertyName, PropertySlot&);
+ bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
+ bool getStringPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&);
- static void visitChildren(JSCell*, SlotVisitor&);
+ bool canGetIndex(unsigned i) { return i < m_length; }
+ JSString* getIndex(ExecState*, unsigned);
- enum {
- HashConsLock = 1u << 2,
- IsHashConsSingleton = 1u << 1,
- Is8Bit = 1u
- };
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
- protected:
- friend class JSValue;
-
- bool isRope() const { return m_value.isNull(); }
- bool is8Bit() const { return m_flags & Is8Bit; }
- void setIs8Bit(bool flag)
- {
- if (flag)
- m_flags |= Is8Bit;
- else
- m_flags &= ~Is8Bit;
- }
- bool shouldTryHashCons();
- bool isHashConsSingleton() const { return m_flags & IsHashConsSingleton; }
- void clearHashConsSingleton() { m_flags &= ~IsHashConsSingleton; }
- void setHashConsSingleton() { m_flags |= IsHashConsSingleton; }
- bool tryHashConsLock();
- void releaseHashConsLock();
-
- unsigned m_flags;
-
- // A string is represented either by a String or a rope of fibers.
- unsigned m_length;
- mutable String m_value;
+ static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString, m_length); }
+ static size_t offsetOfFlags() { return OBJECT_OFFSETOF(JSString, m_flags); }
+ static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_value); }
- private:
- friend class LLIntOffsetsExtractor;
-
- static JSValue toThis(JSCell*, ExecState*, ECMAMode);
+ DECLARE_EXPORT_INFO;
- String& string() { ASSERT(!isRope()); return m_value; }
+ static void dumpToStream(const JSCell*, PrintStream&);
+ static size_t estimatedSize(JSCell*);
+ static void visitChildren(JSCell*, SlotVisitor&);
- friend JSValue jsString(ExecState*, JSString*, JSString*);
- friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length);
+ enum {
+ Is8Bit = 1u
};
- class JSRopeString : public JSString {
- friend class JSString;
+protected:
+ friend class JSValue;
- friend JSRopeString* jsStringBuilder(VM*);
+ bool isRope() const { return m_value.isNull(); }
+ bool isSubstring() const;
+ bool is8Bit() const { return m_flags & Is8Bit; }
+ void setIs8Bit(bool flag) const
+ {
+ if (flag)
+ m_flags |= Is8Bit;
+ else
+ m_flags &= ~Is8Bit;
+ }
- class RopeBuilder {
- public:
- RopeBuilder(VM& vm)
- : m_vm(vm)
- , m_jsString(jsStringBuilder(&vm))
- , m_index(0)
- {
- }
+ mutable unsigned m_flags;
- bool append(JSString* jsString)
- {
- if (m_index == JSRopeString::s_maxInternalRopeLength)
- expand();
- if (static_cast<int32_t>(m_jsString->length() + jsString->length()) < 0) {
- m_jsString = nullptr;
- return false;
- }
- m_jsString->append(m_vm, m_index++, jsString);
- return true;
- }
+ // A string is represented either by a String or a rope of fibers.
+ unsigned m_length;
+ mutable String m_value;
- JSRopeString* release()
- {
- RELEASE_ASSERT(m_jsString);
- JSRopeString* tmp = m_jsString;
- m_jsString = 0;
- return tmp;
- }
+private:
+ friend class LLIntOffsetsExtractor;
- unsigned length() { return m_jsString->m_length; }
+ static JSValue toThis(JSCell*, ExecState*, ECMAMode);
- private:
- void expand();
-
- VM& m_vm;
- JSRopeString* m_jsString;
- size_t m_index;
- };
-
- private:
- JSRopeString(VM& vm)
- : JSString(vm)
- {
- }
+ String& string() { ASSERT(!isRope()); return m_value; }
+ StringView unsafeView(ExecState&) const;
- void finishCreation(VM& vm, JSString* s1, JSString* s2)
- {
- Base::finishCreation(vm);
- m_length = s1->length() + s2->length();
- setIs8Bit(s1->is8Bit() && s2->is8Bit());
- m_fibers[0].set(vm, this, s1);
- m_fibers[1].set(vm, this, s2);
- }
-
- void finishCreation(VM& vm, JSString* s1, JSString* s2, JSString* s3)
- {
- Base::finishCreation(vm);
- m_length = s1->length() + s2->length() + s3->length();
- setIs8Bit(s1->is8Bit() && s2->is8Bit() && s3->is8Bit());
- m_fibers[0].set(vm, this, s1);
- m_fibers[1].set(vm, this, s2);
- m_fibers[2].set(vm, this, s3);
- }
+ friend JSValue jsString(ExecState*, JSString*, JSString*);
+ friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length);
+};
- void finishCreation(VM& vm)
- {
- JSString::finishCreation(vm);
- }
+class JSRopeString final : public JSString {
+ friend class JSString;
- void append(VM& vm, size_t index, JSString* jsString)
- {
- m_fibers[index].set(vm, this, jsString);
- m_length += jsString->m_length;
- RELEASE_ASSERT(static_cast<int32_t>(m_length) >= 0);
- setIs8Bit(is8Bit() && jsString->is8Bit());
- }
+ friend JSRopeString* jsStringBuilder(VM*);
- static JSRopeString* createNull(VM& vm)
+public:
+ class RopeBuilder {
+ public:
+ RopeBuilder(VM& vm)
+ : m_vm(vm)
+ , m_jsString(jsStringBuilder(&vm))
+ , m_index(0)
{
- JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
- newString->finishCreation(vm);
- return newString;
}
- public:
- static JSString* create(VM& vm, JSString* s1, JSString* s2)
+ bool append(JSString* jsString)
{
- JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
- newString->finishCreation(vm, s1, s2);
- return newString;
+ if (m_index == JSRopeString::s_maxInternalRopeLength)
+ expand();
+ if (static_cast<int32_t>(m_jsString->length() + jsString->length()) < 0) {
+ m_jsString = nullptr;
+ return false;
+ }
+ m_jsString->append(m_vm, m_index++, jsString);
+ return true;
}
- static JSString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3)
+
+ JSRopeString* release()
{
- JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
- newString->finishCreation(vm, s1, s2, s3);
- return newString;
+ RELEASE_ASSERT(m_jsString);
+ JSRopeString* tmp = m_jsString;
+ m_jsString = 0;
+ return tmp;
}
- void visitFibers(SlotVisitor&);
-
- static ptrdiff_t offsetOfFibers() { return OBJECT_OFFSETOF(JSRopeString, m_fibers); }
+ unsigned length() const { return m_jsString->m_length; }
- static const unsigned s_maxInternalRopeLength = 3;
-
private:
- friend JSValue jsStringFromRegisterArray(ExecState*, Register*, unsigned);
- friend JSValue jsStringFromArguments(ExecState*, JSValue);
-
- JS_EXPORT_PRIVATE void resolveRope(ExecState*) const;
- void resolveRopeSlowCase8(LChar*) const;
- void resolveRopeSlowCase(UChar*) const;
- void outOfMemory(ExecState*) const;
-
- JS_EXPORT_PRIVATE JSString* getIndexSlowCase(ExecState*, unsigned);
+ void expand();
- mutable std::array<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers;
+ VM& m_vm;
+ JSRopeString* m_jsString;
+ size_t m_index;
};
-
- inline const StringImpl* JSString::tryGetValueImpl() const
+private:
+ JSRopeString(VM& vm)
+ : JSString(vm)
{
- return m_value.impl();
}
- JSString* asString(JSValue);
-
- inline JSString* asString(JSValue value)
+ void finishCreation(VM& vm, JSString* s1, JSString* s2)
{
- ASSERT(value.asCell()->isString());
- return jsCast<JSString*>(value.asCell());
+ Base::finishCreation(vm);
+ m_length = s1->length() + s2->length();
+ setIs8Bit(s1->is8Bit() && s2->is8Bit());
+ setIsSubstring(false);
+ fiber(0).set(vm, this, s1);
+ fiber(1).set(vm, this, s2);
+ fiber(2).clear();
}
- inline JSString* jsEmptyString(VM* vm)
+ void finishCreation(VM& vm, JSString* s1, JSString* s2, JSString* s3)
{
- return vm->smallStrings.emptyString();
+ Base::finishCreation(vm);
+ m_length = s1->length() + s2->length() + s3->length();
+ setIs8Bit(s1->is8Bit() && s2->is8Bit() && s3->is8Bit());
+ setIsSubstring(false);
+ fiber(0).set(vm, this, s1);
+ fiber(1).set(vm, this, s2);
+ fiber(2).set(vm, this, s3);
}
- ALWAYS_INLINE JSString* jsSingleCharacterString(VM* vm, UChar c)
+ void finishCreation(ExecState& exec, JSString& base, unsigned offset, unsigned length)
{
- if (c <= maxSingleCharacterString)
- return vm->smallStrings.singleCharacterString(c);
- return JSString::create(*vm, String(&c, 1).impl());
+ VM& vm = exec.vm();
+ Base::finishCreation(vm);
+ ASSERT(!sumOverflows<int32_t>(offset, length));
+ ASSERT(offset + length <= base.length());
+ m_length = length;
+ setIs8Bit(base.is8Bit());
+ setIsSubstring(true);
+ if (base.isSubstring()) {
+ JSRopeString& baseRope = static_cast<JSRopeString&>(base);
+ substringBase().set(vm, this, baseRope.substringBase().get());
+ substringOffset() = baseRope.substringOffset() + offset;
+ } else {
+ substringBase().set(vm, this, &base);
+ substringOffset() = offset;
+
+ // For now, let's not allow substrings with a rope base.
+ // Resolve non-substring rope bases so we don't have to deal with it.
+ // FIXME: Evaluate if this would be worth adding more branches.
+ if (base.isRope())
+ static_cast<JSRopeString&>(base).resolveRope(&exec);
+ }
}
- ALWAYS_INLINE JSString* jsSingleCharacterSubstring(ExecState* exec, const String& s, unsigned offset)
+ void finishCreation(VM& vm)
{
- VM* vm = &exec->vm();
- ASSERT(offset < static_cast<unsigned>(s.length()));
- UChar c = s.characterAt(offset);
- if (c <= maxSingleCharacterString)
- return vm->smallStrings.singleCharacterString(c);
- return JSString::create(*vm, StringImpl::create(s.impl(), offset, 1));
+ JSString::finishCreation(vm);
+ setIsSubstring(false);
+ fiber(0).clear();
+ fiber(1).clear();
+ fiber(2).clear();
}
- inline JSString* jsNontrivialString(VM* vm, const String& s)
+ void append(VM& vm, size_t index, JSString* jsString)
{
- ASSERT(s.length() > 1);
- return JSString::create(*vm, s.impl());
+ fiber(index).set(vm, this, jsString);
+ m_length += jsString->m_length;
+ RELEASE_ASSERT(static_cast<int32_t>(m_length) >= 0);
+ setIs8Bit(is8Bit() && jsString->is8Bit());
}
- inline const String& JSString::value(ExecState* exec) const
+ static JSRopeString* createNull(VM& vm)
{
- if (isRope())
- static_cast<const JSRopeString*>(this)->resolveRope(exec);
- return m_value;
+ JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
+ newString->finishCreation(vm);
+ return newString;
}
- inline const String& JSString::tryGetValue() const
+public:
+ static JSString* create(VM& vm, JSString* s1, JSString* s2)
{
- if (isRope())
- static_cast<const JSRopeString*>(this)->resolveRope(0);
- return m_value;
+ JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
+ newString->finishCreation(vm, s1, s2);
+ return newString;
}
-
- inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
+ static JSString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3)
{
- ASSERT(canGetIndex(i));
- if (isRope())
- return static_cast<JSRopeString*>(this)->getIndexSlowCase(exec, i);
- ASSERT(i < m_value.length());
- return jsSingleCharacterSubstring(exec, m_value, i);
+ JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
+ newString->finishCreation(vm, s1, s2, s3);
+ return newString;
}
- inline JSString* jsString(VM* vm, const String& s)
+ static JSString* create(ExecState& exec, JSString& base, unsigned offset, unsigned length)
{
- int size = s.length();
- if (!size)
- return vm->smallStrings.emptyString();
- if (size == 1) {
- UChar c = s.characterAt(0);
- if (c <= maxSingleCharacterString)
- return vm->smallStrings.singleCharacterString(c);
- }
- return JSString::create(*vm, s.impl());
+ JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(exec.vm().heap)) JSRopeString(exec.vm());
+ newString->finishCreation(exec, base, offset, length);
+ return newString;
}
- inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length)
+ void visitFibers(SlotVisitor&);
+
+ static ptrdiff_t offsetOfFibers() { return OBJECT_OFFSETOF(JSRopeString, u); }
+
+ static const unsigned s_maxInternalRopeLength = 3;
+
+private:
+ friend JSValue jsStringFromRegisterArray(ExecState*, Register*, unsigned);
+ friend JSValue jsStringFromArguments(ExecState*, JSValue);
+
+ JS_EXPORT_PRIVATE void resolveRope(ExecState*) const;
+ JS_EXPORT_PRIVATE void resolveRopeToAtomicString(ExecState*) const;
+ JS_EXPORT_PRIVATE RefPtr<AtomicStringImpl> resolveRopeToExistingAtomicString(ExecState*) const;
+ void resolveRopeSlowCase8(LChar*) const;
+ void resolveRopeSlowCase(UChar*) const;
+ void outOfMemory(ExecState*) const;
+ void resolveRopeInternal8(LChar*) const;
+ void resolveRopeInternal8NoSubstring(LChar*) const;
+ void resolveRopeInternal16(UChar*) const;
+ void resolveRopeInternal16NoSubstring(UChar*) const;
+ void clearFibers() const;
+ StringView unsafeView(ExecState&) const;
+ StringViewWithUnderlyingString viewWithUnderlyingString(ExecState&) const;
+
+ WriteBarrierBase<JSString>& fiber(unsigned i) const
{
- ASSERT(offset <= static_cast<unsigned>(s->length()));
- ASSERT(length <= static_cast<unsigned>(s->length()));
- ASSERT(offset + length <= static_cast<unsigned>(s->length()));
- VM* vm = &exec->vm();
- if (!length)
- return vm->smallStrings.emptyString();
- return jsSubstring(vm, s->value(exec), offset, length);
+ ASSERT(!isSubstring());
+ ASSERT(i < s_maxInternalRopeLength);
+ return u[i].string;
}
- inline JSString* jsSubstring8(VM* vm, const String& s, unsigned offset, unsigned length)
+ WriteBarrierBase<JSString>& substringBase() const
{
- ASSERT(offset <= static_cast<unsigned>(s.length()));
- ASSERT(length <= static_cast<unsigned>(s.length()));
- ASSERT(offset + length <= static_cast<unsigned>(s.length()));
- if (!length)
- return vm->smallStrings.emptyString();
- if (length == 1) {
- UChar c = s.characterAt(offset);
- if (c <= maxSingleCharacterString)
- return vm->smallStrings.singleCharacterString(c);
- }
- return JSString::createHasOtherOwner(*vm, StringImpl::create8(s.impl(), offset, length));
+ return u[1].string;
}
- inline JSString* jsSubstring(VM* vm, const String& s, unsigned offset, unsigned length)
+ uintptr_t& substringOffset() const
{
- ASSERT(offset <= static_cast<unsigned>(s.length()));
- ASSERT(length <= static_cast<unsigned>(s.length()));
- ASSERT(offset + length <= static_cast<unsigned>(s.length()));
- if (!length)
- return vm->smallStrings.emptyString();
- if (length == 1) {
- UChar c = s.characterAt(offset);
- if (c <= maxSingleCharacterString)
- return vm->smallStrings.singleCharacterString(c);
- }
- return JSString::createHasOtherOwner(*vm, StringImpl::create(s.impl(), offset, length));
+ return u[2].number;
}
- inline JSString* jsOwnedString(VM* vm, const String& s)
+ static uintptr_t notSubstringSentinel()
{
- int size = s.length();
- if (!size)
- return vm->smallStrings.emptyString();
- if (size == 1) {
- UChar c = s.characterAt(0);
- if (c <= maxSingleCharacterString)
- return vm->smallStrings.singleCharacterString(c);
- }
- return JSString::createHasOtherOwner(*vm, s.impl());
+ return 0;
}
- inline JSRopeString* jsStringBuilder(VM* vm)
+ static uintptr_t substringSentinel()
{
- return JSRopeString::createNull(*vm);
+ return 1;
}
- inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->vm()); }
- inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->vm(), s); }
- inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->vm(), c); }
- inline JSString* jsSubstring8(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring8(&exec->vm(), s, offset, length); }
- inline JSString* jsSubstring(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring(&exec->vm(), s, offset, length); }
- inline JSString* jsNontrivialString(ExecState* exec, const String& s) { return jsNontrivialString(&exec->vm(), s); }
- inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->vm(), s); }
+ bool isSubstring() const
+ {
+ return u[0].number == substringSentinel();
+ }
- ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+ void setIsSubstring(bool isSubstring)
{
- if (propertyName == exec->propertyNames().length) {
- slot.setValue(this, DontEnum | DontDelete | ReadOnly, jsNumber(m_length));
- return true;
- }
+ u[0].number = isSubstring ? substringSentinel() : notSubstringSentinel();
+ }
- unsigned i = propertyName.asIndex();
- if (i < m_length) {
- ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail!
- slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, i));
- return true;
- }
+ mutable union {
+ uintptr_t number;
+ WriteBarrierBase<JSString> string;
+ } u[s_maxInternalRopeLength];
+};
+
+class JSString::SafeView {
+public:
+ explicit SafeView(ExecState&, const JSString&);
+ StringView get() const;
+
+ bool is8Bit() const { return m_string->is8Bit(); }
+ unsigned length() const { return m_string->length(); }
+ const LChar* characters8() const { return get().characters8(); }
+ const UChar* characters16() const { return get().characters16(); }
+ UChar operator[](unsigned index) const { return get()[index]; }
+
+private:
+ ExecState& m_state;
+
+ // The following pointer is marked "volatile" to make the compiler leave it on the stack
+ // or in a register as long as this object is alive, even after the last use of the pointer.
+ // That's needed to prevent garbage collecting the string and possibly deleting the block
+ // with the characters in it, and then using the StringView after that.
+ const JSString* volatile m_string;
+};
+
+JS_EXPORT_PRIVATE JSString* jsStringWithCacheSlowCase(VM&, StringImpl&);
+
+inline const StringImpl* JSString::tryGetValueImpl() const
+{
+ return m_value.impl();
+}
+
+inline JSString* asString(JSValue value)
+{
+ ASSERT(value.asCell()->isString());
+ return jsCast<JSString*>(value.asCell());
+}
+
+inline JSString* jsEmptyString(VM* vm)
+{
+ return vm->smallStrings.emptyString();
+}
+
+ALWAYS_INLINE JSString* jsSingleCharacterString(VM* vm, UChar c)
+{
+ if (c <= maxSingleCharacterString)
+ return vm->smallStrings.singleCharacterString(c);
+ return JSString::create(*vm, String(&c, 1).impl());
+}
+
+inline JSString* jsNontrivialString(VM* vm, const String& s)
+{
+ ASSERT(s.length() > 1);
+ return JSString::create(*vm, s.impl());
+}
+
+inline JSString* jsNontrivialString(VM* vm, String&& s)
+{
+ ASSERT(s.length() > 1);
+ return JSString::create(*vm, s.releaseImpl());
+}
+
+ALWAYS_INLINE Identifier JSString::toIdentifier(ExecState* exec) const
+{
+ return Identifier::fromString(exec, toAtomicString(exec));
+}
+
+ALWAYS_INLINE AtomicString JSString::toAtomicString(ExecState* exec) const
+{
+ if (isRope())
+ static_cast<const JSRopeString*>(this)->resolveRopeToAtomicString(exec);
+ return AtomicString(m_value);
+}
+
+ALWAYS_INLINE RefPtr<AtomicStringImpl> JSString::toExistingAtomicString(ExecState* exec) const
+{
+ if (isRope())
+ return static_cast<const JSRopeString*>(this)->resolveRopeToExistingAtomicString(exec);
+ if (m_value.impl()->isAtomic())
+ return static_cast<AtomicStringImpl*>(m_value.impl());
+ return AtomicStringImpl::lookUp(m_value.impl());
+}
+
+inline const String& JSString::value(ExecState* exec) const
+{
+ if (isRope())
+ static_cast<const JSRopeString*>(this)->resolveRope(exec);
+ return m_value;
+}
+
+inline const String& JSString::tryGetValue() const
+{
+ if (isRope())
+ static_cast<const JSRopeString*>(this)->resolveRope(0);
+ return m_value;
+}
+
+inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
+{
+ ASSERT(canGetIndex(i));
+ return jsSingleCharacterString(exec, unsafeView(*exec)[i]);
+}
+
+inline JSString* jsString(VM* vm, const String& s)
+{
+ int size = s.length();
+ if (!size)
+ return vm->smallStrings.emptyString();
+ if (size == 1) {
+ UChar c = s.characterAt(0);
+ if (c <= maxSingleCharacterString)
+ return vm->smallStrings.singleCharacterString(c);
+ }
+ return JSString::create(*vm, s.impl());
+}
+
+inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length)
+{
+ ASSERT(offset <= static_cast<unsigned>(s->length()));
+ ASSERT(length <= static_cast<unsigned>(s->length()));
+ ASSERT(offset + length <= static_cast<unsigned>(s->length()));
+ VM& vm = exec->vm();
+ if (!length)
+ return vm.smallStrings.emptyString();
+ if (!offset && length == s->length())
+ return s;
+ return JSRopeString::create(*exec, *s, offset, length);
+}
+
+inline JSString* jsSubstring(VM* vm, const String& s, unsigned offset, unsigned length)
+{
+ ASSERT(offset <= static_cast<unsigned>(s.length()));
+ ASSERT(length <= static_cast<unsigned>(s.length()));
+ ASSERT(offset + length <= static_cast<unsigned>(s.length()));
+ if (!length)
+ return vm->smallStrings.emptyString();
+ if (length == 1) {
+ UChar c = s.characterAt(offset);
+ if (c <= maxSingleCharacterString)
+ return vm->smallStrings.singleCharacterString(c);
+ }
+ return JSString::createHasOtherOwner(*vm, StringImpl::createSubstringSharingImpl(s.impl(), offset, length));
+}
- return false;
+inline JSString* jsOwnedString(VM* vm, const String& s)
+{
+ int size = s.length();
+ if (!size)
+ return vm->smallStrings.emptyString();
+ if (size == 1) {
+ UChar c = s.characterAt(0);
+ if (c <= maxSingleCharacterString)
+ return vm->smallStrings.singleCharacterString(c);
+ }
+ return JSString::createHasOtherOwner(*vm, s.impl());
+}
+
+inline JSRopeString* jsStringBuilder(VM* vm)
+{
+ return JSRopeString::createNull(*vm);
+}
+
+inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->vm()); }
+inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->vm(), s); }
+inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->vm(), c); }
+inline JSString* jsSubstring(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring(&exec->vm(), s, offset, length); }
+inline JSString* jsNontrivialString(ExecState* exec, const String& s) { return jsNontrivialString(&exec->vm(), s); }
+inline JSString* jsNontrivialString(ExecState* exec, String&& s) { return jsNontrivialString(&exec->vm(), WTFMove(s)); }
+inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->vm(), s); }
+
+ALWAYS_INLINE JSString* jsStringWithCache(ExecState* exec, const String& s)
+{
+ VM& vm = exec->vm();
+ StringImpl* stringImpl = s.impl();
+ if (!stringImpl || !stringImpl->length())
+ return jsEmptyString(&vm);
+
+ if (stringImpl->length() == 1) {
+ UChar singleCharacter = (*stringImpl)[0u];
+ if (singleCharacter <= maxSingleCharacterString)
+ return vm.smallStrings.singleCharacterString(static_cast<unsigned char>(singleCharacter));
}
-
- ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
- {
- if (propertyName < m_length) {
- slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, propertyName));
- return true;
- }
- return false;
+ if (JSString* lastCachedString = vm.lastCachedString.get()) {
+ if (lastCachedString->tryGetValueImpl() == stringImpl)
+ return lastCachedString;
}
- inline bool isJSString(JSValue v) { return v.isCell() && v.asCell()->classInfo() == JSString::info(); }
+ return jsStringWithCacheSlowCase(vm, *stringImpl);
+}
- // --- JSValue inlines ----------------------------
-
- inline bool JSValue::toBoolean(ExecState* exec) const
- {
- if (isInt32())
- return asInt32();
- if (isDouble())
- return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
- if (isCell())
- return asCell()->toBoolean(exec);
- return isTrue(); // false, null, and undefined all convert to false.
- }
+ALWAYS_INLINE JSString* jsStringWithCache(ExecState* exec, const AtomicString& s)
+{
+ return jsStringWithCache(exec, s.string());
+}
- inline JSString* JSValue::toString(ExecState* exec) const
- {
- if (isString())
- return jsCast<JSString*>(asCell());
- return toStringSlowCase(exec);
+ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ if (propertyName == exec->propertyNames().length) {
+ slot.setValue(this, DontEnum | DontDelete | ReadOnly, jsNumber(m_length));
+ return true;
}
- inline String JSValue::toWTFString(ExecState* exec) const
- {
- if (isString())
- return static_cast<JSString*>(asCell())->value(exec);
- return toWTFStringSlowCase(exec);
+ Optional<uint32_t> index = parseIndex(propertyName);
+ if (index && index.value() < m_length) {
+ slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, index.value()));
+ return true;
}
- ALWAYS_INLINE String inlineJSValueNotStringtoString(const JSValue& value, ExecState* exec)
- {
- VM& vm = exec->vm();
- if (value.isInt32())
- return vm.numericStrings.add(value.asInt32());
- if (value.isDouble())
- return vm.numericStrings.add(value.asDouble());
- if (value.isTrue())
- return vm.propertyNames->trueKeyword.string();
- if (value.isFalse())
- return vm.propertyNames->falseKeyword.string();
- if (value.isNull())
- return vm.propertyNames->nullKeyword.string();
- if (value.isUndefined())
- return vm.propertyNames->undefinedKeyword.string();
- return value.toString(exec)->value(exec);
- }
-
- ALWAYS_INLINE String JSValue::toWTFStringInline(ExecState* exec) const
- {
- if (isString())
- return static_cast<JSString*>(asCell())->value(exec);
+ return false;
+}
- return inlineJSValueNotStringtoString(*this, exec);
+ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
+{
+ if (propertyName < m_length) {
+ slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, propertyName));
+ return true;
+ }
+
+ return false;
+}
+
+inline bool isJSString(JSCell* cell)
+{
+ return cell->type() == StringType;
+}
+
+inline bool isJSString(JSValue v)
+{
+ return v.isCell() && isJSString(v.asCell());
+}
+
+ALWAYS_INLINE StringView JSRopeString::unsafeView(ExecState& state) const
+{
+ if (isSubstring()) {
+ if (is8Bit())
+ return StringView(substringBase()->m_value.characters8() + substringOffset(), m_length);
+ return StringView(substringBase()->m_value.characters16() + substringOffset(), m_length);
+ }
+ resolveRope(&state);
+ return m_value;
+}
+
+ALWAYS_INLINE StringViewWithUnderlyingString JSRopeString::viewWithUnderlyingString(ExecState& state) const
+{
+ if (isSubstring()) {
+ auto& base = substringBase()->m_value;
+ if (is8Bit())
+ return { { base.characters8() + substringOffset(), m_length }, base };
+ return { { base.characters16() + substringOffset(), m_length }, base };
}
+ resolveRope(&state);
+ return { m_value, m_value };
+}
+
+ALWAYS_INLINE StringView JSString::unsafeView(ExecState& state) const
+{
+ if (isRope())
+ return static_cast<const JSRopeString*>(this)->unsafeView(state);
+ return m_value;
+}
+
+ALWAYS_INLINE StringViewWithUnderlyingString JSString::viewWithUnderlyingString(ExecState& state) const
+{
+ if (isRope())
+ return static_cast<const JSRopeString&>(*this).viewWithUnderlyingString(state);
+ return { m_value, m_value };
+}
+
+inline bool JSString::isSubstring() const
+{
+ return isRope() && static_cast<const JSRopeString*>(this)->isSubstring();
+}
+
+inline JSString::SafeView::SafeView(ExecState& state, const JSString& string)
+ : m_state(state)
+ , m_string(&string)
+{
+}
+
+inline StringView JSString::SafeView::get() const
+{
+ return m_string->unsafeView(m_state);
+}
+
+ALWAYS_INLINE JSString::SafeView JSString::view(ExecState* exec) const
+{
+ return SafeView(*exec, *this);
+}
+
+// --- JSValue inlines ----------------------------
+
+inline bool JSValue::toBoolean(ExecState* exec) const
+{
+ if (isInt32())
+ return asInt32();
+ if (isDouble())
+ return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
+ if (isCell())
+ return asCell()->toBoolean(exec);
+ return isTrue(); // false, null, and undefined all convert to false.
+}
+
+inline JSString* JSValue::toString(ExecState* exec) const
+{
+ if (isString())
+ return jsCast<JSString*>(asCell());
+ bool returnEmptyStringOnError = true;
+ return toStringSlowCase(exec, returnEmptyStringOnError);
+}
+
+inline JSString* JSValue::toStringOrNull(ExecState* exec) const
+{
+ if (isString())
+ return jsCast<JSString*>(asCell());
+ bool returnEmptyStringOnError = false;
+ return toStringSlowCase(exec, returnEmptyStringOnError);
+}
+
+inline String JSValue::toWTFString(ExecState* exec) const
+{
+ if (isString())
+ return static_cast<JSString*>(asCell())->value(exec);
+ return toWTFStringSlowCase(exec);
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSStringBuilder.h b/Source/JavaScriptCore/runtime/JSStringBuilder.h
index 7b1c1a505..32b39f0a4 100644
--- a/Source/JavaScriptCore/runtime/JSStringBuilder.h
+++ b/Source/JavaScriptCore/runtime/JSStringBuilder.h
@@ -32,6 +32,7 @@
namespace JSC {
+// FIXME: Should move the last few callers over from this to WTF::StringBuilder.
class JSStringBuilder {
public:
JSStringBuilder()
@@ -40,73 +41,64 @@ public:
{
}
- void append(const UChar u)
+ void append(LChar character)
{
if (m_is8Bit) {
- if (u < 0xff) {
- LChar c = u;
- m_okay &= buffer8.tryAppend(&c, 1);
+ m_okay &= buffer8.tryAppend(&character, 1);
+ return;
+ }
+ UChar upconvertedCharacter = character;
+ m_okay &= buffer16.tryAppend(&upconvertedCharacter, 1);
+ }
+
+ void append(UChar character)
+ {
+ if (m_is8Bit) {
+ if (character < 0x100) {
+ LChar narrowedCharacter = character;
+ m_okay &= buffer8.tryAppend(&narrowedCharacter, 1);
return;
}
upConvert();
}
- m_okay &= buffer16.tryAppend(&u, 1);
+ m_okay &= buffer16.tryAppend(&character, 1);
}
void append(const char* str)
{
- append(str, strlen(str));
+ append(reinterpret_cast<const LChar*>(str), strlen(str));
}
- void append(const char* str, size_t len)
+ JSValue build(ExecState* exec)
{
+ if (!m_okay)
+ return throwOutOfMemoryError(exec);
if (m_is8Bit) {
- m_okay &= buffer8.tryAppend(reinterpret_cast<const LChar*>(str), len);
- return;
- }
- m_okay &= buffer8.tryReserveCapacity(buffer16.size() + len);
- for (size_t i = 0; i < len; i++) {
- UChar u = static_cast<unsigned char>(str[i]);
- m_okay &= buffer16.tryAppend(&u, 1);
+ buffer8.shrinkToFit();
+ if (!buffer8.data())
+ return throwOutOfMemoryError(exec);
+ return jsString(exec, String::adopt(buffer8));
}
+ buffer16.shrinkToFit();
+ if (!buffer16.data())
+ return throwOutOfMemoryError(exec);
+ return jsString(exec, String::adopt(buffer16));
}
- void append(const LChar* str, size_t len)
+private:
+ void append(const LChar* characters, size_t length)
{
if (m_is8Bit) {
- m_okay &= buffer8.tryAppend(str, len);
+ m_okay &= buffer8.tryAppend(characters, length);
return;
}
- m_okay &= buffer8.tryReserveCapacity(buffer16.size() + len);
- for (size_t i = 0; i < len; i++) {
- UChar u = str[i];
- m_okay &= buffer16.tryAppend(&u, 1);
+ // FIXME: There must be a more efficient way of doing this.
+ m_okay &= buffer16.tryReserveCapacity(buffer16.size() + length);
+ for (size_t i = 0; i < length; i++) {
+ UChar upconvertedCharacter = characters[i];
+ m_okay &= buffer16.tryAppend(&upconvertedCharacter, 1);
}
}
-
- void append(const UChar* str, size_t len)
- {
- if (m_is8Bit)
- upConvert(); // FIXME: We could check character by character its size.
- m_okay &= buffer16.tryAppend(str, len);
- }
-
- void append(const String& str)
- {
- unsigned length = str.length();
-
- if (!length)
- return;
-
- if (m_is8Bit) {
- if (str.is8Bit()) {
- m_okay &= buffer8.tryAppend(str.characters8(), length);
- return;
- }
- upConvert();
- }
- m_okay &= buffer16.tryAppend(str.deprecatedCharacters(), length);
- }
void upConvert()
{
@@ -120,69 +112,22 @@ public:
m_is8Bit = false;
}
- JSValue build(ExecState* exec)
- {
- if (!m_okay)
- return throwOutOfMemoryError(exec);
- if (m_is8Bit) {
- buffer8.shrinkToFit();
- if (!buffer8.data())
- return throwOutOfMemoryError(exec);
- return jsString(exec, String::adopt(buffer8));
- }
- buffer16.shrinkToFit();
- if (!buffer16.data())
- return throwOutOfMemoryError(exec);
- return jsString(exec, String::adopt(buffer16));
- }
-
-protected:
Vector<LChar, 64, UnsafeVectorOverflow> buffer8;
Vector<UChar, 64, UnsafeVectorOverflow> buffer16;
bool m_okay;
bool m_is8Bit;
};
-template<typename StringType1, typename StringType2>
-inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2)
-{
- PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2);
- if (!result)
- return throwOutOfMemoryError(exec);
- return jsNontrivialString(exec, result);
-}
-
-template<typename StringType1, typename StringType2, typename StringType3>
-inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3)
+template<typename StringType>
+inline JSValue jsMakeNontrivialString(ExecState* exec, StringType&& string)
{
- PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3);
- if (!result)
- return throwOutOfMemoryError(exec);
- return jsNontrivialString(exec, result);
-}
-
-template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
-inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
-{
- PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3, string4);
- if (!result)
- return throwOutOfMemoryError(exec);
- return jsNontrivialString(exec, result);
-}
-
-template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
-inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
-{
- PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3, string4, string5);
- if (!result)
- return throwOutOfMemoryError(exec);
- return jsNontrivialString(exec, result);
+ return jsNontrivialString(exec, std::forward<StringType>(string));
}
-template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
-inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
+template<typename StringType, typename... StringTypes>
+inline JSValue jsMakeNontrivialString(ExecState* exec, const StringType& string, const StringTypes&... strings)
{
- PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3, string4, string5, string6);
+ String result = WTF::tryMakeString(string, strings...);
if (!result)
return throwOutOfMemoryError(exec);
return jsNontrivialString(exec, result);
diff --git a/Source/JavaScriptCore/runtime/JSStringIterator.cpp b/Source/JavaScriptCore/runtime/JSStringIterator.cpp
new file mode 100644
index 000000000..c6fede7ad
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSStringIterator.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 "JSStringIterator.h"
+
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+const ClassInfo JSStringIterator::s_info = { "String Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(JSStringIterator) };
+
+void JSStringIterator::finishCreation(VM& vm, JSGlobalObject*, JSString* iteratedString)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+ putDirect(vm, vm.propertyNames->iteratedStringPrivateName, iteratedString);
+ putDirect(vm, vm.propertyNames->stringIteratorNextIndexPrivateName, jsNumber(0));
+}
+
+JSValue JSStringIterator::iteratedValue(ExecState* exec) const
+{
+ return getDirect(exec->vm(), exec->vm().propertyNames->iteratedStringPrivateName);
+}
+
+JSStringIterator* JSStringIterator::clone(ExecState* exec)
+{
+ VM& vm = exec->vm();
+ JSValue iteratedString = getDirect(vm, vm.propertyNames->iteratedStringPrivateName);
+ JSValue nextIndex = getDirect(vm, vm.propertyNames->stringIteratorNextIndexPrivateName);
+
+ auto clone = JSStringIterator::create(exec, exec->callee()->globalObject()->stringIteratorStructure(), asString(iteratedString));
+ clone->putDirect(vm, vm.propertyNames->stringIteratorNextIndexPrivateName, nextIndex);
+ return clone;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSStringIterator.h b/Source/JavaScriptCore/runtime/JSStringIterator.h
new file mode 100644
index 000000000..6a789a319
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSStringIterator.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 JSStringIterator_h
+#define JSStringIterator_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class JSStringIterator : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+
+ DECLARE_EXPORT_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ static JSStringIterator* create(ExecState* exec, Structure* structure, JSString* iteratedString)
+ {
+ VM& vm = exec->vm();
+ JSStringIterator* instance = new (NotNull, allocateCell<JSStringIterator>(vm.heap)) JSStringIterator(vm, structure);
+ instance->finishCreation(vm, structure->globalObject(), iteratedString);
+ return instance;
+ }
+
+ JSValue iteratedValue(ExecState*) const;
+ JSStringIterator* clone(ExecState*);
+
+private:
+ JSStringIterator(VM& vm, Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ void finishCreation(VM&, JSGlobalObject*, JSString* iteratedString);
+};
+
+}
+
+#endif // !defined(JSStringIterator_h)
diff --git a/Source/JavaScriptCore/runtime/JSStringJoiner.cpp b/Source/JavaScriptCore/runtime/JSStringJoiner.cpp
index b6461c750..57ffdd929 100644
--- a/Source/JavaScriptCore/runtime/JSStringJoiner.cpp
+++ b/Source/JavaScriptCore/runtime/JSStringJoiner.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-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
@@ -26,105 +26,94 @@
#include "config.h"
#include "JSStringJoiner.h"
-#include "ExceptionHelpers.h"
-#include "JSScope.h"
-#include "JSString.h"
-#include "Operations.h"
-#include <wtf/text/StringImpl.h>
+#include "JSCInlines.h"
namespace JSC {
-// The destination is 16bits, at least one string is 16 bits.
-static inline void appendStringToData(UChar*& data, const String& string)
+template<typename CharacterType>
+static inline void appendStringToData(CharacterType*& data, StringView string)
{
- if (string.isNull())
- return;
+ string.getCharactersWithUpconvert(data);
+ data += string.length();
+}
- unsigned length = string.length();
- const StringImpl* stringImpl = string.impl();
+template<typename CharacterType>
+static inline String joinStrings(const Vector<StringViewWithUnderlyingString>& strings, StringView separator, unsigned joinedLength)
+{
+ ASSERT(joinedLength);
- if (stringImpl->is8Bit()) {
- for (unsigned i = 0; i < length; ++i) {
- *data = stringImpl->characters8()[i];
- ++data;
+ CharacterType* data;
+ String result = StringImpl::tryCreateUninitialized(joinedLength, data);
+ if (result.isNull())
+ return result;
+
+ appendStringToData(data, strings[0].view);
+
+ unsigned size = strings.size();
+
+ switch (separator.length()) {
+ case 0:
+ for (unsigned i = 1; i < size; ++i)
+ appendStringToData(data, strings[i].view);
+ break;
+ case 1: {
+ CharacterType separatorCharacter = separator[0];
+ for (unsigned i = 1; i < size; ++i) {
+ *data++ = separatorCharacter;
+ appendStringToData(data, strings[i].view);
}
- } else {
- for (unsigned i = 0; i < length; ++i) {
- *data = stringImpl->characters16()[i];
- ++data;
+ break;
+ }
+ default:
+ for (unsigned i = 1; i < size; ++i) {
+ appendStringToData(data, separator);
+ appendStringToData(data, strings[i].view);
}
}
-}
-
-// If the destination is 8bits, we know every string has to be 8bit.
-static inline void appendStringToData(LChar*& data, const String& string)
-{
- if (string.isNull())
- return;
- ASSERT(string.is8Bit());
+ ASSERT(data == result.characters<CharacterType>() + joinedLength);
- unsigned length = string.length();
- const StringImpl* stringImpl = string.impl();
-
- for (unsigned i = 0; i < length; ++i) {
- *data = stringImpl->characters8()[i];
- ++data;
- }
+ return result;
}
-template<typename CharacterType>
-static inline PassRefPtr<StringImpl> joinStrings(const Vector<String>& strings, const String& separator, unsigned outputLength)
+inline unsigned JSStringJoiner::joinedLength(ExecState& state) const
{
- ASSERT(outputLength);
-
- CharacterType* data;
- RefPtr<StringImpl> outputStringImpl = StringImpl::tryCreateUninitialized(outputLength, data);
- if (!outputStringImpl)
- return PassRefPtr<StringImpl>();
+ unsigned numberOfStrings = m_strings.size();
+ if (!numberOfStrings)
+ return 0;
- const String firstString = strings.first();
- appendStringToData(data, firstString);
+ Checked<unsigned, RecordOverflow> separatorLength = m_separator.length();
+ Checked<unsigned, RecordOverflow> totalSeparatorsLength = separatorLength * (numberOfStrings - 1);
+ Checked<unsigned, RecordOverflow> totalLength = totalSeparatorsLength + m_accumulatedStringsLength;
- for (size_t i = 1; i < strings.size(); ++i) {
- appendStringToData(data, separator);
- appendStringToData(data, strings[i]);
+ unsigned result;
+ if (totalLength.safeGet(result) == CheckedState::DidOverflow) {
+ throwOutOfMemoryError(&state);
+ return 0;
}
-
- ASSERT(data == (outputStringImpl->getCharacters<CharacterType>() + outputStringImpl->length()));
- return outputStringImpl.release();
+ return result;
}
-JSValue JSStringJoiner::join(ExecState* exec)
+JSValue JSStringJoiner::join(ExecState& state)
{
- if (!m_isValid)
- return throwOutOfMemoryError(exec);
+ ASSERT(m_strings.size() <= m_strings.capacity());
- if (!m_strings.size())
- return jsEmptyString(exec);
+ unsigned length = joinedLength(state);
+ if (state.hadException())
+ return jsUndefined();
- Checked<unsigned, RecordOverflow> separatorLength = m_separator.length();
- // FIXME: add special cases of joinStrings() for (separatorLength == 0) and (separatorLength == 1).
- ASSERT(m_strings.size() > 0);
- Checked<unsigned, RecordOverflow> totalSeparactorsLength = separatorLength * (m_strings.size() - 1);
- Checked<unsigned, RecordOverflow> outputStringSize = totalSeparactorsLength + m_accumulatedStringsLength;
-
- unsigned finalSize;
- if (outputStringSize.safeGet(finalSize) == CheckedState::DidOverflow)
- return throwOutOfMemoryError(exec);
-
- if (!outputStringSize)
- return jsEmptyString(exec);
-
- RefPtr<StringImpl> outputStringImpl;
- if (m_is8Bits)
- outputStringImpl = joinStrings<LChar>(m_strings, m_separator, finalSize);
+ if (!length)
+ return jsEmptyString(&state);
+
+ String result;
+ if (m_isAll8Bit)
+ result = joinStrings<LChar>(m_strings, m_separator, length);
else
- outputStringImpl = joinStrings<UChar>(m_strings, m_separator, finalSize);
+ result = joinStrings<UChar>(m_strings, m_separator, length);
- if (!outputStringImpl)
- return throwOutOfMemoryError(exec);
+ if (result.isNull())
+ return throwOutOfMemoryError(&state);
- return JSString::create(exec->vm(), outputStringImpl.release());
+ return jsString(&state, WTFMove(result));
}
}
diff --git a/Source/JavaScriptCore/runtime/JSStringJoiner.h b/Source/JavaScriptCore/runtime/JSStringJoiner.h
index 73950c6d7..255fd3e11 100644
--- a/Source/JavaScriptCore/runtime/JSStringJoiner.h
+++ b/Source/JavaScriptCore/runtime/JSStringJoiner.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-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
@@ -26,49 +26,121 @@
#ifndef JSStringJoiner_h
#define JSStringJoiner_h
+#include "ExceptionHelpers.h"
#include "JSCJSValue.h"
-#include <wtf/Vector.h>
-#include <wtf/text/WTFString.h>
namespace JSC {
-class ExecState;
-
-
class JSStringJoiner {
public:
- JSStringJoiner(const String& separator, size_t stringCount);
+ JSStringJoiner(ExecState&, LChar separator, unsigned stringCount);
+ JSStringJoiner(ExecState&, StringView separator, unsigned stringCount);
- void append(const String&);
- JSValue join(ExecState*);
+ void append(ExecState&, JSValue);
+ bool appendWithoutSideEffects(ExecState&, JSValue);
+ void appendEmptyString();
+
+ JSValue join(ExecState&);
private:
- String m_separator;
- Vector<String> m_strings;
+ void append(StringViewWithUnderlyingString&&);
+ void append8Bit(const String&);
+ void appendLiteral(const Identifier&);
+ unsigned joinedLength(ExecState&) const;
+ LChar m_singleCharacterSeparator;
+ StringView m_separator;
+ Vector<StringViewWithUnderlyingString> m_strings;
Checked<unsigned, RecordOverflow> m_accumulatedStringsLength;
- bool m_isValid;
- bool m_is8Bits;
+ bool m_isAll8Bit { true };
};
-inline JSStringJoiner::JSStringJoiner(const String& separator, size_t stringCount)
+inline JSStringJoiner::JSStringJoiner(ExecState& state, StringView separator, unsigned stringCount)
: m_separator(separator)
- , m_isValid(true)
- , m_is8Bits(m_separator.is8Bit())
+ , m_isAll8Bit(m_separator.is8Bit())
+{
+ if (!m_strings.tryReserveCapacity(stringCount))
+ throwOutOfMemoryError(&state);
+}
+
+inline JSStringJoiner::JSStringJoiner(ExecState& state, LChar separator, unsigned stringCount)
+ : m_singleCharacterSeparator(separator)
+ , m_separator { &m_singleCharacterSeparator, 1 }
+{
+ if (!m_strings.tryReserveCapacity(stringCount))
+ throwOutOfMemoryError(&state);
+}
+
+ALWAYS_INLINE void JSStringJoiner::append(StringViewWithUnderlyingString&& string)
+{
+ m_accumulatedStringsLength += string.view.length();
+ m_isAll8Bit = m_isAll8Bit && string.view.is8Bit();
+ m_strings.uncheckedAppend(WTFMove(string));
+}
+
+ALWAYS_INLINE void JSStringJoiner::append8Bit(const String& string)
+{
+ ASSERT(string.is8Bit());
+ m_accumulatedStringsLength += string.length();
+ m_strings.uncheckedAppend({ string, string });
+}
+
+ALWAYS_INLINE void JSStringJoiner::appendLiteral(const Identifier& literal)
+{
+ m_accumulatedStringsLength += literal.length();
+ ASSERT(literal.string().is8Bit());
+ m_strings.uncheckedAppend({ literal.string(), { } });
+}
+
+ALWAYS_INLINE void JSStringJoiner::appendEmptyString()
{
- ASSERT(!m_separator.isNull());
- m_isValid = m_strings.tryReserveCapacity(stringCount);
+ m_strings.uncheckedAppend({ { }, { } });
}
-inline void JSStringJoiner::append(const String& str)
+ALWAYS_INLINE bool JSStringJoiner::appendWithoutSideEffects(ExecState& state, JSValue value)
{
- if (!m_isValid)
- return;
+ // The following code differs from using the result of JSValue::toString in the following ways:
+ // 1) It's inlined more than JSValue::toString is.
+ // 2) It includes conversion to WTF::String in a way that avoids allocating copies of substrings.
+ // 3) It doesn't create a JSString for numbers, true, or false.
+ // 4) It turns undefined and null into the empty string instead of "undefined" and "null".
+ // 5) It uses optimized code paths for all the cases known to be 8-bit and for the empty string.
+ // If we might make an effectful calls, return false. Otherwise return true.
+
+ if (value.isCell()) {
+ if (!value.asCell()->isString())
+ return false;
+
+ append(asString(value)->viewWithUnderlyingString(state));
+ return true;
+ }
- m_strings.append(str);
- if (!str.isNull()) {
- m_accumulatedStringsLength += str.length();
- m_is8Bits = m_is8Bits && str.is8Bit();
+ if (value.isInt32()) {
+ append8Bit(state.vm().numericStrings.add(value.asInt32()));
+ return true;
+ }
+ if (value.isDouble()) {
+ append8Bit(state.vm().numericStrings.add(value.asDouble()));
+ return true;
+ }
+ if (value.isTrue()) {
+ append8Bit(state.vm().propertyNames->trueKeyword.string());
+ return true;
+ }
+ if (value.isFalse()) {
+ append8Bit(state.vm().propertyNames->falseKeyword.string());
+ return true;
+ }
+ ASSERT(value.isUndefinedOrNull());
+ appendEmptyString();
+ return true;
+}
+
+ALWAYS_INLINE void JSStringJoiner::append(ExecState& state, JSValue value)
+{
+ if (!appendWithoutSideEffects(state, value)) {
+ JSString* jsString = value.toString(&state);
+ append(jsString->viewWithUnderlyingString(state));
}
}
diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
index 2ac2524c5..1e78b7d04 100644
--- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp
@@ -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.
*
@@ -29,10 +29,9 @@
#include "config.h"
#include "JSSymbolTableObject.h"
-#include "JSActivation.h"
#include "JSGlobalObject.h"
-#include "JSNameScope.h"
-#include "Operations.h"
+#include "JSLexicalEnvironment.h"
+#include "JSCInlines.h"
#include "PropertyNameArray.h"
namespace JSC {
@@ -41,9 +40,6 @@ void JSSymbolTableObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSSymbolTableObject* thisObject = jsCast<JSSymbolTableObject*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
Base::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_symbolTable);
}
@@ -51,7 +47,7 @@ void JSSymbolTableObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
bool JSSymbolTableObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
{
JSSymbolTableObject* thisObject = jsCast<JSSymbolTableObject*>(cell);
- if (thisObject->symbolTable()->contains(propertyName.publicName()))
+ if (thisObject->symbolTable()->contains(propertyName.uid()))
return false;
return JSObject::deleteProperty(thisObject, exec, propertyName);
@@ -64,8 +60,11 @@ void JSSymbolTableObject::getOwnNonIndexPropertyNames(JSObject* object, ExecStat
ConcurrentJITLocker locker(thisObject->symbolTable()->m_lock);
SymbolTable::Map::iterator end = thisObject->symbolTable()->end(locker);
for (SymbolTable::Map::iterator it = thisObject->symbolTable()->begin(locker); it != end; ++it) {
- if (!(it->value.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties))
- propertyNames.add(Identifier(exec, it->key.get()));
+ if (!(it->value.getAttributes() & DontEnum) || mode.includeDontEnumProperties()) {
+ if (it->key->isSymbol() && !propertyNames.includeSymbolProperties())
+ continue;
+ propertyNames.add(Identifier::fromUid(exec, it->key.get()));
+ }
}
}
diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h
index b5b20a845..368cedcb8 100644
--- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h
+++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2014, 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
@@ -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.
*
@@ -32,37 +32,47 @@
#include "JSScope.h"
#include "PropertyDescriptor.h"
#include "SymbolTable.h"
+#include "VariableWriteFireDetail.h"
namespace JSC {
+class JSSymbolTableObject;
+
class JSSymbolTableObject : public JSScope {
public:
typedef JSScope Base;
+ static const unsigned StructureFlags = Base::StructureFlags | IsEnvironmentRecord | OverridesGetPropertyNames;
SymbolTable* symbolTable() const { return m_symbolTable.get(); }
JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName);
JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static ptrdiff_t offsetOfSymbolTable() { return OBJECT_OFFSETOF(JSSymbolTableObject, m_symbolTable); }
+
protected:
- static const unsigned StructureFlags = IsEnvironmentRecord | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags;
+ JSSymbolTableObject(VM& vm, Structure* structure, JSScope* scope)
+ : Base(vm, structure, scope)
+ {
+ }
- JSSymbolTableObject(VM& vm, Structure* structure, JSScope* scope, SymbolTable* symbolTable = 0)
+ JSSymbolTableObject(VM& vm, Structure* structure, JSScope* scope, SymbolTable* symbolTable)
: Base(vm, structure, scope)
{
- if (symbolTable)
- m_symbolTable.set(vm, this, symbolTable);
+ ASSERT(symbolTable);
+ setSymbolTable(vm, symbolTable);
}
-
- void finishCreation(VM& vm)
+
+ void setSymbolTable(VM& vm, SymbolTable* symbolTable)
{
- Base::finishCreation(vm);
- if (!m_symbolTable)
- m_symbolTable.set(vm, this, SymbolTable::create(vm));
+ ASSERT(!m_symbolTable);
+ symbolTable->singletonScope()->notifyWrite(vm, this, "Allocated a scope");
+ m_symbolTable.set(vm, this, symbolTable);
}
-
+
static void visitChildren(JSCell*, SlotVisitor&);
-
+
+private:
WriteBarrier<SymbolTable> m_symbolTable;
};
@@ -72,12 +82,18 @@ inline bool symbolTableGet(
{
SymbolTable& symbolTable = *object->symbolTable();
ConcurrentJITLocker locker(symbolTable.m_lock);
- SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName());
+ SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid());
if (iter == symbolTable.end(locker))
return false;
SymbolTableEntry::Fast entry = iter->value;
ASSERT(!entry.isNull());
- slot.setValue(object, entry.getAttributes() | DontDelete, object->registerAt(entry.getIndex()).get());
+
+ ScopeOffset offset = entry.scopeOffset();
+ // Defend against the inspector asking for a var after it has been optimized out.
+ if (!object->isValidScopeOffset(offset))
+ return false;
+
+ slot.setValue(object, entry.getAttributes() | DontDelete, object->variableAt(offset).get());
return true;
}
@@ -87,13 +103,18 @@ inline bool symbolTableGet(
{
SymbolTable& symbolTable = *object->symbolTable();
ConcurrentJITLocker locker(symbolTable.m_lock);
- SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName());
+ SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid());
if (iter == symbolTable.end(locker))
return false;
SymbolTableEntry::Fast entry = iter->value;
ASSERT(!entry.isNull());
- descriptor.setDescriptor(
- object->registerAt(entry.getIndex()).get(), entry.getAttributes() | DontDelete);
+
+ ScopeOffset offset = entry.scopeOffset();
+ // Defend against the inspector asking for a var after it has been optimized out.
+ if (!object->isValidScopeOffset(offset))
+ return false;
+
+ descriptor.setDescriptor(object->variableAt(offset).get(), entry.getAttributes() | DontDelete);
return true;
}
@@ -104,42 +125,64 @@ inline bool symbolTableGet(
{
SymbolTable& symbolTable = *object->symbolTable();
ConcurrentJITLocker locker(symbolTable.m_lock);
- SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName());
+ SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid());
if (iter == symbolTable.end(locker))
return false;
SymbolTableEntry::Fast entry = iter->value;
ASSERT(!entry.isNull());
- slot.setValue(object, entry.getAttributes() | DontDelete, object->registerAt(entry.getIndex()).get());
+
+ ScopeOffset offset = entry.scopeOffset();
+ // Defend against the inspector asking for a var after it has been optimized out.
+ if (!object->isValidScopeOffset(offset))
+ return false;
+
+ slot.setValue(object, entry.getAttributes() | DontDelete, object->variableAt(offset).get());
slotIsWriteable = !entry.isReadOnly();
return true;
}
-template<typename SymbolTableObjectType>
+enum class SymbolTablePutMode {
+ WithAttributes,
+ WithoutAttributes
+};
+
+template<SymbolTablePutMode symbolTablePutMode, typename SymbolTableObjectType>
inline bool symbolTablePut(
- SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value,
- bool shouldThrow)
+ SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes,
+ bool shouldThrowReadOnlyError, bool ignoreReadOnlyErrors, WatchpointSet*& set)
{
- VM& vm = exec->vm();
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object));
-
+
+ VM& vm = exec->vm();
+
WriteBarrierBase<Unknown>* reg;
{
SymbolTable& symbolTable = *object->symbolTable();
- GCSafeConcurrentJITLocker locker(symbolTable.m_lock, exec->vm().heap);
- SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName());
+ // FIXME: This is very suspicious. We shouldn't need a GC-safe lock here.
+ // https://bugs.webkit.org/show_bug.cgi?id=134601
+ GCSafeConcurrentJITLocker locker(symbolTable.m_lock, vm.heap);
+ SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.uid());
if (iter == symbolTable.end(locker))
return false;
bool wasFat;
SymbolTableEntry::Fast fastEntry = iter->value.getFast(wasFat);
ASSERT(!fastEntry.isNull());
- if (fastEntry.isReadOnly()) {
- if (shouldThrow)
+ if (fastEntry.isReadOnly() && !ignoreReadOnlyErrors) {
+ if (shouldThrowReadOnlyError)
throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
return true;
}
- if (VariableWatchpointSet* set = iter->value.watchpointSet())
- set->notifyWrite(value);
- reg = &object->registerAt(fastEntry.getIndex());
+
+ ScopeOffset offset = fastEntry.scopeOffset();
+
+ // Defend against the inspector asking for a var after it has been optimized out.
+ if (!object->isValidScopeOffset(offset))
+ return false;
+
+ set = iter->value.watchpointSet();
+ if (symbolTablePutMode == SymbolTablePutMode::WithAttributes)
+ iter->value.setAttributes(attributes);
+ reg = &object->variableAt(offset);
}
// I'd prefer we not hold lock while executing barriers, since I prefer to reserve
// the right for barriers to be able to trigger GC. And I don't want to hold VM
@@ -149,28 +192,43 @@ inline bool symbolTablePut(
}
template<typename SymbolTableObjectType>
-inline bool symbolTablePutWithAttributes(
- SymbolTableObjectType* object, VM& vm, PropertyName propertyName,
- JSValue value, unsigned attributes)
+inline bool symbolTablePutTouchWatchpointSet(
+ SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value,
+ bool shouldThrowReadOnlyError, bool ignoreReadOnlyErrors)
{
- ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(object));
+ WatchpointSet* set = nullptr;
+ unsigned attributes = 0;
+ bool result = symbolTablePut<SymbolTablePutMode::WithoutAttributes>(object, exec, propertyName, value, attributes, shouldThrowReadOnlyError, ignoreReadOnlyErrors, set);
+ if (set)
+ VariableWriteFireDetail::touch(set, object, propertyName);
+ return result;
+}
- WriteBarrierBase<Unknown>* reg;
- {
- SymbolTable& symbolTable = *object->symbolTable();
- ConcurrentJITLocker locker(symbolTable.m_lock);
- SymbolTable::Map::iterator iter = symbolTable.find(locker, propertyName.publicName());
- if (iter == symbolTable.end(locker))
- return false;
- SymbolTableEntry& entry = iter->value;
- ASSERT(!entry.isNull());
- if (VariableWatchpointSet* set = entry.watchpointSet())
- set->notifyWrite(value);
- entry.setAttributes(attributes);
- reg = &object->registerAt(entry.getIndex());
- }
- reg->set(vm, object, value);
- return true;
+template<typename SymbolTableObjectType>
+inline bool symbolTablePutInvalidateWatchpointSet(
+ SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName, JSValue value,
+ bool shouldThrowReadOnlyError, bool ignoreReadOnlyErrors)
+{
+ WatchpointSet* set = nullptr;
+ unsigned attributes = 0;
+ bool result = symbolTablePut<SymbolTablePutMode::WithoutAttributes>(object, exec, propertyName, value, attributes, shouldThrowReadOnlyError, ignoreReadOnlyErrors, set);
+ if (set)
+ set->invalidate(VariableWriteFireDetail(object, propertyName)); // Don't mess around - if we had found this statically, we would have invalidated it.
+ return result;
+}
+
+template<typename SymbolTableObjectType>
+inline bool symbolTablePutWithAttributesTouchWatchpointSet(
+ SymbolTableObjectType* object, ExecState* exec, PropertyName propertyName,
+ JSValue value, unsigned attributes)
+{
+ WatchpointSet* set = nullptr;
+ bool shouldThrowReadOnlyError = false;
+ bool ignoreReadOnlyErrors = true;
+ bool result = symbolTablePut<SymbolTablePutMode::WithAttributes>(object, exec, propertyName, value, attributes, shouldThrowReadOnlyError, ignoreReadOnlyErrors, set);
+ if (set)
+ VariableWriteFireDetail::touch(set, object, propertyName);
+ return result;
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSTemplateRegistryKey.cpp b/Source/JavaScriptCore/runtime/JSTemplateRegistryKey.cpp
new file mode 100644
index 000000000..e3f3ae990
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSTemplateRegistryKey.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 "JSTemplateRegistryKey.h"
+
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "StructureInlines.h"
+#include "VM.h"
+
+namespace JSC {
+
+const ClassInfo JSTemplateRegistryKey::s_info = { "TemplateRegistryKey", &Base::s_info, nullptr, CREATE_METHOD_TABLE(JSTemplateRegistryKey) };
+
+
+JSTemplateRegistryKey::JSTemplateRegistryKey(VM& vm, const TemplateRegistryKey& templateRegistryKey)
+ : Base(vm, vm.templateRegistryKeyStructure.get())
+ , m_templateRegistryKey(templateRegistryKey)
+{
+}
+
+JSTemplateRegistryKey* JSTemplateRegistryKey::create(VM& vm, const TemplateRegistryKey& templateRegistryKey)
+{
+ JSTemplateRegistryKey* result = new (NotNull, allocateCell<JSTemplateRegistryKey>(vm.heap)) JSTemplateRegistryKey(vm, templateRegistryKey);
+ result->finishCreation(vm);
+ return result;
+}
+
+void JSTemplateRegistryKey::destroy(JSCell* cell)
+{
+ static_cast<JSTemplateRegistryKey*>(cell)->JSTemplateRegistryKey::~JSTemplateRegistryKey();
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NameInstance.h b/Source/JavaScriptCore/runtime/JSTemplateRegistryKey.h
index c3be29a2d..fc6e39286 100644
--- a/Source/JavaScriptCore/runtime/NameInstance.h
+++ b/Source/JavaScriptCore/runtime/JSTemplateRegistryKey.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,55 +23,39 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef NameInstance_h
-#define NameInstance_h
+#ifndef JSTemplateRegistryKey_h
+#define JSTemplateRegistryKey_h
#include "JSDestructibleObject.h"
-#include "PrivateName.h"
+#include "Structure.h"
+#include "TemplateRegistryKey.h"
namespace JSC {
-class NameInstance : public JSDestructibleObject {
+class JSTemplateRegistryKey final : public JSDestructibleObject {
public:
typedef JSDestructibleObject Base;
- DECLARE_INFO;
+ static JSTemplateRegistryKey* create(VM&, const TemplateRegistryKey&);
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(NameInstanceType, StructureFlags), info());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}
- static NameInstance* create(VM& vm, Structure* structure, JSString* nameString)
- {
- NameInstance* name = new (NotNull, allocateCell<NameInstance>(vm.heap)) NameInstance(vm, structure, nameString);
- name->finishCreation(vm);
- return name;
- }
+ DECLARE_INFO;
- const PrivateName& privateName() { return m_privateName; }
- JSString* nameString() { return m_nameString.get(); }
+ const TemplateRegistryKey& templateRegistryKey() const { return m_templateRegistryKey; }
protected:
static void destroy(JSCell*);
- NameInstance(VM&, Structure*, JSString*);
+private:
+ JSTemplateRegistryKey(VM&, const TemplateRegistryKey&);
- void finishCreation(VM& vm)
- {
- Base::finishCreation(vm);
- ASSERT(inherits(info()));
- }
-
- PrivateName m_privateName;
- WriteBarrier<JSString> m_nameString;
+ TemplateRegistryKey m_templateRegistryKey;
};
-inline bool isName(JSValue v)
-{
- return v.isCell() && v.asCell()->structure()->typeInfo().isName();
-}
-
} // namespace JSC
-#endif // NameInstance_h
+#endif // JSTemplateRegistryKey_h
diff --git a/Source/JavaScriptCore/runtime/JSType.h b/Source/JavaScriptCore/runtime/JSType.h
index 10d98d2bd..ec283144f 100644
--- a/Source/JavaScriptCore/runtime/JSType.h
+++ b/Source/JavaScriptCore/runtime/JSType.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2011, 2015-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 Library General Public
@@ -23,47 +23,68 @@
namespace JSC {
-enum JSType {
+enum JSType : uint8_t {
UnspecifiedType,
UndefinedType,
BooleanType,
NumberType,
NullType,
+
+ // The CellType value must come before any JSType that is a JSCell.
+ CellType,
StringType,
- LeafType,
+ SymbolType,
- // The CompoundType value must come before any JSType that may have children.
- CompoundType,
GetterSetterType,
+ CustomGetterSetterType,
APIValueWrapperType,
EvalExecutableType,
ProgramExecutableType,
+ ModuleProgramExecutableType,
FunctionExecutableType,
+ WebAssemblyExecutableType,
UnlinkedFunctionExecutableType,
UnlinkedProgramCodeBlockType,
+ UnlinkedModuleProgramCodeBlockType,
UnlinkedEvalCodeBlockType,
UnlinkedFunctionCodeBlockType,
// The ObjectType value must come before any JSType that is a subclass of JSObject.
ObjectType,
FinalObjectType,
+ JSCalleeType,
JSFunctionType,
- NameInstanceType,
NumberObjectType,
ErrorInstanceType,
- ProxyType,
+ PureForwardingProxyType,
+ ImpureProxyType,
WithScopeType,
+ DirectArgumentsType,
+ ScopedArgumentsType,
+
+ Int8ArrayType,
+ Int16ArrayType,
+ Int32ArrayType,
+ Uint8ArrayType,
+ Uint8ClampedArrayType,
+ Uint16ArrayType,
+ Uint32ArrayType,
+ Float32ArrayType,
+ Float64ArrayType,
+ DataViewType,
- NameScopeObjectType,
- // VariableObjectType must be less than MOST of the types of its subclasses and only its subclasses.
- // We use >=VariableObjectType checks to test for Global & Activation objects, but exclude NameScopes.
- VariableObjectType,
GlobalObjectType,
- ActivationObjectType,
+ ClosureObjectType,
+
+ RegExpObjectType,
+
+ LastJSCObjectType = RegExpObjectType,
};
+COMPILE_ASSERT(sizeof(JSType) == sizeof(uint8_t), sizeof_jstype_is_one_byte);
+
} // namespace JSC
#endif
diff --git a/Source/JavaScriptCore/runtime/JSTypeInfo.h b/Source/JavaScriptCore/runtime/JSTypeInfo.h
index d70d6512e..9ef49bac0 100644
--- a/Source/JavaScriptCore/runtime/JSTypeInfo.h
+++ b/Source/JavaScriptCore/runtime/JSTypeInfo.h
@@ -1,6 +1,6 @@
// -*- mode: c++; c-basic-offset: 4 -*-
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 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
@@ -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
@@ -34,79 +34,86 @@
namespace JSC {
- class LLIntOffsetsExtractor;
-
- static const unsigned MasqueradesAsUndefined = 1; // WebCore uses MasqueradesAsUndefined to make document.all undetectable.
- static const unsigned ImplementsHasInstance = 1 << 1;
- static const unsigned OverridesHasInstance = 1 << 2;
- static const unsigned ImplementsDefaultHasInstance = 1 << 3;
- static const unsigned IsEnvironmentRecord = 1 << 4;
- static const unsigned OverridesGetOwnPropertySlot = 1 << 5;
- static const unsigned InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero = 1 << 6;
- static const unsigned OverridesVisitChildren = 1 << 7;
- static const unsigned OverridesGetPropertyNames = 1 << 8;
- static const unsigned ProhibitsPropertyCaching = 1 << 9;
- static const unsigned HasImpureGetOwnPropertySlot = 1 << 10;
- static const unsigned NewImpurePropertyFiresWatchpoints = 1 << 11;
- static const unsigned StructureHasRareData = 1 << 12;
-
- class TypeInfo {
- public:
- TypeInfo(JSType type, unsigned flags = 0)
- : m_type(type)
- , m_flags(flags & 0xff)
- , m_flags2(flags >> 8)
- {
- ASSERT(static_cast<int>(type) <= 0xff);
- ASSERT(type >= CompoundType || !(flags & OverridesVisitChildren));
- // No object that doesn't ImplementsHasInstance should override it!
- ASSERT((m_flags & (ImplementsHasInstance | OverridesHasInstance)) != OverridesHasInstance);
- // ImplementsDefaultHasInstance means (ImplementsHasInstance & !OverridesHasInstance)
- if ((m_flags & (ImplementsHasInstance | OverridesHasInstance)) == ImplementsHasInstance)
- m_flags |= ImplementsDefaultHasInstance;
- }
-
- JSType type() const { return static_cast<JSType>(m_type); }
- bool isObject() const { return type() >= ObjectType; }
- bool isFinalObject() const { return type() == FinalObjectType; }
- bool isNumberObject() const { return type() == NumberObjectType; }
- bool isName() const { return type() == NameInstanceType; }
-
- unsigned flags() const { return (static_cast<unsigned>(m_flags2) << 8) | static_cast<unsigned>(m_flags); }
- bool masqueradesAsUndefined() const { return isSetOnFlags1(MasqueradesAsUndefined); }
- bool implementsHasInstance() const { return isSetOnFlags1(ImplementsHasInstance); }
- bool isEnvironmentRecord() const { return isSetOnFlags1(IsEnvironmentRecord); }
- bool overridesHasInstance() const { return isSetOnFlags1(OverridesHasInstance); }
- bool implementsDefaultHasInstance() const { return isSetOnFlags1(ImplementsDefaultHasInstance); }
- bool overridesGetOwnPropertySlot() const { return isSetOnFlags1(OverridesGetOwnPropertySlot); }
- bool interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero() const { return isSetOnFlags1(InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero); }
- bool overridesVisitChildren() const { return isSetOnFlags1(OverridesVisitChildren); }
- bool overridesGetPropertyNames() const { return isSetOnFlags2(OverridesGetPropertyNames); }
- bool prohibitsPropertyCaching() const { return isSetOnFlags2(ProhibitsPropertyCaching); }
- bool hasImpureGetOwnPropertySlot() const { return isSetOnFlags2(HasImpureGetOwnPropertySlot); }
- bool newImpurePropertyFiresWatchpoints() const { return isSetOnFlags2(NewImpurePropertyFiresWatchpoints); }
- bool structureHasRareData() const { return isSetOnFlags2(StructureHasRareData); }
-
- static ptrdiff_t flagsOffset()
- {
- return OBJECT_OFFSETOF(TypeInfo, m_flags);
- }
-
- static ptrdiff_t typeOffset()
- {
- return OBJECT_OFFSETOF(TypeInfo, m_type);
- }
-
- private:
- friend class LLIntOffsetsExtractor;
-
- bool isSetOnFlags1(unsigned flag) const { ASSERT(flag <= (1 << 7)); return m_flags & flag; }
- bool isSetOnFlags2(unsigned flag) const { ASSERT(flag >= (1 << 8)); return m_flags2 & (flag >> 8); }
-
- unsigned char m_type;
- unsigned char m_flags;
- unsigned char m_flags2;
- };
+class LLIntOffsetsExtractor;
+
+static const unsigned MasqueradesAsUndefined = 1; // WebCore uses MasqueradesAsUndefined to make document.all undetectable.
+static const unsigned ImplementsDefaultHasInstance = 1 << 1;
+static const unsigned TypeOfShouldCallGetCallData = 1 << 2; // Need this flag if you override getCallData() and you want typeof to use this to determine if it should say "function". Currently we always set this flag when we override getCallData().
+static const unsigned OverridesGetOwnPropertySlot = 1 << 3;
+static const unsigned InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero = 1 << 4;
+static const unsigned StructureIsImmortal = 1 << 5;
+// There are two free bits at the end of the InlineTypeFlags.
+
+static const unsigned ImplementsHasInstance = 1 << 8;
+static const unsigned OverridesGetPropertyNames = 1 << 9;
+static const unsigned ProhibitsPropertyCaching = 1 << 10;
+static const unsigned GetOwnPropertySlotIsImpure = 1 << 11;
+static const unsigned NewImpurePropertyFiresWatchpoints = 1 << 12;
+static const unsigned IsEnvironmentRecord = 1 << 13;
+static const unsigned GetOwnPropertySlotIsImpureForPropertyAbsence = 1 << 14;
+
+class TypeInfo {
+public:
+ typedef uint8_t InlineTypeFlags;
+ typedef uint8_t OutOfLineTypeFlags;
+
+ TypeInfo(JSType type, unsigned flags = 0)
+ : TypeInfo(type, flags & 0xff, flags >> 8)
+ {
+ }
+
+ TypeInfo(JSType type, InlineTypeFlags inlineTypeFlags, OutOfLineTypeFlags outOfLineTypeFlags)
+ : m_type(type)
+ , m_flags(inlineTypeFlags)
+ , m_flags2(outOfLineTypeFlags)
+ {
+ }
+
+ JSType type() const { return static_cast<JSType>(m_type); }
+ bool isObject() const { return isObject(type()); }
+ static bool isObject(JSType type) { return type >= ObjectType; }
+ bool isFinalObject() const { return type() == FinalObjectType; }
+ bool isNumberObject() const { return type() == NumberObjectType; }
+
+ unsigned flags() const { return (static_cast<unsigned>(m_flags2) << 8) | static_cast<unsigned>(m_flags); }
+ bool masqueradesAsUndefined() const { return isSetOnFlags1(MasqueradesAsUndefined); }
+ bool implementsHasInstance() const { return isSetOnFlags2(ImplementsHasInstance); }
+ bool implementsDefaultHasInstance() const { return isSetOnFlags1(ImplementsDefaultHasInstance); }
+ bool typeOfShouldCallGetCallData() const { return isSetOnFlags1(TypeOfShouldCallGetCallData); }
+ bool overridesGetOwnPropertySlot() const { return overridesGetOwnPropertySlot(inlineTypeFlags()); }
+ static bool overridesGetOwnPropertySlot(InlineTypeFlags flags) { return flags & OverridesGetOwnPropertySlot; }
+ bool interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero() const { return isSetOnFlags1(InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero); }
+ bool structureIsImmortal() const { return isSetOnFlags1(StructureIsImmortal); }
+ bool overridesGetPropertyNames() const { return isSetOnFlags2(OverridesGetPropertyNames); }
+ bool prohibitsPropertyCaching() const { return isSetOnFlags2(ProhibitsPropertyCaching); }
+ bool getOwnPropertySlotIsImpure() const { return isSetOnFlags2(GetOwnPropertySlotIsImpure); }
+ bool getOwnPropertySlotIsImpureForPropertyAbsence() const { return isSetOnFlags2(GetOwnPropertySlotIsImpureForPropertyAbsence); }
+ bool newImpurePropertyFiresWatchpoints() const { return isSetOnFlags2(NewImpurePropertyFiresWatchpoints); }
+ bool isEnvironmentRecord() const { return isSetOnFlags2(IsEnvironmentRecord); }
+
+ static ptrdiff_t flagsOffset()
+ {
+ return OBJECT_OFFSETOF(TypeInfo, m_flags);
+ }
+
+ static ptrdiff_t typeOffset()
+ {
+ return OBJECT_OFFSETOF(TypeInfo, m_type);
+ }
+
+ InlineTypeFlags inlineTypeFlags() const { return m_flags; }
+ OutOfLineTypeFlags outOfLineTypeFlags() const { return m_flags2; }
+
+private:
+ friend class LLIntOffsetsExtractor;
+
+ bool isSetOnFlags1(unsigned flag) const { ASSERT(flag <= (1 << 7)); return m_flags & flag; }
+ bool isSetOnFlags2(unsigned flag) const { ASSERT(flag >= (1 << 8)); return m_flags2 & (flag >> 8); }
+
+ unsigned char m_type;
+ unsigned char m_flags;
+ unsigned char m_flags2;
+};
}
diff --git a/Source/JavaScriptCore/runtime/JSTypedArrayConstructors.cpp b/Source/JavaScriptCore/runtime/JSTypedArrayConstructors.cpp
index ec8dff40a..f42f31795 100644
--- a/Source/JavaScriptCore/runtime/JSTypedArrayConstructors.cpp
+++ b/Source/JavaScriptCore/runtime/JSTypedArrayConstructors.cpp
@@ -28,12 +28,12 @@
#include "JSGenericTypedArrayViewConstructorInlines.h"
#include "JSGenericTypedArrayViewInlines.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
#define MAKE_S_INFO(type) \
- template<> const ClassInfo JS##type##Constructor::s_info = {"Function", &JS##type##Constructor::Base::s_info, 0, 0, CREATE_METHOD_TABLE(JS##type##Constructor)}
+ template<> const ClassInfo JS##type##Constructor::s_info = {"Function", &JS##type##Constructor::Base::s_info, 0, CREATE_METHOD_TABLE(JS##type##Constructor)}
MAKE_S_INFO(Int8Array);
MAKE_S_INFO(Int16Array);
diff --git a/Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.cpp b/Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.cpp
index f89a3e276..d9282ead3 100644
--- a/Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.cpp
+++ b/Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.cpp
@@ -27,12 +27,15 @@
#include "JSTypedArrayPrototypes.h"
#include "JSGenericTypedArrayViewPrototypeInlines.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
+const ClassInfo JSTypedArrayViewPrototype::s_info = {"Prototype", &JSTypedArrayViewPrototype::Base::s_info, 0,
+ CREATE_METHOD_TABLE(JSTypedArrayViewPrototype)};
+
#define MAKE_S_INFO(type) \
- template<> const ClassInfo JS##type##Prototype::s_info = {#type "Prototype", &JS##type##Prototype::Base::s_info, 0, 0, CREATE_METHOD_TABLE(JS##type##Prototype)}
+ template<> const ClassInfo JS##type##Prototype::s_info = {#type "Prototype", &JS##type##Prototype::Base::s_info, 0, CREATE_METHOD_TABLE(JS##type##Prototype)}
MAKE_S_INFO(Int8Array);
MAKE_S_INFO(Int16Array);
diff --git a/Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.h b/Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.h
index b0f1c1147..8ede860e5 100644
--- a/Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.h
+++ b/Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.h
@@ -27,6 +27,7 @@
#define JSTypedArrayPrototypes_h
#include "JSGenericTypedArrayViewPrototype.h"
+#include "JSTypedArrayViewPrototype.h"
#include "JSTypedArrays.h"
namespace JSC {
diff --git a/Source/JavaScriptCore/runtime/JSTypedArrayViewConstructor.cpp b/Source/JavaScriptCore/runtime/JSTypedArrayViewConstructor.cpp
new file mode 100644
index 000000000..bf99dbc87
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSTypedArrayViewConstructor.cpp
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "JSTypedArrayViewConstructor.h"
+
+#include "CallFrame.h"
+#include "Error.h"
+#include "GetterSetter.h"
+#include "JSCBuiltins.h"
+#include "JSCellInlines.h"
+#include "JSGenericTypedArrayViewConstructorInlines.h"
+#include "JSObject.h"
+#include "JSTypedArrayViewPrototype.h"
+#include "JSTypedArrays.h"
+
+namespace JSC {
+
+JSTypedArrayViewConstructor::JSTypedArrayViewConstructor(VM& vm, Structure* structure)
+ : Base(vm, structure)
+{
+}
+
+const ClassInfo JSTypedArrayViewConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(JSTypedArrayViewConstructor) };
+
+void JSTypedArrayViewConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, JSTypedArrayViewPrototype* prototype, GetterSetter* speciesSymbol)
+{
+ Base::finishCreation(vm, "TypedArray");
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(3), DontEnum | DontDelete | ReadOnly);
+ putDirectNonIndexAccessor(vm, vm.propertyNames->speciesSymbol, speciesSymbol, Accessor | ReadOnly | DontEnum);
+
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->of, typedArrayConstructorOfCodeGenerator, DontEnum);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->from, typedArrayConstructorFromCodeGenerator, DontEnum);
+}
+
+Structure* JSTypedArrayViewConstructor::createStructure(
+ VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+
+// The only way we can call this function is through Reflect.construct or if they mucked with the TypedArray prototype chain.
+// In either case we are ok with this being slow.
+static EncodedJSValue JSC_HOST_CALL constructTypedArrayView(ExecState* exec)
+{
+ JSValue value = exec->newTarget();
+
+ JSObject* object = jsDynamicCast<JSObject*>(value);
+ if (!object)
+ return JSValue::encode(throwTypeError(exec, "new.target passed to TypedArray is not an object."));
+
+ ConstructData data;
+ if (object->methodTable()->getConstructData(object, data) == ConstructTypeNone)
+ return JSValue::encode(throwTypeError(exec, "new.target passed to TypedArray is not a valid constructor."));
+
+ for (; !value.isNull(); value = jsCast<JSObject*>(value)->prototype()) {
+ if (jsDynamicCast<JSTypedArrayViewConstructor*>(value))
+ return JSValue::encode(throwTypeError(exec, "Unable to find TypedArray constructor that inherits from TypedArray."));
+ if (jsDynamicCast<JSGenericTypedArrayViewConstructor<JSInt8Array>*>(value))
+ return constructGenericTypedArrayView<JSInt8Array>(exec);
+ if (jsDynamicCast<JSGenericTypedArrayViewConstructor<JSInt16Array>*>(value))
+ return constructGenericTypedArrayView<JSInt16Array>(exec);
+ if (jsDynamicCast<JSGenericTypedArrayViewConstructor<JSInt32Array>*>(value))
+ return constructGenericTypedArrayView<JSInt32Array>(exec);
+ if (jsDynamicCast<JSGenericTypedArrayViewConstructor<JSUint8Array>*>(value))
+ return constructGenericTypedArrayView<JSUint8Array>(exec);
+ if (jsDynamicCast<JSGenericTypedArrayViewConstructor<JSUint16Array>*>(value))
+ return constructGenericTypedArrayView<JSUint16Array>(exec);
+ if (jsDynamicCast<JSGenericTypedArrayViewConstructor<JSUint32Array>*>(value))
+ return constructGenericTypedArrayView<JSUint32Array>(exec);
+ if (jsDynamicCast<JSGenericTypedArrayViewConstructor<JSUint8ClampedArray>*>(value))
+ return constructGenericTypedArrayView<JSUint8ClampedArray>(exec);
+ if (jsDynamicCast<JSGenericTypedArrayViewConstructor<JSFloat32Array>*>(value))
+ return constructGenericTypedArrayView<JSFloat32Array>(exec);
+ if (jsDynamicCast<JSGenericTypedArrayViewConstructor<JSFloat64Array>*>(value))
+ return constructGenericTypedArrayView<JSFloat64Array>(exec);
+ }
+
+ return JSValue::encode(throwTypeError(exec, "Unable to find TypedArray constructor in prototype-chain, hit null."));
+}
+
+ConstructType JSTypedArrayViewConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructTypedArrayView;
+ return ConstructTypeHost;
+}
+
+CallType JSTypedArrayViewConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = nullptr;
+ return CallTypeNone;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSTypedArrayViewConstructor.h b/Source/JavaScriptCore/runtime/JSTypedArrayViewConstructor.h
new file mode 100644
index 000000000..259f6ee97
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSTypedArrayViewConstructor.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#ifndef JSTypedArrayViewConstructor_h
+#define JSTypedArrayViewConstructor_h
+
+#include "InternalFunction.h"
+
+namespace JSC {
+
+class JSTypedArrayViewPrototype;
+class GetterSetter;
+
+class JSTypedArrayViewConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+
+protected:
+ JSTypedArrayViewConstructor(VM&, Structure*);
+ void finishCreation(VM&, JSGlobalObject*, JSTypedArrayViewPrototype*, GetterSetter* speciesSymbol);
+
+public:
+ static JSTypedArrayViewConstructor* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, JSTypedArrayViewPrototype* prototype, GetterSetter* speciesSymbol)
+ {
+ JSTypedArrayViewConstructor* result = new (NotNull, allocateCell<JSTypedArrayViewConstructor>(vm.heap)) JSTypedArrayViewConstructor(vm, structure);
+ result->finishCreation(vm, globalObject, prototype, speciesSymbol);
+ return result;
+ }
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+protected:
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+};
+
+
+
+} // namespace JSC
+
+#endif /* JSTypedArrayViewConstructor_h */
diff --git a/Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.cpp b/Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.cpp
new file mode 100644
index 000000000..69d14de31
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.cpp
@@ -0,0 +1,301 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "JSTypedArrayViewPrototype.h"
+
+#include "CallFrame.h"
+#include "GetterSetter.h"
+#include "JSCellInlines.h"
+#include "JSFunction.h"
+#include "JSGenericTypedArrayViewPrototypeFunctions.h"
+#include "TypedArrayAdaptors.h"
+
+namespace JSC {
+
+#define CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(functionName) do { \
+ switch (thisValue.getObject()->classInfo()->typedArrayStorageType) { \
+ case TypeUint8Clamped: \
+ return functionName<JSUint8ClampedArray>(exec); \
+ case TypeInt32: \
+ return functionName<JSInt32Array>(exec); \
+ case TypeUint32: \
+ return functionName<JSUint32Array>(exec); \
+ case TypeFloat64: \
+ return functionName<JSFloat64Array>(exec); \
+ case TypeFloat32: \
+ return functionName<JSFloat32Array>(exec); \
+ case TypeInt8: \
+ return functionName<JSInt8Array>(exec); \
+ case TypeUint8: \
+ return functionName<JSUint8Array>(exec); \
+ case TypeInt16: \
+ return functionName<JSInt16Array>(exec); \
+ case TypeUint16: \
+ return functionName<JSUint16Array>(exec); \
+ case NotTypedArray: \
+ case TypeDataView: \
+ return throwVMError(exec, createTypeError(exec, \
+ "Receiver should be a typed array view")); \
+ } \
+ RELEASE_ASSERT_NOT_REACHED(); \
+} while (false)
+
+EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncLength(ExecState* exec)
+{
+ JSArrayBufferView* thisObject = jsDynamicCast<JSArrayBufferView*>(exec->argument(0));
+ if (!thisObject)
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view"));
+ if (thisObject->isNeutered())
+ return throwVMTypeError(exec, "Underlying ArrayBuffer has been detached from the view");
+
+ return JSValue::encode(jsNumber(thisObject->length()));
+}
+
+EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncSort(ExecState* exec)
+{
+ JSValue thisValue = exec->argument(0);
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewPrivateFuncSort);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncSet(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncSet);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncEntries(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncEntries);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncCopyWithin(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncCopyWithin);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncFill(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncFill);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncLastIndexOf(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncLastIndexOf);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncIndexOf(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncIndexOf);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncJoin(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncJoin);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncKeys(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncKeys);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoGetterFuncLength(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoGetterFuncLength);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoGetterFuncByteLength(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoGetterFuncByteLength);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoGetterFuncByteOffset(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoGetterFuncByteOffset);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncReverse(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncReverse);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncSubarray(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncSubarray);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncSlice(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(genericTypedArrayViewProtoFuncSlice);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoFuncValues(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+ CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION(typedArrayViewProtoFuncValues);
+}
+
+static EncodedJSValue JSC_HOST_CALL typedArrayViewProtoGetterFuncToStringTag(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view but was not an object"));
+
+ VM& vm = exec->vm();
+ switch (thisValue.getObject()->classInfo()->typedArrayStorageType) {
+ case TypeUint8Clamped:
+ return JSValue::encode(jsString(&vm, "Uint8ClampedArray"));
+ case TypeInt32:
+ return JSValue::encode(jsString(&vm, "Int32Array"));
+ case TypeUint32:
+ return JSValue::encode(jsString(&vm, "Uint32Array"));
+ case TypeFloat64:
+ return JSValue::encode(jsString(&vm, "Float64Array"));
+ case TypeFloat32:
+ return JSValue::encode(jsString(&vm, "Float32Array"));
+ case TypeInt8:
+ return JSValue::encode(jsString(&vm, "Int8Array"));
+ case TypeUint8:
+ return JSValue::encode(jsString(&vm, "Uint8Array"));
+ case TypeInt16:
+ return JSValue::encode(jsString(&vm, "Int16Array"));
+ case TypeUint16:
+ return JSValue::encode(jsString(&vm, "Uint16Array"));
+ case NotTypedArray:
+ case TypeDataView:
+ return throwVMError(exec, createTypeError(exec, "Receiver should be a typed array view"));
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+
+#undef CALL_GENERIC_TYPEDARRAY_PROTOTYPE_FUNCTION
+
+JSTypedArrayViewPrototype::JSTypedArrayViewPrototype(VM& vm, Structure* structure)
+ : Base(vm, structure)
+{
+}
+
+void JSTypedArrayViewPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+
+ ASSERT(inherits(info()));
+
+ JSC_NATIVE_INTRINSIC_GETTER(vm.propertyNames->byteLength, typedArrayViewProtoGetterFuncByteLength, DontEnum | ReadOnly | DontDelete, TypedArrayByteLengthIntrinsic);
+ JSC_NATIVE_INTRINSIC_GETTER(vm.propertyNames->byteOffset, typedArrayViewProtoGetterFuncByteOffset, DontEnum | ReadOnly | DontDelete, TypedArrayByteOffsetIntrinsic);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("copyWithin", typedArrayViewProtoFuncCopyWithin, DontEnum, 2);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("every", typedArrayPrototypeEveryCodeGenerator, DontEnum);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("filter", typedArrayPrototypeFilterCodeGenerator, DontEnum);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("sort", typedArrayPrototypeSortCodeGenerator, DontEnum);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->entries, typedArrayViewProtoFuncEntries, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("fill", typedArrayViewProtoFuncFill, DontEnum, 1);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("find", typedArrayPrototypeFindCodeGenerator, DontEnum);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("findIndex", typedArrayPrototypeFindIndexCodeGenerator, DontEnum);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->forEach, typedArrayPrototypeForEachCodeGenerator, DontEnum);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("indexOf", typedArrayViewProtoFuncIndexOf, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->join, typedArrayViewProtoFuncJoin, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->keys, typedArrayViewProtoFuncKeys, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("lastIndexOf", typedArrayViewProtoFuncLastIndexOf, DontEnum, 1);
+ JSC_NATIVE_INTRINSIC_GETTER(vm.propertyNames->length, typedArrayViewProtoGetterFuncLength, DontEnum | ReadOnly | DontDelete, TypedArrayLengthIntrinsic);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("map", typedArrayPrototypeMapCodeGenerator, DontEnum);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("reduce", typedArrayPrototypeReduceCodeGenerator, DontEnum);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("reduceRight", typedArrayPrototypeReduceRightCodeGenerator, DontEnum);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("reverse", typedArrayViewProtoFuncReverse, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->set, typedArrayViewProtoFuncSet, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->slice, typedArrayViewProtoFuncSlice, DontEnum, 2);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("some", typedArrayPrototypeSomeCodeGenerator, DontEnum);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->subarray, typedArrayViewProtoFuncSubarray, DontEnum, 2);
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toLocaleString, typedArrayPrototypeToLocaleStringCodeGenerator, DontEnum);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toString, arrayProtoFuncToString, DontEnum, 0);
+ JSC_NATIVE_GETTER(vm.propertyNames->toStringTagSymbol, typedArrayViewProtoGetterFuncToStringTag, DontEnum | ReadOnly);
+
+ JSFunction* valuesFunction = JSFunction::create(vm, globalObject, 0, vm.propertyNames->values.string(), typedArrayViewProtoFuncValues);
+
+ putDirectWithoutTransition(vm, vm.propertyNames->values, valuesFunction, DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, valuesFunction, DontEnum);
+
+}
+
+JSTypedArrayViewPrototype* JSTypedArrayViewPrototype::create(
+ VM& vm, JSGlobalObject* globalObject, Structure* structure)
+{
+ JSTypedArrayViewPrototype* prototype =
+ new (NotNull, allocateCell<JSTypedArrayViewPrototype>(vm.heap))
+ JSTypedArrayViewPrototype(vm, structure);
+ prototype->finishCreation(vm, globalObject);
+ return prototype;
+}
+
+Structure* JSTypedArrayViewPrototype::createStructure(
+ VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.h b/Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.h
new file mode 100644
index 000000000..ad9df601c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef JSTypedArrayViewPrototype_h
+#define JSTypedArrayViewPrototype_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class JSTypedArrayViewPrototype : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+
+protected:
+ JSTypedArrayViewPrototype(VM&, Structure*);
+ void finishCreation(VM&, JSGlobalObject*);
+
+public:
+ static JSTypedArrayViewPrototype* create(VM&, JSGlobalObject*, Structure*);
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+};
+
+EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncSort(ExecState*);
+EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncLength(ExecState*);
+
+
+} // namespace JSC
+
+#endif /* JSTypedArrayViewPrototype_h */
diff --git a/Source/JavaScriptCore/runtime/JSTypedArrays.cpp b/Source/JavaScriptCore/runtime/JSTypedArrays.cpp
index d9f8cffa6..3a469ad78 100644
--- a/Source/JavaScriptCore/runtime/JSTypedArrays.cpp
+++ b/Source/JavaScriptCore/runtime/JSTypedArrays.cpp
@@ -26,16 +26,17 @@
#include "config.h"
#include "JSTypedArrays.h"
+#include "CopiedBlockInlines.h"
#include "CopyVisitorInlines.h"
#include "GenericTypedArrayViewInlines.h"
#include "JSGenericTypedArrayViewInlines.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
#define MAKE_S_INFO(type) \
template<> const ClassInfo JS##type##Array::s_info = { \
- #type "Array", &JS##type##Array::Base::s_info, 0, 0, \
+ #type "Array", &JS##type##Array::Base::s_info, 0, \
CREATE_METHOD_TABLE(JS##type##Array) \
}; \
const ClassInfo* get##type##ArrayClassInfo() { return &JS##type##Array::s_info; }
diff --git a/Source/JavaScriptCore/runtime/JSWeakMap.cpp b/Source/JavaScriptCore/runtime/JSWeakMap.cpp
index 049686df2..0e4e657c2 100644
--- a/Source/JavaScriptCore/runtime/JSWeakMap.cpp
+++ b/Source/JavaScriptCore/runtime/JSWeakMap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple, Inc. All rights reserved.
+ * Copyright (C) 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,11 +28,13 @@
#include "JSCJSValueInlines.h"
#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
#include "WeakMapData.h"
+#include "WriteBarrierInlines.h"
namespace JSC {
-const ClassInfo JSWeakMap::s_info = { "WeakMap", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSWeakMap) };
+const ClassInfo JSWeakMap::s_info = { "WeakMap", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWeakMap) };
void JSWeakMap::finishCreation(VM& vm)
{
diff --git a/Source/JavaScriptCore/runtime/JSWeakMap.h b/Source/JavaScriptCore/runtime/JSWeakMap.h
index 81b3962de..a3229c265 100644
--- a/Source/JavaScriptCore/runtime/JSWeakMap.h
+++ b/Source/JavaScriptCore/runtime/JSWeakMap.h
@@ -65,8 +65,6 @@ public:
void clear(CallFrame*);
private:
- static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
-
JSWeakMap(VM& vm, Structure* structure)
: Base(vm, structure)
{
diff --git a/Source/JavaScriptCore/runtime/SetIteratorConstructor.cpp b/Source/JavaScriptCore/runtime/JSWeakSet.cpp
index c16ff9bed..82c22ea44 100644
--- a/Source/JavaScriptCore/runtime/SetIteratorConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/JSWeakSet.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple, Inc. All rights reserved.
+ * 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
@@ -24,22 +24,29 @@
*/
#include "config.h"
-#include "SetIteratorConstructor.h"
+#include "JSWeakSet.h"
#include "JSCJSValueInlines.h"
-#include "JSCellInlines.h"
-#include "JSGlobalObject.h"
-#include "JSSetIterator.h"
-#include "SetIteratorPrototype.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+#include "WeakMapData.h"
+#include "WriteBarrierInlines.h"
namespace JSC {
-const ClassInfo SetIteratorConstructor::s_info = { "Set Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(SetIteratorConstructor) };
+const ClassInfo JSWeakSet::s_info = { "WeakSet", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWeakSet) };
-void SetIteratorConstructor::finishCreation(VM& vm, SetIteratorPrototype* prototype)
+void JSWeakSet::finishCreation(VM& vm)
{
Base::finishCreation(vm);
- putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly);
+ m_weakMapData.set(vm, this, WeakMapData::create(vm));
+}
+
+void JSWeakSet::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ Base::visitChildren(cell, visitor);
+ JSWeakSet* thisObj = jsCast<JSWeakSet*>(cell);
+ visitor.append(&thisObj->m_weakMapData);
}
}
diff --git a/Source/JavaScriptCore/runtime/JSWeakSet.h b/Source/JavaScriptCore/runtime/JSWeakSet.h
new file mode 100644
index 000000000..da2ecaa4a
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSWeakSet.h
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+#ifndef JSWeakSet_h
+#define JSWeakSet_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class WeakMapData;
+
+class JSWeakSet : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+
+ DECLARE_EXPORT_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ static JSWeakSet* create(VM& vm, Structure* structure)
+ {
+ JSWeakSet* instance = new (NotNull, allocateCell<JSWeakSet>(vm.heap)) JSWeakSet(vm, structure);
+ instance->finishCreation(vm);
+ return instance;
+ }
+
+ static JSWeakSet* create(ExecState* exec, Structure* structure)
+ {
+ return create(exec->vm(), structure);
+ }
+
+ WeakMapData* weakMapData() { return m_weakMapData.get(); }
+
+ JSValue get(CallFrame*, JSObject*);
+ bool has(CallFrame*, JSObject*);
+ bool remove(CallFrame*, JSObject*);
+
+ void set(CallFrame*, JSObject*, JSValue);
+ void clear(CallFrame*);
+
+private:
+ JSWeakSet(VM& vm, Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ void finishCreation(VM&);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ WriteBarrier<WeakMapData> m_weakMapData;
+};
+
+}
+
+#endif // !defined(JSWeakSet_h)
diff --git a/Source/JavaScriptCore/runtime/JSWithScope.cpp b/Source/JavaScriptCore/runtime/JSWithScope.cpp
index 82f2e210f..1ffe8d1f2 100644
--- a/Source/JavaScriptCore/runtime/JSWithScope.cpp
+++ b/Source/JavaScriptCore/runtime/JSWithScope.cpp
@@ -26,19 +26,16 @@
#include "config.h"
#include "JSWithScope.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
-const ClassInfo JSWithScope::s_info = { "WithScope", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSWithScope) };
+const ClassInfo JSWithScope::s_info = { "WithScope", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWithScope) };
void JSWithScope::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSWithScope* thisObject = jsCast<JSWithScope*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
Base::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_object);
}
diff --git a/Source/JavaScriptCore/runtime/JSWithScope.h b/Source/JavaScriptCore/runtime/JSWithScope.h
index 9b7e1826d..8e5d09fa1 100644
--- a/Source/JavaScriptCore/runtime/JSWithScope.h
+++ b/Source/JavaScriptCore/runtime/JSWithScope.h
@@ -34,13 +34,6 @@ class JSWithScope : public JSScope {
public:
typedef JSScope Base;
- static JSWithScope* create(ExecState* exec, JSObject* object)
- {
- JSWithScope* withScope = new (NotNull, allocateCell<JSWithScope>(*exec->heap())) JSWithScope(exec, object);
- withScope->finishCreation(exec->vm());
- return withScope;
- }
-
static JSWithScope* create(ExecState* exec, JSObject* object, JSScope* next)
{
JSWithScope* withScope = new (NotNull, allocateCell<JSWithScope>(*exec->heap())) JSWithScope(exec, object, next);
@@ -59,20 +52,7 @@ public:
DECLARE_EXPORT_INFO;
-protected:
- static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
-
private:
- JSWithScope(ExecState* exec, JSObject* object)
- : Base(
- exec->vm(),
- exec->lexicalGlobalObject()->withScopeStructure(),
- exec->scope()
- )
- , m_object(exec->vm(), this, object)
- {
- }
-
JSWithScope(ExecState* exec, JSObject* object, JSScope* next)
: Base(
exec->vm(),
diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.cpp b/Source/JavaScriptCore/runtime/JSWrapperObject.cpp
index 3853207ff..b6fadadb0 100644
--- a/Source/JavaScriptCore/runtime/JSWrapperObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSWrapperObject.cpp
@@ -22,7 +22,7 @@
#include "config.h"
#include "JSWrapperObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
@@ -32,9 +32,6 @@ void JSWrapperObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSWrapperObject* thisObject = jsCast<JSWrapperObject*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
JSObject::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_internalValue);
}
diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.h b/Source/JavaScriptCore/runtime/JSWrapperObject.h
index 349c75e6a..1036add59 100644
--- a/Source/JavaScriptCore/runtime/JSWrapperObject.h
+++ b/Source/JavaScriptCore/runtime/JSWrapperObject.h
@@ -26,62 +26,61 @@
namespace JSC {
- // This class is used as a base for classes such as String,
- // Number, Boolean and Date which are wrappers for primitive types.
- class JSWrapperObject : public JSDestructibleObject {
- public:
- typedef JSDestructibleObject Base;
-
- static size_t allocationSize(size_t inlineCapacity)
- {
- ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
- return sizeof(JSWrapperObject);
- }
-
- JSValue internalValue() const;
- void setInternalValue(VM&, JSValue);
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
-
- static ptrdiff_t internalValueOffset() { return OBJECT_OFFSETOF(JSWrapperObject, m_internalValue); }
- static ptrdiff_t internalValueCellOffset()
- {
+// This class is used as a base for classes such as String,
+// Number, Boolean and Date which are wrappers for primitive types.
+class JSWrapperObject : public JSDestructibleObject {
+public:
+ typedef JSDestructibleObject Base;
+
+ static size_t allocationSize(size_t inlineCapacity)
+ {
+ ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
+ return sizeof(JSWrapperObject);
+ }
+
+ JSValue internalValue() const;
+ void setInternalValue(VM&, JSValue);
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ static ptrdiff_t internalValueOffset() { return OBJECT_OFFSETOF(JSWrapperObject, m_internalValue); }
+ static ptrdiff_t internalValueCellOffset()
+ {
#if USE(JSVALUE64)
- return internalValueOffset();
+ return internalValueOffset();
#else
- return internalValueOffset() + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload);
+ return internalValueOffset() + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload);
#endif
- }
+ }
- protected:
- explicit JSWrapperObject(VM&, Structure*);
- static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
+protected:
+ explicit JSWrapperObject(VM&, Structure*);
- static void visitChildren(JSCell*, SlotVisitor&);
+ JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
- private:
- WriteBarrier<Unknown> m_internalValue;
- };
+private:
+ WriteBarrier<Unknown> m_internalValue;
+};
- inline JSWrapperObject::JSWrapperObject(VM& vm, Structure* structure)
- : JSDestructibleObject(vm, structure)
- {
- }
+inline JSWrapperObject::JSWrapperObject(VM& vm, Structure* structure)
+ : JSDestructibleObject(vm, structure)
+{
+}
- inline JSValue JSWrapperObject::internalValue() const
- {
- return m_internalValue.get();
- }
+inline JSValue JSWrapperObject::internalValue() const
+{
+ return m_internalValue.get();
+}
- inline void JSWrapperObject::setInternalValue(VM& vm, JSValue value)
- {
- ASSERT(value);
- ASSERT(!value.isObject());
- m_internalValue.set(vm, this, value);
- }
+inline void JSWrapperObject::setInternalValue(VM& vm, JSValue value)
+{
+ ASSERT(value);
+ ASSERT(!value.isObject());
+ m_internalValue.set(vm, this, value);
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/LiteralParser.cpp b/Source/JavaScriptCore/runtime/LiteralParser.cpp
index 21f6cc301..f55498381 100644
--- a/Source/JavaScriptCore/runtime/LiteralParser.cpp
+++ b/Source/JavaScriptCore/runtime/LiteralParser.cpp
@@ -28,12 +28,13 @@
#include "LiteralParser.h"
#include "ButterflyInlines.h"
+#include "CodeBlock.h"
#include "CopiedSpaceInlines.h"
#include "JSArray.h"
#include "JSString.h"
#include "Lexer.h"
#include "ObjectConstructor.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "StrongInlines.h"
#include <wtf/ASCIICType.h>
#include <wtf/dtoa.h>
@@ -57,20 +58,20 @@ bool LiteralParser<CharType>::tryJSONPParse(Vector<JSONPData>& results, bool nee
do {
Vector<JSONPPathEntry> path;
// Unguarded next to start off the lexer
- Identifier name = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
+ Identifier name = Identifier::fromString(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
JSONPPathEntry entry;
if (name == m_exec->vm().propertyNames->varKeyword) {
if (m_lexer.next() != TokIdentifier)
return false;
entry.m_type = JSONPPathEntryTypeDeclare;
- entry.m_pathEntryName = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
+ entry.m_pathEntryName = Identifier::fromString(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
path.append(entry);
} else {
entry.m_type = JSONPPathEntryTypeDot;
- entry.m_pathEntryName = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
+ entry.m_pathEntryName = Identifier::fromString(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
path.append(entry);
}
- if (m_exec->vm().keywords->isKeyword(entry.m_pathEntryName))
+ if (isLexerKeyword(entry.m_pathEntryName))
return false;
TokenType tokenType = m_lexer.next();
if (entry.m_type == JSONPPathEntryTypeDeclare && tokenType != TokAssign)
@@ -94,7 +95,7 @@ bool LiteralParser<CharType>::tryJSONPParse(Vector<JSONPData>& results, bool nee
entry.m_type = JSONPPathEntryTypeDot;
if (m_lexer.next() != TokIdentifier)
return false;
- entry.m_pathEntryName = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
+ entry.m_pathEntryName = Identifier::fromString(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
break;
}
case TokLParen: {
@@ -135,17 +136,17 @@ ALWAYS_INLINE const Identifier LiteralParser<CharType>::makeIdentifier(const LCh
if (!length)
return m_exec->vm().propertyNames->emptyIdentifier;
if (characters[0] >= MaximumCachableCharacter)
- return Identifier(&m_exec->vm(), characters, length);
+ return Identifier::fromString(&m_exec->vm(), characters, length);
if (length == 1) {
if (!m_shortIdentifiers[characters[0]].isNull())
return m_shortIdentifiers[characters[0]];
- m_shortIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length);
+ m_shortIdentifiers[characters[0]] = Identifier::fromString(&m_exec->vm(), characters, length);
return m_shortIdentifiers[characters[0]];
}
if (!m_recentIdentifiers[characters[0]].isNull() && Identifier::equal(m_recentIdentifiers[characters[0]].impl(), characters, length))
return m_recentIdentifiers[characters[0]];
- m_recentIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length);
+ m_recentIdentifiers[characters[0]] = Identifier::fromString(&m_exec->vm(), characters, length);
return m_recentIdentifiers[characters[0]];
}
@@ -155,17 +156,17 @@ ALWAYS_INLINE const Identifier LiteralParser<CharType>::makeIdentifier(const UCh
if (!length)
return m_exec->vm().propertyNames->emptyIdentifier;
if (characters[0] >= MaximumCachableCharacter)
- return Identifier(&m_exec->vm(), characters, length);
+ return Identifier::fromString(&m_exec->vm(), characters, length);
if (length == 1) {
if (!m_shortIdentifiers[characters[0]].isNull())
return m_shortIdentifiers[characters[0]];
- m_shortIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length);
+ m_shortIdentifiers[characters[0]] = Identifier::fromString(&m_exec->vm(), characters, length);
return m_shortIdentifiers[characters[0]];
}
if (!m_recentIdentifiers[characters[0]].isNull() && Identifier::equal(m_recentIdentifiers[characters[0]].impl(), characters, length))
return m_recentIdentifiers[characters[0]];
- m_recentIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length);
+ m_recentIdentifiers[characters[0]] = Identifier::fromString(&m_exec->vm(), characters, length);
return m_recentIdentifiers[characters[0]];
}
@@ -281,7 +282,7 @@ template <ParserMode mode> TokenType LiteralParser<CharType>::Lexer::lex(Literal
return lexString<mode, '\''>(token);
}
}
- m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr).impl();
+ m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr);
return TokError;
}
@@ -406,7 +407,7 @@ template <ParserMode mode, char terminator> ALWAYS_INLINE TokenType LiteralParse
} // uNNNN == 5 characters
for (int i = 1; i < 5; i++) {
if (!isASCIIHexDigit(m_ptr[i])) {
- m_lexErrorMessage = String::format("\"\\%s\" is not a valid unicode escape", String(m_ptr, 5).ascii().data()).impl();
+ m_lexErrorMessage = String::format("\"\\%s\" is not a valid unicode escape", String(m_ptr, 5).ascii().data());
return TokError;
}
}
@@ -420,7 +421,7 @@ template <ParserMode mode, char terminator> ALWAYS_INLINE TokenType LiteralParse
m_ptr++;
break;
}
- m_lexErrorMessage = String::format("Invalid escape character %c", *m_ptr).impl();
+ m_lexErrorMessage = String::format("Invalid escape character %c", *m_ptr);
return TokError;
}
}
@@ -497,7 +498,7 @@ TokenType LiteralParser<CharType>::Lexer::lexNumber(LiteralParserToken<CharType>
while (m_ptr < m_end && isASCIIDigit(*m_ptr))
++m_ptr;
} else if (m_ptr < m_end && (*m_ptr != 'e' && *m_ptr != 'E') && (m_ptr - token.start) < 10) {
- int result = 0;
+ double result = 0;
token.type = TokNumber;
token.end = m_ptr;
const CharType* digit = token.start;
@@ -548,6 +549,7 @@ JSValue LiteralParser<CharType>::parse(ParserState initialState)
JSValue lastValue;
Vector<ParserState, 16, UnsafeVectorOverflow> stateStack;
Vector<Identifier, 16, UnsafeVectorOverflow> identifierStack;
+ HashSet<JSObject*> visitedUnderscoreProto;
while (1) {
switch(state) {
startParseArray:
@@ -649,11 +651,20 @@ JSValue LiteralParser<CharType>::parse(ParserState initialState)
{
JSObject* object = asObject(objectStack.last());
PropertyName ident = identifierStack.last();
- unsigned i = ident.asIndex();
- if (i != PropertyName::NotAnIndex)
- object->putDirectIndex(m_exec, i, lastValue);
- else
- object->putDirect(m_exec->vm(), ident, lastValue);
+ if (m_mode != StrictJSON && ident == m_exec->vm().propertyNames->underscoreProto) {
+ if (!visitedUnderscoreProto.add(object).isNewEntry) {
+ m_parseErrorMessage = ASCIILiteral("Attempted to redefine __proto__ property");
+ return JSValue();
+ }
+ CodeBlock* codeBlock = m_exec->codeBlock();
+ PutPropertySlot slot(object, codeBlock ? codeBlock->isStrictMode() : false);
+ objectStack.last().put(m_exec, ident, lastValue, slot);
+ } else {
+ if (Optional<uint32_t> index = parseIndex(ident))
+ object->putDirectIndex(m_exec, index.value(), lastValue);
+ else
+ object->putDirect(m_exec->vm(), ident, lastValue);
+ }
identifierStack.removeLast();
if (m_lexer.currentToken().type == TokComma)
goto doParseObjectStartExpression;
@@ -711,9 +722,9 @@ JSValue LiteralParser<CharType>::parse(ParserState initialState)
case TokIdentifier: {
const LiteralParserToken<CharType>& token = m_lexer.currentToken();
if (token.stringIs8Bit)
- m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken8, m_lexer.currentToken().stringLength).ascii().data()).impl();
+ m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken8, m_lexer.currentToken().stringLength).ascii().data());
else
- m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken16, m_lexer.currentToken().stringLength).ascii().data()).impl();
+ m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken16, m_lexer.currentToken().stringLength).ascii().data());
return JSValue();
}
case TokColon:
diff --git a/Source/JavaScriptCore/runtime/LiteralParser.h b/Source/JavaScriptCore/runtime/LiteralParser.h
index f05f03204..fcb79fa40 100644
--- a/Source/JavaScriptCore/runtime/LiteralParser.h
+++ b/Source/JavaScriptCore/runtime/LiteralParser.h
@@ -98,9 +98,9 @@ public:
String getErrorMessage()
{
if (!m_lexer.getErrorMessage().isEmpty())
- return String::format("JSON Parse error: %s", m_lexer.getErrorMessage().ascii().data()).impl();
+ return String::format("JSON Parse error: %s", m_lexer.getErrorMessage().ascii().data());
if (!m_parseErrorMessage.isEmpty())
- return String::format("JSON Parse error: %s", m_parseErrorMessage.ascii().data()).impl();
+ return String::format("JSON Parse error: %s", m_parseErrorMessage.ascii().data());
return ASCIILiteral("JSON Parse error: Unable to parse JSON string");
}
diff --git a/Source/JavaScriptCore/runtime/Lookup.cpp b/Source/JavaScriptCore/runtime/Lookup.cpp
index a806dd052..dcee6ba58 100644
--- a/Source/JavaScriptCore/runtime/Lookup.cpp
+++ b/Source/JavaScriptCore/runtime/Lookup.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2012, 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
@@ -21,56 +21,34 @@
#include "Lookup.h"
#include "Executable.h"
+#include "GetterSetter.h"
#include "JSFunction.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
-void HashTable::createTable(VM& vm) const
+void reifyStaticAccessor(VM& vm, const HashTableValue& value, JSObject& thisObj, PropertyName propertyName)
{
- ASSERT(!table);
- int linkIndex = compactHashSizeMask + 1;
- HashEntry* entries = new HashEntry[compactSize];
- for (int i = 0; i < compactSize; ++i)
- entries[i].setKey(0);
- for (int i = 0; values[i].key; ++i) {
- StringImpl* identifier = Identifier::add(&vm, values[i].key).leakRef();
- int hashIndex = identifier->existingHash() & compactHashSizeMask;
- HashEntry* entry = &entries[hashIndex];
-
- if (entry->key()) {
- while (entry->next()) {
- entry = entry->next();
- }
- ASSERT(linkIndex < compactSize);
- entry->setNext(&entries[linkIndex++]);
- entry = entry->next();
- }
-
- entry->initialize(identifier, values[i].attributes, values[i].value1, values[i].value2, values[i].intrinsic);
+ JSGlobalObject* globalObject = thisObj.globalObject();
+ GetterSetter* accessor = GetterSetter::create(vm, globalObject);
+ if (value.accessorGetter()) {
+ String getterName = WTF::tryMakeString(ASCIILiteral("get "), String(*propertyName.publicName()));
+ if (!getterName)
+ return;
+ accessor->setGetter(vm, globalObject, value.attributes() & Builtin
+ ? JSFunction::createBuiltinFunction(vm, value.builtinAccessorGetterGenerator()(vm), globalObject, getterName)
+ : JSFunction::create(vm, globalObject, 0, getterName, value.accessorGetter()));
}
- table = entries;
+ thisObj.putDirectNonIndexAccessor(vm, propertyName, accessor, attributesForStructure(value.attributes()));
}
-void HashTable::deleteTable() const
-{
- if (table) {
- int max = compactSize;
- for (int i = 0; i != max; ++i) {
- if (StringImpl* key = table[i].key())
- key->deref();
- }
- delete [] table;
- table = 0;
- }
-}
-
-bool setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot)
+bool setUpStaticFunctionSlot(ExecState* exec, const HashTableValue* entry, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot)
{
ASSERT(thisObj->globalObject());
- ASSERT(entry->attributes() & Function);
+ ASSERT(entry->attributes() & BuiltinOrFunctionOrAccessor);
VM& vm = exec->vm();
unsigned attributes;
+ bool isAccessor = entry->attributes() & Accessor;
PropertyOffset offset = thisObj->getDirectOffset(vm, propertyName, attributes);
if (!isValidOffset(offset)) {
@@ -78,15 +56,26 @@ bool setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject*
// all static functions at that time - after this we shouldn't be re-adding anything.
if (thisObj->staticFunctionsReified())
return false;
-
- thisObj->putDirectNativeFunction(
- vm, thisObj->globalObject(), propertyName, entry->functionLength(),
- entry->function(), entry->intrinsic(), entry->attributes());
+
+ if (entry->attributes() & Builtin)
+ thisObj->putDirectBuiltinFunction(vm, thisObj->globalObject(), propertyName, entry->builtinGenerator()(vm), attributesForStructure(entry->attributes()));
+ else if (entry->attributes() & Function) {
+ thisObj->putDirectNativeFunction(
+ vm, thisObj->globalObject(), propertyName, entry->functionLength(),
+ entry->function(), entry->intrinsic(), attributesForStructure(entry->attributes()));
+ } else {
+ ASSERT(isAccessor);
+ reifyStaticAccessor(vm, *entry, *thisObj, propertyName);
+ }
+
offset = thisObj->getDirectOffset(vm, propertyName, attributes);
ASSERT(isValidOffset(offset));
}
- slot.setValue(thisObj, attributes, thisObj->getDirect(offset), offset);
+ if (isAccessor)
+ slot.setCacheableGetterSlot(thisObj, attributes, jsCast<GetterSetter*>(thisObj->getDirect(offset)), offset);
+ else
+ slot.setValue(thisObj, attributes, thisObj->getDirect(offset), offset);
return true;
}
diff --git a/Source/JavaScriptCore/runtime/Lookup.h b/Source/JavaScriptCore/runtime/Lookup.h
index bde83d4a6..0bf9d2e9b 100644
--- a/Source/JavaScriptCore/runtime/Lookup.h
+++ b/Source/JavaScriptCore/runtime/Lookup.h
@@ -21,305 +21,351 @@
#ifndef Lookup_h
#define Lookup_h
+#include "BatchedTransitionOptimizer.h"
#include "CallFrame.h"
-#include "Intrinsic.h"
+#include "CustomGetterSetter.h"
#include "Identifier.h"
+#include "IdentifierInlines.h"
+#include "Intrinsic.h"
#include "JSGlobalObject.h"
#include "PropertySlot.h"
#include "PutPropertySlot.h"
#include <wtf/Assertions.h>
namespace JSC {
- // Hash table generated by the create_hash_table script.
- struct HashTableValue {
- const char* key; // property name
- unsigned char attributes; // JSObject attributes
- Intrinsic intrinsic;
- intptr_t value1;
- intptr_t value2;
- };
-
- // FIXME: There is no reason this get function can't be simpler.
- // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject)
- typedef PropertySlot::GetValueFunc GetFunction;
- typedef PutPropertySlot::PutValueFunc PutFunction;
-
- class HashEntry {
- WTF_MAKE_FAST_ALLOCATED;
- public:
- void initialize(StringImpl* key, unsigned char attributes, intptr_t v1, intptr_t v2, Intrinsic intrinsic)
- {
- m_key = key;
- m_attributes = attributes;
- m_u.store.value1 = v1;
- m_u.store.value2 = v2;
- m_intrinsic = intrinsic;
- m_next = 0;
- }
- void setKey(StringImpl* key) { m_key = key; }
- StringImpl* key() const { return m_key; }
-
- unsigned char attributes() const { return m_attributes; }
-
- Intrinsic intrinsic() const
- {
- ASSERT(m_attributes & Function);
- return m_intrinsic;
- }
+struct CompactHashIndex {
+ const int16_t value;
+ const int16_t next;
+};
+
+// FIXME: There is no reason this get function can't be simpler.
+// ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject)
+typedef PropertySlot::GetValueFunc GetFunction;
+typedef PutPropertySlot::PutValueFunc PutFunction;
+typedef FunctionExecutable* (*BuiltinGenerator)(VM&);
+
+// Hash table generated by the create_hash_table script.
+struct HashTableValue {
+ const char* m_key; // property name
+ unsigned m_attributes; // JSObject attributes
+ Intrinsic m_intrinsic;
+ union ValueStorage {
+ constexpr ValueStorage(intptr_t value1, intptr_t value2)
+ : value1(value1)
+ , value2(value2)
+ { }
+ constexpr ValueStorage(long long constant)
+ : constant(constant)
+ { }
+
+ struct {
+ intptr_t value1;
+ intptr_t value2;
+ };
+ long long constant;
+ } m_values;
- NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; }
- unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); }
+ unsigned attributes() const { return m_attributes; }
- GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; }
- PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; }
+ Intrinsic intrinsic() const { ASSERT(m_attributes & Function); return m_intrinsic; }
+ BuiltinGenerator builtinGenerator() const { ASSERT(m_attributes & Builtin); return reinterpret_cast<BuiltinGenerator>(m_values.value1); }
+ NativeFunction function() const { ASSERT(m_attributes & Function); return reinterpret_cast<NativeFunction>(m_values.value1); }
+ unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_values.value2); }
- intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; }
+ GetFunction propertyGetter() const { ASSERT(!(m_attributes & BuiltinOrFunctionOrAccessorOrConstant)); return reinterpret_cast<GetFunction>(m_values.value1); }
+ PutFunction propertyPutter() const { ASSERT(!(m_attributes & BuiltinOrFunctionOrAccessorOrConstant)); return reinterpret_cast<PutFunction>(m_values.value2); }
- void setNext(HashEntry *next) { m_next = next; }
- HashEntry* next() const { return m_next; }
+ NativeFunction accessorGetter() const { ASSERT(m_attributes & Accessor); return reinterpret_cast<NativeFunction>(m_values.value1); }
+ NativeFunction accessorSetter() const { ASSERT(m_attributes & Accessor); return reinterpret_cast<NativeFunction>(m_values.value2); }
+ BuiltinGenerator builtinAccessorGetterGenerator() const;
+ BuiltinGenerator builtinAccessorSetterGenerator() const;
- private:
- StringImpl* m_key;
- unsigned char m_attributes; // JSObject attributes
- Intrinsic m_intrinsic;
-
- union {
- struct {
- intptr_t value1;
- intptr_t value2;
- } store;
- struct {
- NativeFunction functionValue;
- intptr_t length; // number of arguments for function
- } function;
- struct {
- GetFunction get;
- PutFunction put;
- } property;
- struct {
- intptr_t value;
- intptr_t unused;
- } lexer;
- } m_u;
-
- HashEntry* m_next;
- };
+ long long constantInteger() const { ASSERT(m_attributes & ConstantInteger); return m_values.constant; }
- struct HashTable {
+ intptr_t lexerValue() const { ASSERT(!m_attributes); return m_values.value1; }
+};
- int compactSize;
- int compactHashSizeMask;
- bool hasSetterOrReadonlyProperties;
+struct HashTable {
+ int numberOfValues;
+ int indexMask;
+ bool hasSetterOrReadonlyProperties;
- const HashTableValue* values; // Fixed values generated by script.
- mutable const HashEntry* table; // Table allocated at runtime.
+ const HashTableValue* values; // Fixed values generated by script.
+ const CompactHashIndex* index;
- ALWAYS_INLINE HashTable copy() const
- {
- // Don't copy dynamic table since it's thread specific.
- HashTable result = { compactSize, compactHashSizeMask, hasSetterOrReadonlyProperties, values, 0 };
- return result;
- }
+ // Find an entry in the table, and return the entry.
+ ALWAYS_INLINE const HashTableValue* entry(PropertyName propertyName) const
+ {
+ if (propertyName.isSymbol())
+ return nullptr;
+
+ auto uid = propertyName.uid();
+ if (!uid)
+ return nullptr;
+
+ int indexEntry = IdentifierRepHash::hash(uid) & indexMask;
+ int valueIndex = index[indexEntry].value;
+ if (valueIndex == -1)
+ return nullptr;
+
+ while (true) {
+ if (WTF::equal(uid, values[valueIndex].m_key))
+ return &values[valueIndex];
+
+ indexEntry = index[indexEntry].next;
+ if (indexEntry == -1)
+ return nullptr;
+ valueIndex = index[indexEntry].value;
+ ASSERT(valueIndex != -1);
+ };
+ }
- ALWAYS_INLINE void initializeIfNeeded(VM& vm) const
+ class ConstIterator {
+ public:
+ ConstIterator(const HashTable* table, int position)
+ : m_table(table)
+ , m_position(position)
{
- if (!table)
- createTable(vm);
+ skipInvalidKeys();
}
- ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
+ const HashTableValue* value() const
{
- if (!table)
- createTable(exec->vm());
+ return &m_table->values[m_position];
}
- JS_EXPORT_PRIVATE void deleteTable() const;
+ const HashTableValue& operator*() const { return *value(); }
- // Find an entry in the table, and return the entry.
- ALWAYS_INLINE const HashEntry* entry(VM& vm, PropertyName identifier) const
+ const char* key() const
{
- initializeIfNeeded(vm);
- return entry(identifier);
+ return m_table->values[m_position].m_key;
}
- ALWAYS_INLINE const HashEntry* entry(ExecState* exec, PropertyName identifier) const
+ const HashTableValue* operator->() const
{
- initializeIfNeeded(exec);
- return entry(identifier);
+ return value();
}
- class ConstIterator {
- public:
- ConstIterator(const HashTable* table, int position)
- : m_table(table)
- , m_position(position)
- {
- skipInvalidKeys();
- }
-
- const HashEntry* operator->()
- {
- return &m_table->table[m_position];
- }
-
- const HashEntry* operator*()
- {
- return &m_table->table[m_position];
- }
-
- bool operator!=(const ConstIterator& other)
- {
- ASSERT(m_table == other.m_table);
- return m_position != other.m_position;
- }
-
- ConstIterator& operator++()
- {
- ASSERT(m_position < m_table->compactSize);
- ++m_position;
- skipInvalidKeys();
- return *this;
- }
-
- private:
- void skipInvalidKeys()
- {
- ASSERT(m_position <= m_table->compactSize);
- while (m_position < m_table->compactSize && !m_table->table[m_position].key())
- ++m_position;
- ASSERT(m_position <= m_table->compactSize);
- }
-
- const HashTable* m_table;
- int m_position;
- };
-
- ConstIterator begin(VM& vm) const
+ bool operator!=(const ConstIterator& other) const
{
- initializeIfNeeded(vm);
- return ConstIterator(this, 0);
+ ASSERT(m_table == other.m_table);
+ return m_position != other.m_position;
}
- ConstIterator end(VM& vm) const
+
+ ConstIterator& operator++()
{
- initializeIfNeeded(vm);
- return ConstIterator(this, compactSize);
+ ASSERT(m_position < m_table->numberOfValues);
+ ++m_position;
+ skipInvalidKeys();
+ return *this;
}
private:
- ALWAYS_INLINE const HashEntry* entry(PropertyName propertyName) const
+ void skipInvalidKeys()
{
- StringImpl* impl = propertyName.publicName();
- if (!impl)
- return 0;
-
- ASSERT(table);
-
- const HashEntry* entry = &table[impl->existingHash() & compactHashSizeMask];
-
- if (!entry->key())
- return 0;
-
- do {
- if (entry->key() == impl)
- return entry;
- entry = entry->next();
- } while (entry);
-
- return 0;
+ ASSERT(m_position <= m_table->numberOfValues);
+ while (m_position < m_table->numberOfValues && !m_table->values[m_position].m_key)
+ ++m_position;
+ ASSERT(m_position <= m_table->numberOfValues);
}
- // Convert the hash table keys to identifiers.
- JS_EXPORT_PRIVATE void createTable(VM&) const;
+ const HashTable* m_table;
+ int m_position;
};
- JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, PropertyName, PropertySlot&);
-
- /**
- * This method does it all (looking in the hashtable, checking for function
- * overrides, creating the function or retrieving from cache, calling
- * getValueProperty in case of a non-function property, forwarding to parent if
- * unknown property).
- */
- template <class ThisImp, class ParentImp>
- inline bool getStaticPropertySlot(ExecState* exec, const HashTable& table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
+ ConstIterator begin() const
+ {
+ return ConstIterator(this, 0);
+ }
+ ConstIterator end() const
{
- const HashEntry* entry = table.entry(exec, propertyName);
+ return ConstIterator(this, numberOfValues);
+ }
+};
+
+JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashTableValue*, JSObject* thisObject, PropertyName, PropertySlot&);
+JS_EXPORT_PRIVATE void reifyStaticAccessor(VM&, const HashTableValue&, JSObject& thisObject, PropertyName);
+
+inline BuiltinGenerator HashTableValue::builtinAccessorGetterGenerator() const
+{
+ ASSERT(m_attributes & Accessor);
+ ASSERT(m_attributes & Builtin);
+ return reinterpret_cast<BuiltinGenerator>(m_values.value1);
+}
+
+inline BuiltinGenerator HashTableValue::builtinAccessorSetterGenerator() const
+{
+ ASSERT(m_attributes & Accessor);
+ ASSERT(m_attributes & Builtin);
+ return reinterpret_cast<BuiltinGenerator>(m_values.value2);
+}
+
+/**
+ * This method does it all (looking in the hashtable, checking for function
+ * overrides, creating the function or retrieving from cache, calling
+ * getValueProperty in case of a non-function property, forwarding to parent if
+ * unknown property).
+ */
+template <class ThisImp, class ParentImp>
+inline bool getStaticPropertySlot(ExecState* exec, const HashTable& table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
+{
+ if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
+ return true;
- if (!entry) // not found, forward to parent
- return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
+ if (thisObj->staticFunctionsReified())
+ return false;
- if (entry->attributes() & Function)
- return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+ auto* entry = table.entry(propertyName);
+ if (!entry)
+ return false;
+
+ if (entry->attributes() & BuiltinOrFunctionOrAccessor)
+ return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
- slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter());
+ if (entry->attributes() & ConstantInteger) {
+ slot.setValue(thisObj, attributesForStructure(entry->attributes()), jsNumber(entry->constantInteger()));
return true;
}
- /**
- * Simplified version of getStaticPropertySlot in case there are only functions.
- * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
- * a dummy getValueProperty.
- */
- template <class ParentImp>
- inline bool getStaticFunctionSlot(ExecState* exec, const HashTable& table, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot)
- {
- if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
- return true;
+ slot.setCacheableCustom(thisObj, attributesForStructure(entry->attributes()), entry->propertyGetter());
+ return true;
+}
- const HashEntry* entry = table.entry(exec, propertyName);
- if (!entry)
- return false;
+/**
+ * Simplified version of getStaticPropertySlot in case there are only functions.
+ * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
+ * a dummy getValueProperty.
+ */
+template <class ParentImp>
+inline bool getStaticFunctionSlot(ExecState* exec, const HashTable& table, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot)
+{
+ if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
+ return true;
- return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
- }
+ if (thisObj->staticFunctionsReified())
+ return false;
- /**
- * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
- * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
- */
- template <class ThisImp, class ParentImp>
- inline bool getStaticValueSlot(ExecState* exec, const HashTable& table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
- {
- const HashEntry* entry = table.entry(exec, propertyName);
+ auto* entry = table.entry(propertyName);
+ if (!entry)
+ return false;
- if (!entry) // not found, forward to parent
- return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
+ return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+}
- ASSERT(!(entry->attributes() & Function));
+/**
+ * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
+ * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
+ */
+template <class ThisImp, class ParentImp>
+inline bool getStaticValueSlot(ExecState* exec, const HashTable& table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
+{
+ if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
+ return true;
+
+ if (thisObj->staticFunctionsReified())
+ return false;
+
+ auto* entry = table.entry(propertyName);
+ if (!entry)
+ return false;
+
+ ASSERT(!(entry->attributes() & BuiltinOrFunctionOrAccessor));
- slot.setCacheableCustom(thisObj, entry->attributes(), entry->propertyGetter());
+ if (entry->attributes() & ConstantInteger) {
+ slot.setValue(thisObj, attributesForStructure(entry->attributes()), jsNumber(entry->constantInteger()));
return true;
}
- inline void putEntry(ExecState* exec, const HashEntry* entry, JSObject* base, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
- {
- // If this is a function put it as an override property.
- if (entry->attributes() & Function) {
- if (JSObject* thisObject = jsDynamicCast<JSObject*>(slot.thisValue()))
+ slot.setCacheableCustom(thisObj, attributesForStructure(entry->attributes()), entry->propertyGetter());
+ return true;
+}
+
+// 'base' means the object holding the property (possibly in the prototype chain of the object put was called on).
+// 'thisValue' is the object that put is being applied to (in the case of a proxy, the proxy target).
+// 'slot.thisValue()' is the object the put was originally performed on (in the case of a proxy, the proxy itself).
+inline void putEntry(ExecState* exec, const HashTableValue* entry, JSObject* base, JSObject* thisValue, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
+ if (entry->attributes() & BuiltinOrFunction) {
+ if (!(entry->attributes() & ReadOnly)) {
+ // If this is a function put it as an override property.
+ if (JSObject* thisObject = jsDynamicCast<JSObject*>(thisValue))
thisObject->putDirect(exec->vm(), propertyName, value);
- } else if (!(entry->attributes() & ReadOnly)) {
- entry->propertyPutter()(exec, base, JSValue::encode(slot.thisValue()), JSValue::encode(value));
- slot.setCustomProperty(base, entry->propertyPutter());
} else if (slot.isStrictMode())
throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ } else if (entry->attributes() & Accessor) {
+ if (slot.isStrictMode())
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ } else if (!(entry->attributes() & ReadOnly)) {
+ JSValue updateThisValue = entry->attributes() & CustomAccessor ? slot.thisValue() : JSValue(base);
+ entry->propertyPutter()(exec, JSValue::encode(updateThisValue), JSValue::encode(value));
+ if (entry->attributes() & CustomAccessor)
+ slot.setCustomAccessor(base, entry->propertyPutter());
+ else
+ slot.setCustomValue(base, entry->propertyPutter());
+ } else if (slot.isStrictMode())
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+}
+
+/**
+ * This one is for "put".
+ * It looks up a hash entry for the property to be set. If an entry
+ * is found it sets the value and returns true, else it returns false.
+ */
+inline bool lookupPut(ExecState* exec, PropertyName propertyName, JSObject* base, JSValue value, const HashTable& table, PutPropertySlot& slot)
+{
+ const HashTableValue* entry = table.entry(propertyName);
+
+ if (!entry)
+ return false;
+
+ putEntry(exec, entry, base, base, propertyName, value, slot);
+ return true;
+}
+
+inline void reifyStaticProperty(VM& vm, const HashTableValue& value, JSObject& thisObj)
+{
+ if (!value.m_key)
+ return;
+
+ Identifier propertyName = Identifier::fromString(&vm, reinterpret_cast<const LChar*>(value.m_key), strlen(value.m_key));
+ if (value.attributes() & Builtin) {
+ if (value.attributes() & Accessor)
+ reifyStaticAccessor(vm, value, thisObj, propertyName);
+ else
+ thisObj.putDirectBuiltinFunction(vm, thisObj.globalObject(), propertyName, value.builtinGenerator()(vm), attributesForStructure(value.attributes()));
+ return;
}
- /**
- * This one is for "put".
- * It looks up a hash entry for the property to be set. If an entry
- * is found it sets the value and returns true, else it returns false.
- */
- inline bool lookupPut(ExecState* exec, PropertyName propertyName, JSObject* base, JSValue value, const HashTable& table, PutPropertySlot& slot)
- {
- const HashEntry* entry = table.entry(exec, propertyName);
+ if (value.attributes() & Function) {
+ thisObj.putDirectNativeFunction(
+ vm, thisObj.globalObject(), propertyName, value.functionLength(),
+ value.function(), value.intrinsic(), attributesForStructure(value.attributes()));
+ return;
+ }
- if (!entry)
- return false;
+ if (value.attributes() & ConstantInteger) {
+ thisObj.putDirect(vm, propertyName, jsNumber(value.constantInteger()), attributesForStructure(value.attributes()));
+ return;
+ }
- putEntry(exec, entry, base, propertyName, value, slot);
- return true;
+ if (value.attributes() & Accessor) {
+ reifyStaticAccessor(vm, value, thisObj, propertyName);
+ return;
}
+
+ CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, value.propertyGetter(), value.propertyPutter());
+ thisObj.putDirectCustomAccessor(vm, propertyName, customGetterSetter, attributesForStructure(value.attributes()));
+}
+
+template<unsigned numberOfValues>
+inline void reifyStaticProperties(VM& vm, const HashTableValue (&values)[numberOfValues], JSObject& thisObj)
+{
+ BatchedTransitionOptimizer transitionOptimizer(vm, &thisObj);
+ for (auto& value : values)
+ reifyStaticProperty(vm, value, thisObj);
+}
+
} // namespace JSC
#endif // Lookup_h
diff --git a/Source/JavaScriptCore/runtime/MapConstructor.cpp b/Source/JavaScriptCore/runtime/MapConstructor.cpp
index 9e3a4bf3b..fed1bf068 100644
--- a/Source/JavaScriptCore/runtime/MapConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/MapConstructor.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -27,35 +27,108 @@
#include "MapConstructor.h"
#include "Error.h"
+#include "GetterSetter.h"
+#include "IteratorOperations.h"
#include "JSCJSValueInlines.h"
#include "JSCellInlines.h"
#include "JSGlobalObject.h"
#include "JSMap.h"
#include "MapPrototype.h"
+#include "StructureInlines.h"
namespace JSC {
-const ClassInfo MapConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(MapConstructor) };
+const ClassInfo MapConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(MapConstructor) };
-void MapConstructor::finishCreation(VM& vm, MapPrototype* mapPrototype)
+void MapConstructor::finishCreation(VM& vm, MapPrototype* mapPrototype, GetterSetter* speciesSymbol)
{
Base::finishCreation(vm, mapPrototype->classInfo()->className);
putDirectWithoutTransition(vm, vm.propertyNames->prototype, mapPrototype, DontEnum | DontDelete | ReadOnly);
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum | DontDelete);
+ putDirectNonIndexAccessor(vm, vm.propertyNames->speciesSymbol, speciesSymbol, Accessor | ReadOnly | DontEnum);
}
-static EncodedJSValue JSC_HOST_CALL constructMap(ExecState* exec)
+static EncodedJSValue JSC_HOST_CALL callMap(ExecState* exec)
{
- // Until we have iterators we throw if we've been given
- // any arguments that could require us to throw.
- if (!exec->argument(0).isUndefinedOrNull())
- return JSValue::encode(throwTypeError(exec, ASCIILiteral("Map constructor does not accept arguments")));
- if (!exec->argument(1).isUndefined())
- return throwVMError(exec, createRangeError(exec, WTF::ASCIILiteral("Invalid comparator function")));
+ return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(exec, "Map"));
+}
+static EncodedJSValue JSC_HOST_CALL constructMap(ExecState* exec)
+{
JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject();
- Structure* mapStructure = globalObject->mapStructure();
- return JSValue::encode(JSMap::create(exec, mapStructure));
+ Structure* mapStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), globalObject->mapStructure());
+ JSMap* map = JSMap::create(exec, mapStructure);
+ JSValue iterable = exec->argument(0);
+ if (iterable.isUndefinedOrNull())
+ return JSValue::encode(map);
+
+ JSValue adderFunction = map->JSObject::get(exec, exec->propertyNames().set);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ CallData adderFunctionCallData;
+ CallType adderFunctionCallType = getCallData(adderFunction, adderFunctionCallData);
+ if (adderFunctionCallType == CallTypeNone)
+ return JSValue::encode(throwTypeError(exec));
+
+ JSValue iteratorFunction = iterable.get(exec, exec->propertyNames().iteratorSymbol);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ CallData iteratorFunctionCallData;
+ CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData);
+ if (iteratorFunctionCallType == CallTypeNone)
+ return JSValue::encode(throwTypeError(exec));
+
+ ArgList iteratorFunctionArguments;
+ JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (!iterator.isObject())
+ return JSValue::encode(throwTypeError(exec));
+
+ while (true) {
+ JSValue next = iteratorStep(exec, iterator);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (next.isFalse())
+ return JSValue::encode(map);
+
+ JSValue nextItem = iteratorValue(exec, next);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (!nextItem.isObject()) {
+ throwTypeError(exec);
+ iteratorClose(exec, iterator);
+ return JSValue::encode(jsUndefined());
+ }
+
+ JSValue key = nextItem.get(exec, 0);
+ if (exec->hadException()) {
+ iteratorClose(exec, iterator);
+ return JSValue::encode(jsUndefined());
+ }
+
+ JSValue value = nextItem.get(exec, 1);
+ if (exec->hadException()) {
+ iteratorClose(exec, iterator);
+ return JSValue::encode(jsUndefined());
+ }
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(key);
+ arguments.append(value);
+ call(exec, adderFunction, adderFunctionCallType, adderFunctionCallData, map, arguments);
+ if (exec->hadException()) {
+ iteratorClose(exec, iterator);
+ return JSValue::encode(jsUndefined());
+ }
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return JSValue::encode(map);
}
ConstructType MapConstructor::getConstructData(JSCell*, ConstructData& constructData)
@@ -66,7 +139,7 @@ ConstructType MapConstructor::getConstructData(JSCell*, ConstructData& construct
CallType MapConstructor::getCallData(JSCell*, CallData& callData)
{
- callData.native.function = constructMap;
+ callData.native.function = callMap;
return CallTypeHost;
}
diff --git a/Source/JavaScriptCore/runtime/MapConstructor.h b/Source/JavaScriptCore/runtime/MapConstructor.h
index 1a85de5b1..0462d7466 100644
--- a/Source/JavaScriptCore/runtime/MapConstructor.h
+++ b/Source/JavaScriptCore/runtime/MapConstructor.h
@@ -31,15 +31,16 @@
namespace JSC {
class MapPrototype;
+class GetterSetter;
class MapConstructor : public InternalFunction {
public:
typedef InternalFunction Base;
- static MapConstructor* create(VM& vm, Structure* structure, MapPrototype* mapPrototype)
+ static MapConstructor* create(VM& vm, Structure* structure, MapPrototype* mapPrototype, GetterSetter* speciesSymbol)
{
MapConstructor* constructor = new (NotNull, allocateCell<MapConstructor>(vm.heap)) MapConstructor(vm, structure);
- constructor->finishCreation(vm, mapPrototype);
+ constructor->finishCreation(vm, mapPrototype, speciesSymbol);
return constructor;
}
@@ -55,7 +56,7 @@ private:
: Base(vm, structure)
{
}
- void finishCreation(VM&, MapPrototype*);
+ void finishCreation(VM&, MapPrototype*, GetterSetter* speciesSymbol);
static ConstructType getConstructData(JSCell*, ConstructData&);
static CallType getCallData(JSCell*, CallData&);
};
diff --git a/Source/JavaScriptCore/runtime/MapData.cpp b/Source/JavaScriptCore/runtime/MapData.cpp
deleted file mode 100644
index f5a3e7610..000000000
--- a/Source/JavaScriptCore/runtime/MapData.cpp
+++ /dev/null
@@ -1,256 +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. 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 "MapData.h"
-
-#include "CopiedAllocator.h"
-#include "CopyVisitorInlines.h"
-#include "ExceptionHelpers.h"
-#include "JSCJSValueInlines.h"
-#include "SlotVisitorInlines.h"
-
-#include <wtf/CryptographicallyRandomNumber.h>
-#include <wtf/MathExtras.h>
-
-
-namespace JSC {
-
-const ClassInfo MapData::s_info = { "MapData", 0, 0, 0, CREATE_METHOD_TABLE(MapData) };
-
-static const int32_t minimumMapSize = 8;
-
-MapData::MapData(VM& vm)
- : Base(vm, vm.mapDataStructure.get())
- , m_capacity(0)
- , m_size(0)
- , m_deletedCount(0)
- , m_iteratorCount(0)
- , m_entries(0)
-{
-}
-
-MapData::Entry* MapData::find(CallFrame* callFrame, KeyType key)
-{
- if (key.value.isString()) {
- auto iter = m_stringKeyedTable.find(asString(key.value)->value(callFrame).impl());
- if (iter == m_stringKeyedTable.end())
- return 0;
- return &m_entries[iter->value];
- }
- if (key.value.isCell()) {
- auto iter = m_cellKeyedTable.find(key.value.asCell());
- if (iter == m_cellKeyedTable.end())
- return 0;
- return &m_entries[iter->value];
- }
-
- auto iter = m_valueKeyedTable.find(JSValue::encode(key.value));
- if (iter == m_valueKeyedTable.end())
- return 0;
- return &m_entries[iter->value];
-}
-
-bool MapData::contains(CallFrame* callFrame, KeyType key)
-{
- return find(callFrame, key);
-}
-
-template <typename Map, typename Key> MapData::Entry* MapData::add(CallFrame* callFrame, Map& map, Key key, KeyType keyValue)
-{
- typename Map::iterator location = map.find(key);
- if (location != map.end())
- return &m_entries[location->value];
-
- if (!ensureSpaceForAppend(callFrame))
- return 0;
-
- auto result = map.add(key, m_size);
- RELEASE_ASSERT(result.isNewEntry);
- Entry* entry = &m_entries[m_size++];
- new (entry) Entry();
- entry->key.set(callFrame->vm(), this, keyValue.value);
- return entry;
-}
-
-void MapData::set(CallFrame* callFrame, KeyType key, JSValue value)
-{
- Entry* location = add(callFrame, key);
- if (!location)
- return;
- location->value.set(callFrame->vm(), this, value);
-}
-
-MapData::Entry* MapData::add(CallFrame* callFrame, KeyType key)
-{
- if (key.value.isString())
- return add(callFrame, m_stringKeyedTable, asString(key.value)->value(callFrame).impl(), key);
- if (key.value.isCell())
- return add(callFrame, m_cellKeyedTable, key.value.asCell(), key);
- return add(callFrame, m_valueKeyedTable, JSValue::encode(key.value), key);
-}
-
-JSValue MapData::get(CallFrame* callFrame, KeyType key)
-{
- if (Entry* entry = find(callFrame, key))
- return entry->value.get();
- return JSValue();
-}
-
-bool MapData::remove(CallFrame* callFrame, KeyType key)
-{
- int32_t location;
- if (key.value.isString()) {
- auto iter = m_stringKeyedTable.find(asString(key.value)->value(callFrame).impl());
- if (iter == m_stringKeyedTable.end())
- return false;
- location = iter->value;
- m_stringKeyedTable.remove(iter);
- } else if (key.value.isCell()) {
- auto iter = m_cellKeyedTable.find(key.value.asCell());
- if (iter == m_cellKeyedTable.end())
- return false;
- location = iter->value;
- m_cellKeyedTable.remove(iter);
- } else {
- auto iter = m_valueKeyedTable.find(JSValue::encode(key.value));
- if (iter == m_valueKeyedTable.end())
- return false;
- location = iter->value;
- m_valueKeyedTable.remove(iter);
- }
- m_entries[location].key.clear();
- m_entries[location].value.clear();
- m_deletedCount++;
- return true;
-}
-
-void MapData::replaceAndPackBackingStore(Entry* destination, int32_t newCapacity)
-{
- ASSERT(shouldPack());
- int32_t newEnd = 0;
- RELEASE_ASSERT(newCapacity > 0);
- for (int32_t i = 0; i < m_size; i++) {
- Entry& entry = m_entries[i];
- if (!entry.key)
- continue;
- ASSERT(newEnd < newCapacity);
- destination[newEnd] = entry;
-
- // We overwrite the old entry with a forwarding index for the new entry,
- // so that we can fix up our hash tables below without doing additional
- // hash lookups
- entry.value.setWithoutWriteBarrier(jsNumber(newEnd));
- newEnd++;
- }
-
- // Fixup for the hashmaps
- for (auto ptr = m_valueKeyedTable.begin(); ptr != m_valueKeyedTable.end(); ++ptr)
- ptr->value = m_entries[ptr->value].value.get().asInt32();
- for (auto ptr = m_stringKeyedTable.begin(); ptr != m_stringKeyedTable.end(); ++ptr)
- ptr->value = m_entries[ptr->value].value.get().asInt32();
-
- ASSERT((m_size - newEnd) == m_deletedCount);
- m_deletedCount = 0;
-
- m_capacity = newCapacity;
- m_size = newEnd;
- m_entries = destination;
-
-}
-
-void MapData::replaceBackingStore(Entry* destination, int32_t newCapacity)
-{
- ASSERT(!shouldPack());
- RELEASE_ASSERT(newCapacity > 0);
- ASSERT(newCapacity >= m_capacity);
- memcpy(destination, m_entries, sizeof(Entry) * m_size);
- m_capacity = newCapacity;
- m_entries = destination;
-}
-
-CheckedBoolean MapData::ensureSpaceForAppend(CallFrame* callFrame)
-{
- if (m_capacity > m_size)
- return true;
-
- size_t requiredSize = std::max(m_capacity + (m_capacity / 2) + 1, minimumMapSize);
- void* newStorage = 0;
- DeferGC defer(*callFrame->heap());
- if (!callFrame->heap()->tryAllocateStorage(this, requiredSize * sizeof(Entry), &newStorage)) {
- throwOutOfMemoryError(callFrame);
- return false;
- }
- Entry* newEntries = static_cast<Entry*>(newStorage);
- if (shouldPack())
- replaceAndPackBackingStore(newEntries, requiredSize);
- else
- replaceBackingStore(newEntries, requiredSize);
- Heap::writeBarrier(this);
- return true;
-}
-
-void MapData::visitChildren(JSCell* cell, SlotVisitor& visitor)
-{
- Base::visitChildren(cell, visitor);
- MapData* thisObject = jsCast<MapData*>(cell);
- Entry* entries = thisObject->m_entries;
- if (!entries)
- return;
- size_t size = thisObject->m_size;
- if (thisObject->m_deletedCount) {
- for (size_t i = 0; i < size; i++) {
- if (!entries[i].key)
- continue;
- visitor.append(&entries[i].key);
- visitor.append(&entries[i].value);
- }
- } else
- visitor.appendValues(&entries[0].key, size * (sizeof(Entry) / sizeof(WriteBarrier<Unknown>)));
-
- visitor.copyLater(thisObject, MapBackingStoreCopyToken, entries, thisObject->capacityInBytes());
-}
-
-void MapData::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token)
-{
- MapData* thisObject = jsCast<MapData*>(cell);
- if (token == MapBackingStoreCopyToken && visitor.checkIfShouldCopy(thisObject->m_entries)) {
- Entry* oldEntries = thisObject->m_entries;
- Entry* newEntries = static_cast<Entry*>(visitor.allocateNewSpace(thisObject->capacityInBytes()));
- if (thisObject->shouldPack())
- thisObject->replaceAndPackBackingStore(newEntries, thisObject->m_capacity);
- else
- thisObject->replaceBackingStore(newEntries, thisObject->m_capacity);
- visitor.didCopy(oldEntries, thisObject->capacityInBytes());
- }
- Base::copyBackingStore(cell, visitor, token);
-}
-
-void MapData::destroy(JSCell* cell)
-{
- static_cast<MapData*>(cell)->~MapData();
-}
-
-}
diff --git a/Source/JavaScriptCore/runtime/MapData.h b/Source/JavaScriptCore/runtime/MapData.h
index 9c2bb559f..6a4cc2ca0 100644
--- a/Source/JavaScriptCore/runtime/MapData.h
+++ b/Source/JavaScriptCore/runtime/MapData.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 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
@@ -26,43 +26,69 @@
#ifndef MapData_h
#define MapData_h
+#include "CopyBarrier.h"
#include "JSCell.h"
-#include "Structure.h"
+#include "WeakGCMapInlines.h"
#include <wtf/HashFunctions.h>
#include <wtf/HashMap.h>
#include <wtf/MathExtras.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
namespace JSC {
-class MapData : public JSCell {
+class ExecState;
+class VM;
+
+template<typename Entry, typename JSIterator>
+class MapDataImpl {
public:
- typedef JSCell Base;
-
- struct const_iterator {
- const_iterator(const MapData*);
- ~const_iterator();
- const WTF::KeyValuePair<JSValue, JSValue> operator*() const;
- JSValue key() const { RELEASE_ASSERT(!atEnd()); return m_mapData->m_entries[m_index].key.get(); }
- JSValue value() const { RELEASE_ASSERT(!atEnd()); return m_mapData->m_entries[m_index].value.get(); }
- void operator++() { ASSERT(!atEnd()); internalIncrement(); }
- static const_iterator end(const MapData*);
- bool operator!=(const const_iterator& other);
- bool operator==(const const_iterator& other);
- void finish() { m_index = std::numeric_limits<int32_t>::max(); }
-
- bool ensureSlot();
+ enum : int32_t {
+ minimumMapSize = 8
+ };
+
+ class IteratorData {
+ public:
+ friend class MapDataImpl;
+
+ IteratorData(const MapDataImpl*);
+ bool next(WTF::KeyValuePair<JSValue, JSValue>&);
+
+ // This function is called while packing a map's backing store. The
+ // passed-in index is the new index the entry would have after packing.
+ void didRemoveEntry(int32_t packedIndex)
+ {
+ if (isFinished())
+ return;
+
+ if (m_index <= packedIndex)
+ return;
+
+ --m_index;
+ }
+
+ void didRemoveAllEntries()
+ {
+ if (isFinished())
+ return;
+ m_index = 0;
+ }
+
+ void finish()
+ {
+ m_index = -1;
+ }
private:
- // This is a bit gnarly. We use an index of -1 to indicate the
- // "end()" iterator. By casting to unsigned we can immediately
- // test if both iterators are at the end of their iteration.
- // We need this in order to keep the common case (eg. iter != end())
- // fast.
- bool atEnd() const { return static_cast<size_t>(m_index) >= static_cast<size_t>(m_mapData->m_size); }
- void internalIncrement();
- const MapData* m_mapData;
- int32_t m_index;
+ bool ensureSlot() const;
+ bool isFinished() const { return m_index == -1; }
+ int32_t refreshCursor() const;
+
+ const MapDataImpl* m_mapData;
+ mutable int32_t m_index;
};
+ STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(IteratorData);
struct KeyType {
ALWAYS_INLINE KeyType() { }
@@ -70,63 +96,37 @@ public:
JSValue value;
};
- static MapData* create(VM& vm)
- {
- MapData* mapData = new (NotNull, allocateCell<MapData>(vm.heap)) MapData(vm);
- mapData->finishCreation(vm);
- return mapData;
- }
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), info());
- }
-
- static const bool needsDestruction = true;
- static const bool hasImmortalStructure = true;
+ MapDataImpl(VM&, JSCell* owner);
- JS_EXPORT_PRIVATE void set(CallFrame*, KeyType, JSValue);
- JSValue get(CallFrame*, KeyType);
- bool remove(CallFrame*, KeyType);
- bool contains(CallFrame*, KeyType);
- size_t size(CallFrame*) const { return m_size - m_deletedCount; }
+ void set(ExecState*, JSCell* owner, KeyType, JSValue);
+ JSValue get(ExecState*, KeyType);
+ bool remove(ExecState*, KeyType);
+ bool contains(ExecState*, KeyType);
+ size_t size(ExecState*) const { return m_size - m_deletedCount; }
- const_iterator begin() const { return const_iterator(this); }
- const_iterator end() const { return const_iterator::end(this); }
+ IteratorData createIteratorData(JSIterator*);
void clear();
- DECLARE_INFO;
- static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
+ void visitChildren(JSCell* owner, SlotVisitor&);
+ void copyBackingStore(CopyVisitor&, CopyToken);
+
+ size_t capacityInBytes() const { return m_capacity * sizeof(Entry); }
private:
typedef WTF::UnsignedWithZeroKeyHashTraits<int32_t> IndexTraits;
- // Our marking functions expect Entry to maintain this layout, and have all
- // fields be WriteBarrier<Unknown>
- struct Entry {
- WriteBarrier<Unknown> key;
- WriteBarrier<Unknown> value;
- };
-
typedef HashMap<JSCell*, int32_t, typename WTF::DefaultHash<JSCell*>::Hash, WTF::HashTraits<JSCell*>, IndexTraits> CellKeyedMap;
typedef HashMap<EncodedJSValue, int32_t, EncodedJSValueHash, EncodedJSValueHashTraits, IndexTraits> ValueKeyedMap;
typedef HashMap<StringImpl*, int32_t, typename WTF::DefaultHash<StringImpl*>::Hash, WTF::HashTraits<StringImpl*>, IndexTraits> StringKeyedMap;
+ typedef HashMap<SymbolImpl*, int32_t, typename WTF::PtrHash<SymbolImpl*>, WTF::HashTraits<SymbolImpl*>, IndexTraits> SymbolKeyedMap;
- size_t capacityInBytes() { return m_capacity * sizeof(Entry); }
-
- MapData(VM&);
- static void destroy(JSCell*);
- static void visitChildren(JSCell*, SlotVisitor&);
- static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken);
+ ALWAYS_INLINE Entry* find(ExecState*, KeyType);
+ ALWAYS_INLINE Entry* add(ExecState*, JSCell* owner, KeyType);
+ template <typename Map, typename Key> ALWAYS_INLINE Entry* add(ExecState*, JSCell* owner, Map&, Key, KeyType);
-
- ALWAYS_INLINE Entry* find(CallFrame*, KeyType);
- ALWAYS_INLINE Entry* add(CallFrame*, KeyType);
- template <typename Map, typename Key> ALWAYS_INLINE Entry* add(CallFrame*, Map&, Key, KeyType);
-
- ALWAYS_INLINE bool shouldPack() const { return m_deletedCount && !m_iteratorCount; }
- CheckedBoolean ensureSpaceForAppend(CallFrame*);
+ ALWAYS_INLINE bool shouldPack() const { return m_deletedCount; }
+ CheckedBoolean ensureSpaceForAppend(ExecState*, JSCell* owner);
ALWAYS_INLINE void replaceAndPackBackingStore(Entry* destination, int32_t newSize);
ALWAYS_INLINE void replaceBackingStore(Entry* destination, int32_t newSize);
@@ -134,31 +134,34 @@ private:
CellKeyedMap m_cellKeyedTable;
ValueKeyedMap m_valueKeyedTable;
StringKeyedMap m_stringKeyedTable;
+ SymbolKeyedMap m_symbolKeyedTable;
int32_t m_capacity;
int32_t m_size;
int32_t m_deletedCount;
- mutable int32_t m_iteratorCount;
- Entry* m_entries;
+ JSCell* m_owner;
+ CopyBarrier<Entry> m_entries;
+ WeakGCMap<JSIterator*, JSIterator> m_iterators;
};
-ALWAYS_INLINE void MapData::clear()
+template<typename Entry, typename JSIterator>
+ALWAYS_INLINE MapDataImpl<Entry, JSIterator>::MapDataImpl(VM& vm, JSCell* owner)
+ : m_capacity(0)
+ , m_size(0)
+ , m_deletedCount(0)
+ , m_owner(owner)
+ , m_iterators(vm)
{
- m_valueKeyedTable.clear();
- m_stringKeyedTable.clear();
- m_capacity = 0;
- m_size = 0;
- m_deletedCount = 0;
- m_entries = 0;
}
-ALWAYS_INLINE MapData::KeyType::KeyType(JSValue v)
+template<typename Entry, typename JSIterator>
+ALWAYS_INLINE MapDataImpl<Entry, JSIterator>::KeyType::KeyType(JSValue v)
{
if (!v.isDouble()) {
value = v;
return;
}
double d = v.asDouble();
- if (std::isnan(d) || (std::signbit(d) && d == 0.0)) {
+ if (std::isnan(d)) {
value = v;
return;
}
@@ -170,65 +173,45 @@ ALWAYS_INLINE MapData::KeyType::KeyType(JSValue v)
value = jsNumber(i);
}
-ALWAYS_INLINE void MapData::const_iterator::internalIncrement()
-{
- Entry* entries = m_mapData->m_entries;
- size_t index = m_index + 1;
- size_t end = m_mapData->m_size;
- while (index < end && !entries[index].key)
- index++;
- m_index = index;
-}
-
-ALWAYS_INLINE bool MapData::const_iterator::ensureSlot()
-{
- // When an iterator exists outside of host cost it is possible for
- // the containing map to be modified
- Entry* entries = m_mapData->m_entries;
- size_t index = m_index;
- size_t end = m_mapData->m_size;
- if (index < end && entries[index].key)
- return true;
- internalIncrement();
- return static_cast<size_t>(m_index) < end;
-}
-
-ALWAYS_INLINE MapData::const_iterator::const_iterator(const MapData* mapData)
+template<typename Entry, typename JSIterator>
+ALWAYS_INLINE MapDataImpl<Entry, JSIterator>::IteratorData::IteratorData(const MapDataImpl<Entry, JSIterator>* mapData)
: m_mapData(mapData)
- , m_index(-1)
+ , m_index(0)
{
- internalIncrement();
}
-ALWAYS_INLINE MapData::const_iterator::~const_iterator()
+template<typename Entry, typename JSIterator>
+ALWAYS_INLINE bool MapDataImpl<Entry, JSIterator>::IteratorData::next(WTF::KeyValuePair<JSValue, JSValue>& pair)
{
- m_mapData->m_iteratorCount--;
-}
-
-ALWAYS_INLINE const WTF::KeyValuePair<JSValue, JSValue> MapData::const_iterator::operator*() const
-{
- Entry* entry = &m_mapData->m_entries[m_index];
- return WTF::KeyValuePair<JSValue, JSValue>(entry->key.get(), entry->value.get());
+ if (!ensureSlot())
+ return false;
+ Entry* entry = &m_mapData->m_entries.get(m_mapData->m_owner)[m_index];
+ pair = WTF::KeyValuePair<JSValue, JSValue>(entry->key().get(), entry->value().get());
+ m_index += 1;
+ return true;
}
-ALWAYS_INLINE MapData::const_iterator MapData::const_iterator::end(const MapData* mapData)
+// This is a bit gnarly. We use an index of -1 to indicate the
+// finished state. By casting to unsigned we can immediately
+// test if both iterators are at the end of their iteration.
+template<typename Entry, typename JSIterator>
+ALWAYS_INLINE bool MapDataImpl<Entry, JSIterator>::IteratorData::ensureSlot() const
{
- const_iterator result(mapData);
- result.m_index = -1;
- return result;
+ int32_t index = refreshCursor();
+ return static_cast<size_t>(index) < static_cast<size_t>(m_mapData->m_size);
}
-ALWAYS_INLINE bool MapData::const_iterator::operator!=(const const_iterator& other)
+template<typename Entry, typename JSIterator>
+ALWAYS_INLINE int32_t MapDataImpl<Entry, JSIterator>::IteratorData::refreshCursor() const
{
- ASSERT(other.m_mapData == m_mapData);
- if (atEnd() && other.atEnd())
- return false;
- return m_index != other.m_index;
-}
+ if (isFinished())
+ return m_index;
-ALWAYS_INLINE bool MapData::const_iterator::operator==(const const_iterator& other)
-{
- return !(*this != other);
+ Entry* entries = m_mapData->m_entries.get(m_mapData->m_owner);
+ size_t end = m_mapData->m_size;
+ while (static_cast<size_t>(m_index) < end && !entries[m_index].key())
+ m_index++;
+ return m_index;
}
}
diff --git a/Source/JavaScriptCore/runtime/MapDataInlines.h b/Source/JavaScriptCore/runtime/MapDataInlines.h
new file mode 100644
index 000000000..5f006ceb8
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/MapDataInlines.h
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 "CopiedAllocator.h"
+#include "CopyVisitorInlines.h"
+#include "ExceptionHelpers.h"
+#include "JSCJSValueInlines.h"
+#include "MapData.h"
+#include "SlotVisitorInlines.h"
+
+#include <wtf/CryptographicallyRandomNumber.h>
+#include <wtf/MathExtras.h>
+
+
+namespace JSC {
+
+template<typename Entry, typename JSIterator>
+inline void MapDataImpl<Entry, JSIterator>::clear()
+{
+ m_cellKeyedTable.clear();
+ m_valueKeyedTable.clear();
+ m_stringKeyedTable.clear();
+ m_symbolKeyedTable.clear();
+ m_capacity = 0;
+ m_size = 0;
+ m_deletedCount = 0;
+ m_entries.clear();
+ m_iterators.forEach([](JSIterator* iterator, JSIterator*) {
+ iterator->iteratorData()->didRemoveAllEntries();
+ });
+}
+
+template<typename Entry, typename JSIterator>
+inline Entry* MapDataImpl<Entry, JSIterator>::find(ExecState* exec, KeyType key)
+{
+ if (key.value.isString()) {
+ auto iter = m_stringKeyedTable.find(asString(key.value)->value(exec).impl());
+ if (iter == m_stringKeyedTable.end())
+ return 0;
+ return &m_entries.get(m_owner)[iter->value];
+ }
+ if (key.value.isSymbol()) {
+ auto iter = m_symbolKeyedTable.find(asSymbol(key.value)->privateName().uid());
+ if (iter == m_symbolKeyedTable.end())
+ return 0;
+ return &m_entries.get(m_owner)[iter->value];
+ }
+ if (key.value.isCell()) {
+ auto iter = m_cellKeyedTable.find(key.value.asCell());
+ if (iter == m_cellKeyedTable.end())
+ return 0;
+ return &m_entries.get(m_owner)[iter->value];
+ }
+
+ auto iter = m_valueKeyedTable.find(JSValue::encode(key.value));
+ if (iter == m_valueKeyedTable.end())
+ return 0;
+ return &m_entries.get(m_owner)[iter->value];
+}
+
+template<typename Entry, typename JSIterator>
+inline bool MapDataImpl<Entry, JSIterator>::contains(ExecState* exec, KeyType key)
+{
+ return find(exec, key);
+}
+
+template<typename Entry, typename JSIterator>
+template <typename Map, typename Key>
+inline Entry* MapDataImpl<Entry, JSIterator>::add(ExecState* exec, JSCell* owner, Map& map, Key key, KeyType keyValue)
+{
+ typename Map::iterator location = map.find(key);
+ if (location != map.end())
+ return &m_entries.get(m_owner)[location->value];
+
+ if (!ensureSpaceForAppend(exec, owner))
+ return 0;
+
+ auto result = map.add(key, m_size);
+ RELEASE_ASSERT(result.isNewEntry);
+ Entry* entry = &m_entries.get(m_owner)[m_size++];
+ new (entry) Entry();
+ entry->setKey(exec->vm(), owner, keyValue.value);
+ return entry;
+}
+
+template<typename Entry, typename JSIterator>
+inline void MapDataImpl<Entry, JSIterator>::set(ExecState* exec, JSCell* owner, KeyType key, JSValue value)
+{
+ Entry* location = add(exec, owner, key);
+ if (!location)
+ return;
+ location->setValue(exec->vm(), owner, value);
+}
+
+template<typename Entry, typename JSIterator>
+inline Entry* MapDataImpl<Entry, JSIterator>::add(ExecState* exec, JSCell* owner, KeyType key)
+{
+ if (key.value.isString())
+ return add(exec, owner, m_stringKeyedTable, asString(key.value)->value(exec).impl(), key);
+ if (key.value.isSymbol())
+ return add(exec, owner, m_symbolKeyedTable, asSymbol(key.value)->privateName().uid(), key);
+ if (key.value.isCell())
+ return add(exec, owner, m_cellKeyedTable, key.value.asCell(), key);
+ return add(exec, owner, m_valueKeyedTable, JSValue::encode(key.value), key);
+}
+
+template<typename Entry, typename JSIterator>
+inline JSValue MapDataImpl<Entry, JSIterator>::get(ExecState* exec, KeyType key)
+{
+ if (Entry* entry = find(exec, key))
+ return entry->value().get();
+ return JSValue();
+}
+
+template<typename Entry, typename JSIterator>
+inline bool MapDataImpl<Entry, JSIterator>::remove(ExecState* exec, KeyType key)
+{
+ int32_t location;
+ if (key.value.isString()) {
+ auto iter = m_stringKeyedTable.find(asString(key.value)->value(exec).impl());
+ if (iter == m_stringKeyedTable.end())
+ return false;
+ location = iter->value;
+ m_stringKeyedTable.remove(iter);
+ } else if (key.value.isSymbol()) {
+ auto iter = m_symbolKeyedTable.find(asSymbol(key.value)->privateName().uid());
+ if (iter == m_symbolKeyedTable.end())
+ return false;
+ location = iter->value;
+ m_symbolKeyedTable.remove(iter);
+ } else if (key.value.isCell()) {
+ auto iter = m_cellKeyedTable.find(key.value.asCell());
+ if (iter == m_cellKeyedTable.end())
+ return false;
+ location = iter->value;
+ m_cellKeyedTable.remove(iter);
+ } else {
+ auto iter = m_valueKeyedTable.find(JSValue::encode(key.value));
+ if (iter == m_valueKeyedTable.end())
+ return false;
+ location = iter->value;
+ m_valueKeyedTable.remove(iter);
+ }
+ m_entries.get(m_owner)[location].clear();
+ m_deletedCount++;
+ return true;
+}
+
+template<typename Entry, typename JSIterator>
+inline void MapDataImpl<Entry, JSIterator>::replaceAndPackBackingStore(Entry* destination, int32_t newCapacity)
+{
+ ASSERT(shouldPack());
+ int32_t newEnd = 0;
+ RELEASE_ASSERT(newCapacity > 0);
+ for (int32_t i = 0; i < m_size; i++) {
+ Entry& entry = m_entries.getWithoutBarrier()[i];
+ if (!entry.key()) {
+ m_iterators.forEach([newEnd](JSIterator* iterator, JSIterator*) {
+ iterator->iteratorData()->didRemoveEntry(newEnd);
+ });
+ continue;
+ }
+ ASSERT(newEnd < newCapacity);
+ destination[newEnd] = entry;
+
+ // We overwrite the old entry with a forwarding index for the new entry,
+ // so that we can fix up our hash tables below without doing additional
+ // hash lookups
+ entry.setKeyWithoutWriteBarrier(jsNumber(newEnd));
+ newEnd++;
+ }
+
+ // Fixup for the hashmaps
+ for (auto ptr = m_valueKeyedTable.begin(); ptr != m_valueKeyedTable.end(); ++ptr)
+ ptr->value = m_entries.getWithoutBarrier()[ptr->value].key().get().asInt32();
+ for (auto ptr = m_cellKeyedTable.begin(); ptr != m_cellKeyedTable.end(); ++ptr)
+ ptr->value = m_entries.getWithoutBarrier()[ptr->value].key().get().asInt32();
+ for (auto ptr = m_stringKeyedTable.begin(); ptr != m_stringKeyedTable.end(); ++ptr)
+ ptr->value = m_entries.getWithoutBarrier()[ptr->value].key().get().asInt32();
+ for (auto ptr = m_symbolKeyedTable.begin(); ptr != m_symbolKeyedTable.end(); ++ptr)
+ ptr->value = m_entries.getWithoutBarrier()[ptr->value].key().get().asInt32();
+
+ ASSERT((m_size - newEnd) == m_deletedCount);
+ m_deletedCount = 0;
+
+ m_capacity = newCapacity;
+ m_size = newEnd;
+ m_entries.setWithoutBarrier(destination);
+}
+
+template<typename Entry, typename JSIterator>
+inline void MapDataImpl<Entry, JSIterator>::replaceBackingStore(Entry* destination, int32_t newCapacity)
+{
+ ASSERT(!shouldPack());
+ RELEASE_ASSERT(newCapacity > 0);
+ ASSERT(newCapacity >= m_capacity);
+ memcpy(destination, m_entries.getWithoutBarrier(), sizeof(Entry) * m_size);
+ m_capacity = newCapacity;
+ m_entries.setWithoutBarrier(destination);
+}
+
+template<typename Entry, typename JSIterator>
+inline CheckedBoolean MapDataImpl<Entry, JSIterator>::ensureSpaceForAppend(ExecState* exec, JSCell* owner)
+{
+ if (m_capacity > m_size)
+ return true;
+
+ size_t requiredSize = std::max(m_capacity + (m_capacity / 2) + 1, static_cast<int32_t>(minimumMapSize));
+ void* newStorage = nullptr;
+ DeferGC defer(*exec->heap());
+ if (!exec->heap()->tryAllocateStorage(owner, requiredSize * sizeof(Entry), &newStorage)) {
+ throwOutOfMemoryError(exec);
+ return false;
+ }
+ Entry* newEntries = static_cast<Entry*>(newStorage);
+ // Do a read barrier to ensure that m_entries points to to-space for the remainder of this GC epoch.
+ m_entries.get(m_owner);
+ if (shouldPack())
+ replaceAndPackBackingStore(newEntries, requiredSize);
+ else
+ replaceBackingStore(newEntries, requiredSize);
+ exec->heap()->writeBarrier(owner);
+ return true;
+}
+
+template<typename Entry, typename JSIterator>
+inline void MapDataImpl<Entry, JSIterator>::visitChildren(JSCell* owner, SlotVisitor& visitor)
+{
+ Entry* entries = m_entries.getWithoutBarrier();
+ if (!entries)
+ return;
+ if (m_deletedCount) {
+ for (int32_t i = 0; i < m_size; i++) {
+ if (!entries[i].key())
+ continue;
+ entries[i].visitChildren(visitor);
+ }
+ } else {
+ // Guaranteed that all fields of Entry type is WriteBarrier<Unknown>.
+ visitor.appendValues(reinterpret_cast<WriteBarrier<Unknown>*>(&entries[0]), m_size * (sizeof(Entry) / sizeof(WriteBarrier<Unknown>)));
+ }
+
+ visitor.copyLater(owner, MapBackingStoreCopyToken, m_entries.getWithoutBarrier(), capacityInBytes());
+}
+
+template<typename Entry, typename JSIterator>
+inline void MapDataImpl<Entry, JSIterator>::copyBackingStore(CopyVisitor& visitor, CopyToken token)
+{
+ if (token == MapBackingStoreCopyToken && visitor.checkIfShouldCopy(m_entries.getWithoutBarrier())) {
+ Entry* oldEntries = m_entries.getWithoutBarrier();
+ Entry* newEntries = static_cast<Entry*>(visitor.allocateNewSpace(capacityInBytes()));
+ if (shouldPack())
+ replaceAndPackBackingStore(newEntries, m_capacity);
+ else
+ replaceBackingStore(newEntries, m_capacity);
+ visitor.didCopy(oldEntries, capacityInBytes());
+ }
+}
+
+template<typename Entry, typename JSIterator>
+inline auto MapDataImpl<Entry, JSIterator>::createIteratorData(JSIterator* iterator) -> IteratorData
+{
+ m_iterators.set(iterator, iterator);
+ return IteratorData(this);
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/MapIteratorPrototype.cpp b/Source/JavaScriptCore/runtime/MapIteratorPrototype.cpp
index 048bf932c..0b060eb45 100644
--- a/Source/JavaScriptCore/runtime/MapIteratorPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/MapIteratorPrototype.cpp
@@ -26,31 +26,26 @@
#include "config.h"
#include "MapIteratorPrototype.h"
+#include "IteratorOperations.h"
#include "JSCJSValueInlines.h"
#include "JSCellInlines.h"
#include "JSMapIterator.h"
+#include "StructureInlines.h"
namespace JSC {
-const ClassInfo MapIteratorPrototype::s_info = { "Map Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(MapIteratorPrototype) };
+const ClassInfo MapIteratorPrototype::s_info = { "Map Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(MapIteratorPrototype) };
-static EncodedJSValue JSC_HOST_CALL MapIteratorPrototypeFuncIterator(ExecState*);
static EncodedJSValue JSC_HOST_CALL MapIteratorPrototypeFuncNext(ExecState*);
-
void MapIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
{
Base::finishCreation(vm);
ASSERT(inherits(info()));
vm.prototypeMap.addPrototype(this);
- JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, MapIteratorPrototypeFuncIterator, DontEnum, 0);
- JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorNextPrivateName, MapIteratorPrototypeFuncNext, DontEnum, 0);
-}
-
-EncodedJSValue JSC_HOST_CALL MapIteratorPrototypeFuncIterator(CallFrame* callFrame)
-{
- return JSValue::encode(callFrame->thisValue());
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->next, MapIteratorPrototypeFuncNext, DontEnum, 0);
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Map Iterator"), DontEnum | ReadOnly);
}
EncodedJSValue JSC_HOST_CALL MapIteratorPrototypeFuncNext(CallFrame* callFrame)
@@ -58,12 +53,12 @@ EncodedJSValue JSC_HOST_CALL MapIteratorPrototypeFuncNext(CallFrame* callFrame)
JSMapIterator* iterator = jsDynamicCast<JSMapIterator*>(callFrame->thisValue());
if (!iterator)
return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot call MapIterator.next() on a non-MapIterator object")));
-
+
JSValue result;
if (iterator->next(callFrame, result))
- return JSValue::encode(result);
+ return JSValue::encode(createIteratorResultObject(callFrame, result, false));
iterator->finish();
- return JSValue::encode(callFrame->vm().iterationTerminator.get());
+ return JSValue::encode(createIteratorResultObject(callFrame, jsUndefined(), true));
}
diff --git a/Source/JavaScriptCore/runtime/MapPrototype.cpp b/Source/JavaScriptCore/runtime/MapPrototype.cpp
index 889599e0e..fb8b541fc 100644
--- a/Source/JavaScriptCore/runtime/MapPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/MapPrototype.cpp
@@ -30,19 +30,29 @@
#include "Error.h"
#include "ExceptionHelpers.h"
#include "GetterSetter.h"
+#include "IteratorOperations.h"
#include "JSCJSValueInlines.h"
#include "JSFunctionInlines.h"
#include "JSMap.h"
#include "JSMapIterator.h"
-#include "MapData.h"
+#include "Lookup.h"
+#include "MapDataInlines.h"
+#include "StructureInlines.h"
+
+#include "MapPrototype.lut.h"
namespace JSC {
-const ClassInfo MapPrototype::s_info = { "Map", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(MapPrototype) };
+const ClassInfo MapPrototype::s_info = { "Map", &Base::s_info, &mapPrototypeTable, CREATE_METHOD_TABLE(MapPrototype) };
+
+/* Source for MapPrototype.lut.h
+@begin mapPrototypeTable
+ forEach JSBuiltin DontEnum|Function 0
+@end
+*/
static EncodedJSValue JSC_HOST_CALL mapProtoFuncClear(ExecState*);
static EncodedJSValue JSC_HOST_CALL mapProtoFuncDelete(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mapProtoFuncForEach(ExecState*);
static EncodedJSValue JSC_HOST_CALL mapProtoFuncGet(ExecState*);
static EncodedJSValue JSC_HOST_CALL mapProtoFuncHas(ExecState*);
static EncodedJSValue JSC_HOST_CALL mapProtoFuncSet(ExecState*);
@@ -58,120 +68,97 @@ void MapPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
ASSERT(inherits(info()));
vm.prototypeMap.addPrototype(this);
- JSC_NATIVE_FUNCTION(vm.propertyNames->clear, mapProtoFuncClear, DontEnum, 0);
- JSC_NATIVE_FUNCTION(vm.propertyNames->deleteKeyword, mapProtoFuncDelete, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->forEach, mapProtoFuncForEach, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->get, mapProtoFuncGet, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->has, mapProtoFuncHas, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->set, mapProtoFuncSet, DontEnum, 2);
- JSC_NATIVE_FUNCTION(vm.propertyNames->keys, mapProtoFuncKeys, DontEnum, 0);
- JSC_NATIVE_FUNCTION(vm.propertyNames->values, mapProtoFuncValues, DontEnum, 0);
- JSC_NATIVE_FUNCTION(vm.propertyNames->entries, mapProtoFuncEntries, DontEnum, 0);
- JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, mapProtoFuncEntries, DontEnum, 0);
-
- GetterSetter* accessor = GetterSetter::create(vm);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->clear, mapProtoFuncClear, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->deleteKeyword, mapProtoFuncDelete, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->get, mapProtoFuncGet, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, mapProtoFuncHas, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->set, mapProtoFuncSet, DontEnum, 2);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->keys, mapProtoFuncKeys, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->values, mapProtoFuncValues, DontEnum, 0);
+
+ // Private get / set operations.
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->getPrivateName, mapProtoFuncGet, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->setPrivateName, mapProtoFuncSet, DontEnum, 2);
+
+ JSFunction* entries = JSFunction::create(vm, globalObject, 0, vm.propertyNames->entries.string(), mapProtoFuncEntries);
+ putDirectWithoutTransition(vm, vm.propertyNames->entries, entries, DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, entries, DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Map"), DontEnum | ReadOnly);
+
+ GetterSetter* accessor = GetterSetter::create(vm, globalObject);
JSFunction* function = JSFunction::create(vm, globalObject, 0, vm.propertyNames->size.string(), mapProtoFuncSize);
- accessor->setGetter(vm, function);
+ accessor->setGetter(vm, globalObject, function);
putDirectNonIndexAccessor(vm, vm.propertyNames->size, accessor, DontEnum | Accessor);
}
-ALWAYS_INLINE static MapData* getMapData(CallFrame* callFrame, JSValue thisValue)
+bool MapPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<Base>(exec, mapPrototypeTable, jsCast<MapPrototype*>(object), propertyName, slot);
+}
+
+ALWAYS_INLINE static JSMap* getMap(CallFrame* callFrame, JSValue thisValue)
{
if (!thisValue.isObject()) {
throwVMError(callFrame, createNotAnObjectError(callFrame, thisValue));
- return 0;
+ return nullptr;
}
JSMap* map = jsDynamicCast<JSMap*>(thisValue);
if (!map) {
throwTypeError(callFrame, ASCIILiteral("Map operation called on non-Map object"));
- return 0;
+ return nullptr;
}
- return map->mapData();
+ return map;
}
EncodedJSValue JSC_HOST_CALL mapProtoFuncClear(CallFrame* callFrame)
{
- MapData* data = getMapData(callFrame, callFrame->thisValue());
- if (!data)
+ JSMap* map = getMap(callFrame, callFrame->thisValue());
+ if (!map)
return JSValue::encode(jsUndefined());
- data->clear();
+ map->clear(callFrame);
return JSValue::encode(jsUndefined());
}
EncodedJSValue JSC_HOST_CALL mapProtoFuncDelete(CallFrame* callFrame)
{
- MapData* data = getMapData(callFrame, callFrame->thisValue());
- if (!data)
+ JSMap* map = getMap(callFrame, callFrame->thisValue());
+ if (!map)
return JSValue::encode(jsUndefined());
- return JSValue::encode(jsBoolean(data->remove(callFrame, callFrame->argument(0))));
-}
-
-EncodedJSValue JSC_HOST_CALL mapProtoFuncForEach(CallFrame* callFrame)
-{
- MapData* data = getMapData(callFrame, callFrame->thisValue());
- if (!data)
- return JSValue::encode(jsUndefined());
- JSValue callBack = callFrame->argument(0);
- CallData callData;
- CallType callType = getCallData(callBack, callData);
- if (callType == CallTypeNone)
- return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("Map.prototype.forEach called without callback")));
- JSValue thisValue = callFrame->argument(1);
- VM* vm = &callFrame->vm();
- if (callType == CallTypeJS) {
- JSFunction* function = jsCast<JSFunction*>(callBack);
- CachedCall cachedCall(callFrame, function, 2);
- for (auto ptr = data->begin(), end = data->end(); ptr != end && !vm->exception(); ++ptr) {
- cachedCall.setThis(thisValue);
- cachedCall.setArgument(0, ptr.value());
- cachedCall.setArgument(1, ptr.key());
- cachedCall.call();
- }
- } else {
- for (auto ptr = data->begin(), end = data->end(); ptr != end && !vm->exception(); ++ptr) {
- MarkedArgumentBuffer args;
- args.append(ptr.value());
- args.append(ptr.key());
- JSC::call(callFrame, callBack, callType, callData, thisValue, args);
- }
- }
- return JSValue::encode(jsUndefined());
+ return JSValue::encode(jsBoolean(map->remove(callFrame, callFrame->argument(0))));
}
EncodedJSValue JSC_HOST_CALL mapProtoFuncGet(CallFrame* callFrame)
{
- MapData* data = getMapData(callFrame, callFrame->thisValue());
- if (!data)
+ JSMap* map = getMap(callFrame, callFrame->thisValue());
+ if (!map)
return JSValue::encode(jsUndefined());
- JSValue result = data->get(callFrame, callFrame->argument(0));
- if (!result)
- result = jsUndefined();
- return JSValue::encode(result);
+ return JSValue::encode(map->get(callFrame, callFrame->argument(0)));
}
EncodedJSValue JSC_HOST_CALL mapProtoFuncHas(CallFrame* callFrame)
{
- MapData* data = getMapData(callFrame, callFrame->thisValue());
- if (!data)
+ JSMap* map = getMap(callFrame, callFrame->thisValue());
+ if (!map)
return JSValue::encode(jsUndefined());
- return JSValue::encode(jsBoolean(data->contains(callFrame, callFrame->argument(0))));
+ return JSValue::encode(jsBoolean(map->has(callFrame, callFrame->argument(0))));
}
EncodedJSValue JSC_HOST_CALL mapProtoFuncSet(CallFrame* callFrame)
{
- MapData* data = getMapData(callFrame, callFrame->thisValue());
- if (!data)
+ JSValue thisValue = callFrame->thisValue();
+ JSMap* map = getMap(callFrame, thisValue);
+ if (!map)
return JSValue::encode(jsUndefined());
- data->set(callFrame, callFrame->argument(0), callFrame->argument(1));
- return JSValue::encode(callFrame->thisValue());
+ map->set(callFrame, callFrame->argument(0), callFrame->argument(1));
+ return JSValue::encode(thisValue);
}
EncodedJSValue JSC_HOST_CALL mapProtoFuncSize(CallFrame* callFrame)
{
- MapData* data = getMapData(callFrame, callFrame->thisValue());
- if (!data)
+ JSMap* map = getMap(callFrame, callFrame->thisValue());
+ if (!map)
return JSValue::encode(jsUndefined());
- return JSValue::encode(jsNumber(data->size(callFrame)));
+ return JSValue::encode(jsNumber(map->size(callFrame)));
}
EncodedJSValue JSC_HOST_CALL mapProtoFuncValues(CallFrame* callFrame)
@@ -186,7 +173,7 @@ EncodedJSValue JSC_HOST_CALL mapProtoFuncEntries(CallFrame* callFrame)
{
JSMap* thisObj = jsDynamicCast<JSMap*>(callFrame->thisValue());
if (!thisObj)
- return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Map key iterator for a non-Map object.")));
+ return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Map entry iterator for a non-Map object.")));
return JSValue::encode(JSMapIterator::create(callFrame->vm(), callFrame->callee()->globalObject()->mapIteratorStructure(), thisObj, MapIterateKeyValue));
}
@@ -194,8 +181,35 @@ EncodedJSValue JSC_HOST_CALL mapProtoFuncKeys(CallFrame* callFrame)
{
JSMap* thisObj = jsDynamicCast<JSMap*>(callFrame->thisValue());
if (!thisObj)
- return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Map entry iterator for a non-Map object.")));
+ return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Map key iterator for a non-Map object.")));
return JSValue::encode(JSMapIterator::create(callFrame->vm(), callFrame->callee()->globalObject()->mapIteratorStructure(), thisObj, MapIterateKey));
}
+EncodedJSValue JSC_HOST_CALL privateFuncIsMap(ExecState* exec)
+{
+ return JSValue::encode(jsBoolean(jsDynamicCast<JSMap*>(exec->uncheckedArgument(0))));
+}
+
+EncodedJSValue JSC_HOST_CALL privateFuncMapIterator(ExecState* exec)
+{
+ ASSERT(jsDynamicCast<JSMap*>(exec->uncheckedArgument(0)));
+ JSMap* map = jsCast<JSMap*>(exec->uncheckedArgument(0));
+ return JSValue::encode(JSMapIterator::create(exec->vm(), exec->callee()->globalObject()->mapIteratorStructure(), map, MapIterateKeyValue));
+}
+
+EncodedJSValue JSC_HOST_CALL privateFuncMapIteratorNext(ExecState* exec)
+{
+ ASSERT(jsDynamicCast<JSMapIterator*>(exec->thisValue()));
+ JSMapIterator* iterator = jsCast<JSMapIterator*>(exec->thisValue());
+ JSValue key, value;
+ if (iterator->nextKeyValue(key, value)) {
+ JSArray* resultArray = jsCast<JSArray*>(exec->uncheckedArgument(0));
+ resultArray->putDirectIndex(exec, 0, key);
+ resultArray->putDirectIndex(exec, 1, value);
+ return JSValue::encode(jsBoolean(false));
+ }
+ iterator->finish();
+ return JSValue::encode(jsBoolean(true));
+}
+
}
diff --git a/Source/JavaScriptCore/runtime/MapPrototype.h b/Source/JavaScriptCore/runtime/MapPrototype.h
index eaa582537..3e72567db 100644
--- a/Source/JavaScriptCore/runtime/MapPrototype.h
+++ b/Source/JavaScriptCore/runtime/MapPrototype.h
@@ -34,6 +34,8 @@ class MapPrototype : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | Base::StructureFlags;
+
static MapPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
{
MapPrototype* prototype = new (NotNull, allocateCell<MapPrototype>(vm.heap)) MapPrototype(vm, structure);
@@ -54,8 +56,13 @@ private:
{
}
void finishCreation(VM&, JSGlobalObject*);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
};
+EncodedJSValue JSC_HOST_CALL privateFuncIsMap(ExecState*);
+EncodedJSValue JSC_HOST_CALL privateFuncMapIterator(ExecState*);
+EncodedJSValue JSC_HOST_CALL privateFuncMapIteratorNext(ExecState*);
+
}
#endif // !defined(MapPrototype_h)
diff --git a/Source/JavaScriptCore/runtime/MathCommon.cpp b/Source/JavaScriptCore/runtime/MathCommon.cpp
new file mode 100644
index 000000000..d6882c03e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/MathCommon.cpp
@@ -0,0 +1,443 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "MathCommon.h"
+
+#include <cmath>
+#include "PureNaN.h"
+
+namespace JSC {
+
+#if PLATFORM(IOS) && CPU(ARM_THUMB2)
+
+// The following code is taken from netlib.org:
+// http://www.netlib.org/fdlibm/fdlibm.h
+// http://www.netlib.org/fdlibm/e_pow.c
+// http://www.netlib.org/fdlibm/s_scalbn.c
+//
+// And was originally distributed under the following license:
+
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+/*
+ * ====================================================
+ * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_pow(x,y) return x**y
+ *
+ * n
+ * Method: Let x = 2 * (1+f)
+ * 1. Compute and return log2(x) in two pieces:
+ * log2(x) = w1 + w2,
+ * where w1 has 53-24 = 29 bit trailing zeros.
+ * 2. Perform y*log2(x) = n+y' by simulating muti-precision
+ * arithmetic, where |y'|<=0.5.
+ * 3. Return x**y = 2**n*exp(y'*log2)
+ *
+ * Special cases:
+ * 1. (anything) ** 0 is 1
+ * 2. (anything) ** 1 is itself
+ * 3. (anything) ** NAN is NAN
+ * 4. NAN ** (anything except 0) is NAN
+ * 5. +-(|x| > 1) ** +INF is +INF
+ * 6. +-(|x| > 1) ** -INF is +0
+ * 7. +-(|x| < 1) ** +INF is +0
+ * 8. +-(|x| < 1) ** -INF is +INF
+ * 9. +-1 ** +-INF is NAN
+ * 10. +0 ** (+anything except 0, NAN) is +0
+ * 11. -0 ** (+anything except 0, NAN, odd integer) is +0
+ * 12. +0 ** (-anything except 0, NAN) is +INF
+ * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF
+ * 14. -0 ** (odd integer) = -( +0 ** (odd integer) )
+ * 15. +INF ** (+anything except 0,NAN) is +INF
+ * 16. +INF ** (-anything except 0,NAN) is +0
+ * 17. -INF ** (anything) = -0 ** (-anything)
+ * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
+ * 19. (-anything except 0 and inf) ** (non-integer) is NAN
+ *
+ * Accuracy:
+ * pow(x,y) returns x**y nearly rounded. In particular
+ * pow(integer,integer)
+ * always returns the correct integer provided it is
+ * representable.
+ *
+ * Constants :
+ * The hexadecimal values are the intended ones for the following
+ * constants. The decimal values may be used, provided that the
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#define __HI(x) *(1+(int*)&x)
+#define __LO(x) *(int*)&x
+
+static const double
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
+dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
+zero = 0.0,
+one = 1.0,
+two = 2.0,
+two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */
+huge = 1.0e300,
+tiny = 1.0e-300,
+/* for scalbn */
+two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
+/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
+L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
+L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
+L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
+L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
+L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
+P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
+lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
+lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
+ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
+cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
+cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
+cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
+ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
+ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
+ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
+
+inline double fdlibmScalbn (double x, int n)
+{
+ int k,hx,lx;
+ hx = __HI(x);
+ lx = __LO(x);
+ k = (hx&0x7ff00000)>>20; /* extract exponent */
+ if (k==0) { /* 0 or subnormal x */
+ if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
+ x *= two54;
+ hx = __HI(x);
+ k = ((hx&0x7ff00000)>>20) - 54;
+ if (n< -50000) return tiny*x; /*underflow*/
+ }
+ if (k==0x7ff) return x+x; /* NaN or Inf */
+ k = k+n;
+ if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */
+ if (k > 0) /* normal result */
+ {__HI(x) = (hx&0x800fffff)|(k<<20); return x;}
+ if (k <= -54) {
+ if (n > 50000) /* in case integer overflow in n+k */
+ return huge*copysign(huge,x); /*overflow*/
+ else return tiny*copysign(tiny,x); /*underflow*/
+ }
+ k += 54; /* subnormal result */
+ __HI(x) = (hx&0x800fffff)|(k<<20);
+ return x*twom54;
+}
+
+static double fdlibmPow(double x, double y)
+{
+ double z,ax,z_h,z_l,p_h,p_l;
+ double y1,t1,t2,r,s,t,u,v,w;
+ int i0,i1,i,j,k,yisint,n;
+ int hx,hy,ix,iy;
+ unsigned lx,ly;
+
+ i0 = ((*(int*)&one)>>29)^1; i1=1-i0;
+ hx = __HI(x); lx = __LO(x);
+ hy = __HI(y); ly = __LO(y);
+ ix = hx&0x7fffffff; iy = hy&0x7fffffff;
+
+ /* y==zero: x**0 = 1 */
+ if((iy|ly)==0) return one;
+
+ /* +-NaN return x+y */
+ if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
+ iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0)))
+ return x+y;
+
+ /* determine if y is an odd int when x < 0
+ * yisint = 0 ... y is not an integer
+ * yisint = 1 ... y is an odd int
+ * yisint = 2 ... y is an even int
+ */
+ yisint = 0;
+ if(hx<0) {
+ if(iy>=0x43400000) yisint = 2; /* even integer y */
+ else if(iy>=0x3ff00000) {
+ k = (iy>>20)-0x3ff; /* exponent */
+ if(k>20) {
+ j = ly>>(52-k);
+ if(static_cast<unsigned>(j<<(52-k))==ly) yisint = 2-(j&1);
+ } else if(ly==0) {
+ j = iy>>(20-k);
+ if((j<<(20-k))==iy) yisint = 2-(j&1);
+ }
+ }
+ }
+
+ /* special value of y */
+ if(ly==0) {
+ if (iy==0x7ff00000) { /* y is +-inf */
+ if(((ix-0x3ff00000)|lx)==0)
+ return y - y; /* inf**+-1 is NaN */
+ else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
+ return (hy>=0)? y: zero;
+ else /* (|x|<1)**-,+inf = inf,0 */
+ return (hy<0)?-y: zero;
+ }
+ if(iy==0x3ff00000) { /* y is +-1 */
+ if(hy<0) return one/x; else return x;
+ }
+ if(hy==0x40000000) return x*x; /* y is 2 */
+ if(hy==0x3fe00000) { /* y is 0.5 */
+ if(hx>=0) /* x >= +0 */
+ return sqrt(x);
+ }
+ }
+
+ ax = fabs(x);
+ /* special value of x */
+ if(lx==0) {
+ if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
+ z = ax; /*x is +-0,+-inf,+-1*/
+ if(hy<0) z = one/z; /* z = (1/|x|) */
+ if(hx<0) {
+ if(((ix-0x3ff00000)|yisint)==0) {
+ z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+ } else if(yisint==1)
+ z = -z; /* (x<0)**odd = -(|x|**odd) */
+ }
+ return z;
+ }
+ }
+
+ n = (hx>>31)+1;
+
+ /* (x<0)**(non-int) is NaN */
+ if((n|yisint)==0) return (x-x)/(x-x);
+
+ s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+ if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
+
+ /* |y| is huge */
+ if(iy>0x41e00000) { /* if |y| > 2**31 */
+ if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */
+ if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny;
+ if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny;
+ }
+ /* over/underflow if x is not close to one */
+ if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny;
+ if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny;
+ /* now |1-x| is tiny <= 2**-20, suffice to compute
+ log(x) by x-x^2/2+x^3/3-x^4/4 */
+ t = ax-one; /* t has 20 trailing zeros */
+ w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));
+ u = ivln2_h*t; /* ivln2_h has 21 sig. bits */
+ v = t*ivln2_l-w*ivln2;
+ t1 = u+v;
+ __LO(t1) = 0;
+ t2 = v-(t1-u);
+ } else {
+ double ss,s2,s_h,s_l,t_h,t_l;
+ n = 0;
+ /* take care subnormal number */
+ if(ix<0x00100000)
+ {ax *= two53; n -= 53; ix = __HI(ax); }
+ n += ((ix)>>20)-0x3ff;
+ j = ix&0x000fffff;
+ /* determine interval */
+ ix = j|0x3ff00000; /* normalize ix */
+ if(j<=0x3988E) k=0; /* |x|<sqrt(3/2) */
+ else if(j<0xBB67A) k=1; /* |x|<sqrt(3) */
+ else {k=0;n+=1;ix -= 0x00100000;}
+ __HI(ax) = ix;
+
+ /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+ u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */
+ v = one/(ax+bp[k]);
+ ss = u*v;
+ s_h = ss;
+ __LO(s_h) = 0;
+ /* t_h=ax+bp[k] High */
+ t_h = zero;
+ __HI(t_h)=((ix>>1)|0x20000000)+0x00080000+(k<<18);
+ t_l = ax - (t_h-bp[k]);
+ s_l = v*((u-s_h*t_h)-s_h*t_l);
+ /* compute log(ax) */
+ s2 = ss*ss;
+ r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+ r += s_l*(s_h+ss);
+ s2 = s_h*s_h;
+ t_h = 3.0+s2+r;
+ __LO(t_h) = 0;
+ t_l = r-((t_h-3.0)-s2);
+ /* u+v = ss*(1+...) */
+ u = s_h*t_h;
+ v = s_l*t_h+t_l*ss;
+ /* 2/(3log2)*(ss+...) */
+ p_h = u+v;
+ __LO(p_h) = 0;
+ p_l = v-(p_h-u);
+ z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */
+ z_l = cp_l*p_h+p_l*cp+dp_l[k];
+ /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+ t = (double)n;
+ t1 = (((z_h+z_l)+dp_h[k])+t);
+ __LO(t1) = 0;
+ t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+ }
+
+ /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+ y1 = y;
+ __LO(y1) = 0;
+ p_l = (y-y1)*t1+y*t2;
+ p_h = y1*t1;
+ z = p_l+p_h;
+ j = __HI(z);
+ i = __LO(z);
+ if (j>=0x40900000) { /* z >= 1024 */
+ if(((j-0x40900000)|i)!=0) /* if z > 1024 */
+ return s*huge*huge; /* overflow */
+ else {
+ if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */
+ }
+ } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */
+ if(((j-0xc090cc00)|i)!=0) /* z < -1075 */
+ return s*tiny*tiny; /* underflow */
+ else {
+ if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */
+ }
+ }
+ /*
+ * compute 2**(p_h+p_l)
+ */
+ i = j&0x7fffffff;
+ k = (i>>20)-0x3ff;
+ n = 0;
+ if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */
+ n = j+(0x00100000>>(k+1));
+ k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */
+ t = zero;
+ __HI(t) = (n&~(0x000fffff>>k));
+ n = ((n&0x000fffff)|0x00100000)>>(20-k);
+ if(j<0) n = -n;
+ p_h -= t;
+ }
+ t = p_l+p_h;
+ __LO(t) = 0;
+ u = t*lg2_h;
+ v = (p_l-(t-p_h))*lg2+t*lg2_l;
+ z = u+v;
+ w = v-(z-u);
+ t = z*z;
+ t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+ r = (z*t1)/(t1-two)-(w+z*w);
+ z = one-(r-z);
+ j = __HI(z);
+ j += (n<<20);
+ if((j>>20)<=0) z = fdlibmScalbn(z,n); /* subnormal output */
+ else __HI(z) += (n<<20);
+ return s*z;
+}
+
+static ALWAYS_INLINE bool isDenormal(double x)
+{
+ static const uint64_t signbit = 0x8000000000000000ULL;
+ static const uint64_t minNormal = 0x0001000000000000ULL;
+ return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 < minNormal - 1;
+}
+
+static ALWAYS_INLINE bool isEdgeCase(double x)
+{
+ static const uint64_t signbit = 0x8000000000000000ULL;
+ static const uint64_t infinity = 0x7fffffffffffffffULL;
+ return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 >= infinity - 1;
+}
+
+static ALWAYS_INLINE double mathPowInternal(double x, double y)
+{
+ if (!isDenormal(x) && !isDenormal(y)) {
+ double libmResult = std::pow(x, y);
+ if (libmResult || isEdgeCase(x) || isEdgeCase(y))
+ return libmResult;
+ }
+ return fdlibmPow(x, y);
+}
+
+#else
+
+ALWAYS_INLINE double mathPowInternal(double x, double y)
+{
+ return pow(x, y);
+}
+
+#endif
+
+double JIT_OPERATION operationMathPow(double x, double y)
+{
+ if (std::isnan(y))
+ return PNaN;
+ if (std::isinf(y) && fabs(x) == 1)
+ return PNaN;
+ int32_t yAsInt = y;
+ if (static_cast<double>(yAsInt) != y || yAsInt < 0)
+ return mathPowInternal(x, y);
+
+ // If the exponent is a positive int32 integer, we do a fast exponentiation
+ double result = 1;
+ while (yAsInt) {
+ if (yAsInt & 1)
+ result *= x;
+ x *= x;
+ yAsInt >>= 1;
+ }
+ return result;
+}
+
+extern "C" {
+double jsRound(double value)
+{
+ double integer = ceil(value);
+ return integer - (integer - value > 0.5);
+}
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/MathCommon.h b/Source/JavaScriptCore/runtime/MathCommon.h
new file mode 100644
index 000000000..2f84ed727
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/MathCommon.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#ifndef MathCommon_h
+#define MathCommon_h
+
+#include "JITOperations.h"
+
+#ifndef JIT_OPERATION
+#define JIT_OPERATION
+#endif
+
+namespace JSC {
+double JIT_OPERATION operationMathPow(double x, double y) WTF_INTERNAL;
+
+inline int clz32(uint32_t number)
+{
+#if COMPILER(GCC_OR_CLANG)
+ int zeroCount = 32;
+ if (number)
+ zeroCount = __builtin_clz(number);
+ return zeroCount;
+#else
+ int zeroCount = 0;
+ for (int i = 31; i >= 0; i--) {
+ if (!(number >> i))
+ zeroCount++;
+ else
+ break;
+ }
+ return zeroCount;
+#endif
+}
+
+extern "C" {
+double JIT_OPERATION jsRound(double value) REFERENCED_FROM_ASM WTF_INTERNAL;
+}
+
+}
+
+#endif // MathCommon_h
diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp
index ca355ed44..997b0647e 100644
--- a/Source/JavaScriptCore/runtime/MathObject.cpp
+++ b/Source/JavaScriptCore/runtime/MathObject.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2007, 2008, 2013 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2007, 2008, 2013, 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
@@ -22,56 +22,59 @@
#include "MathObject.h"
#include "Lookup.h"
+#include "MathCommon.h"
#include "ObjectPrototype.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include <time.h>
#include <wtf/Assertions.h>
#include <wtf/MathExtras.h>
#include <wtf/RandomNumber.h>
#include <wtf/RandomNumberSeed.h>
+#include <wtf/Vector.h>
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(MathObject);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncACos(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncACosh(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncASin(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncASinh(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncATan(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncATanh(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncCbrt(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncCosh(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncExp(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncExpm1(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncFround(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog1p(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog10(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog2(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncSinh(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncTanh(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncTrunc(ExecState*);
-static EncodedJSValue JSC_HOST_CALL mathProtoFuncIMul(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncACos(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncACosh(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncASin(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncASinh(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncATan(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncATanh(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncCbrt(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncClz32(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncCosh(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncExp(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncExpm1(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncFround(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncHypot(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncLog1p(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncLog10(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncLog2(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncSign(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncSinh(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncTanh(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncTrunc(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncIMul(ExecState*);
}
namespace JSC {
-const ClassInfo MathObject::s_info = { "Math", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(MathObject) };
+const ClassInfo MathObject::s_info = { "Math", &Base::s_info, 0, CREATE_METHOD_TABLE(MathObject) };
MathObject::MathObject(VM& vm, Structure* structure)
: JSNonFinalObject(vm, structure)
@@ -83,47 +86,51 @@ void MathObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
Base::finishCreation(vm);
ASSERT(inherits(info()));
- putDirectWithoutTransition(vm, Identifier(&vm, "E"), jsNumber(exp(1.0)), DontDelete | DontEnum | ReadOnly);
- putDirectWithoutTransition(vm, Identifier(&vm, "LN2"), jsNumber(log(2.0)), DontDelete | DontEnum | ReadOnly);
- putDirectWithoutTransition(vm, Identifier(&vm, "LN10"), jsNumber(log(10.0)), DontDelete | DontEnum | ReadOnly);
- putDirectWithoutTransition(vm, Identifier(&vm, "LOG2E"), jsNumber(1.0 / log(2.0)), DontDelete | DontEnum | ReadOnly);
- putDirectWithoutTransition(vm, Identifier(&vm, "LOG10E"), jsNumber(0.4342944819032518), DontDelete | DontEnum | ReadOnly);
- putDirectWithoutTransition(vm, Identifier(&vm, "PI"), jsNumber(piDouble), DontDelete | DontEnum | ReadOnly);
- putDirectWithoutTransition(vm, Identifier(&vm, "SQRT1_2"), jsNumber(sqrt(0.5)), DontDelete | DontEnum | ReadOnly);
- putDirectWithoutTransition(vm, Identifier(&vm, "SQRT2"), jsNumber(sqrt(2.0)), DontDelete | DontEnum | ReadOnly);
-
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "abs"), 1, mathProtoFuncAbs, AbsIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "acos"), 1, mathProtoFuncACos, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "asin"), 1, mathProtoFuncASin, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "atan"), 1, mathProtoFuncATan, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "acosh"), 1, mathProtoFuncACosh, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "asinh"), 1, mathProtoFuncASinh, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "atanh"), 1, mathProtoFuncATanh, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "atan2"), 2, mathProtoFuncATan2, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "cbrt"), 1, mathProtoFuncCbrt, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "ceil"), 1, mathProtoFuncCeil, CeilIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "cos"), 1, mathProtoFuncCos, CosIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "cosh"), 1, mathProtoFuncCosh, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "exp"), 1, mathProtoFuncExp, ExpIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "expm1"), 1, mathProtoFuncExpm1, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "floor"), 1, mathProtoFuncFloor, FloorIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "fround"), 1, mathProtoFuncFround, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log"), 1, mathProtoFuncLog, LogIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log10"), 1, mathProtoFuncLog10, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log1p"), 1, mathProtoFuncLog1p, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "log2"), 1, mathProtoFuncLog2, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "max"), 2, mathProtoFuncMax, MaxIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "min"), 2, mathProtoFuncMin, MinIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "pow"), 2, mathProtoFuncPow, PowIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "random"), 0, mathProtoFuncRandom, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "round"), 1, mathProtoFuncRound, RoundIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "sin"), 1, mathProtoFuncSin, SinIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "sinh"), 1, mathProtoFuncSinh, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "sqrt"), 1, mathProtoFuncSqrt, SqrtIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "tan"), 1, mathProtoFuncTan, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "tanh"), 1, mathProtoFuncTanh, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "trunc"), 1, mathProtoFuncTrunc, NoIntrinsic, DontEnum | Function);
- putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier(&vm, "imul"), 1, mathProtoFuncIMul, IMulIntrinsic, DontEnum | Function);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "E"), jsNumber(exp(1.0)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LN2"), jsNumber(log(2.0)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LN10"), jsNumber(log(10.0)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LOG2E"), jsNumber(1.0 / log(2.0)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "LOG10E"), jsNumber(0.4342944819032518), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "PI"), jsNumber(piDouble), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "SQRT1_2"), jsNumber(sqrt(0.5)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "SQRT2"), jsNumber(sqrt(2.0)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Math"), DontEnum | ReadOnly);
+
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "abs"), 1, mathProtoFuncAbs, AbsIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "acos"), 1, mathProtoFuncACos, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "asin"), 1, mathProtoFuncASin, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "atan"), 1, mathProtoFuncATan, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "acosh"), 1, mathProtoFuncACosh, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "asinh"), 1, mathProtoFuncASinh, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "atanh"), 1, mathProtoFuncATanh, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "atan2"), 2, mathProtoFuncATan2, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "cbrt"), 1, mathProtoFuncCbrt, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "ceil"), 1, mathProtoFuncCeil, CeilIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "clz32"), 1, mathProtoFuncClz32, Clz32Intrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "cos"), 1, mathProtoFuncCos, CosIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "cosh"), 1, mathProtoFuncCosh, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "exp"), 1, mathProtoFuncExp, ExpIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "expm1"), 1, mathProtoFuncExpm1, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "floor"), 1, mathProtoFuncFloor, FloorIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "fround"), 1, mathProtoFuncFround, FRoundIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "hypot"), 2, mathProtoFuncHypot, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log"), 1, mathProtoFuncLog, LogIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log10"), 1, mathProtoFuncLog10, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log1p"), 1, mathProtoFuncLog1p, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "log2"), 1, mathProtoFuncLog2, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "max"), 2, mathProtoFuncMax, MaxIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "min"), 2, mathProtoFuncMin, MinIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "pow"), 2, mathProtoFuncPow, PowIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "random"), 0, mathProtoFuncRandom, RandomIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "round"), 1, mathProtoFuncRound, RoundIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "sign"), 1, mathProtoFuncSign, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "sin"), 1, mathProtoFuncSin, SinIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "sinh"), 1, mathProtoFuncSinh, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "sqrt"), 1, mathProtoFuncSqrt, SqrtIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "tan"), 1, mathProtoFuncTan, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "tanh"), 1, mathProtoFuncTanh, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "trunc"), 1, mathProtoFuncTrunc, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "imul"), 2, mathProtoFuncIMul, IMulIntrinsic, DontEnum);
}
// ------------------------------ Functions --------------------------------
@@ -160,6 +167,14 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState* exec)
return JSValue::encode(jsNumber(ceil(exec->argument(0).toNumber(exec))));
}
+EncodedJSValue JSC_HOST_CALL mathProtoFuncClz32(ExecState* exec)
+{
+ uint32_t value = exec->argument(0).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+ return JSValue::encode(JSValue(clz32(value)));
+}
+
EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState* exec)
{
return JSValue::encode(jsDoubleNumber(cos(exec->argument(0).toNumber(exec))));
@@ -175,6 +190,35 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState* exec)
return JSValue::encode(jsNumber(floor(exec->argument(0).toNumber(exec))));
}
+EncodedJSValue JSC_HOST_CALL mathProtoFuncHypot(ExecState* exec)
+{
+ unsigned argsCount = exec->argumentCount();
+ double max = 0;
+ Vector<double, 8> args;
+ args.reserveInitialCapacity(argsCount);
+ for (unsigned i = 0; i < argsCount; ++i) {
+ args.uncheckedAppend(exec->uncheckedArgument(i).toNumber(exec));
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+ if (std::isinf(args[i]))
+ return JSValue::encode(jsDoubleNumber(+std::numeric_limits<double>::infinity()));
+ max = std::max(fabs(args[i]), max);
+ }
+ if (!max)
+ max = 1;
+ // Kahan summation algorithm significantly reduces the numerical error in the total obtained.
+ double sum = 0;
+ double compensation = 0;
+ for (double argument : args) {
+ double scaledArgument = argument / max;
+ double summand = scaledArgument * scaledArgument - compensation;
+ double preliminary = sum + summand;
+ compensation = (preliminary - sum) - summand;
+ sum = preliminary;
+ }
+ return JSValue::encode(jsDoubleNumber(sqrt(sum) * max));
+}
+
EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState* exec)
{
return JSValue::encode(jsDoubleNumber(log(exec->argument(0).toNumber(exec))));
@@ -187,10 +231,8 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState* exec)
for (unsigned k = 0; k < argsCount; ++k) {
double val = exec->uncheckedArgument(k).toNumber(exec);
if (std::isnan(val)) {
- result = QNaN;
- break;
- }
- if (val > result || (!val && !result && !std::signbit(val)))
+ result = PNaN;
+ } else if (val > result || (!val && !result && !std::signbit(val)))
result = val;
}
return JSValue::encode(jsNumber(result));
@@ -203,52 +245,13 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState* exec)
for (unsigned k = 0; k < argsCount; ++k) {
double val = exec->uncheckedArgument(k).toNumber(exec);
if (std::isnan(val)) {
- result = QNaN;
- break;
- }
- if (val < result || (!val && !result && std::signbit(val)))
+ result = PNaN;
+ } else if (val < result || (!val && !result && std::signbit(val)))
result = val;
}
return JSValue::encode(jsNumber(result));
}
-#if PLATFORM(IOS) && CPU(ARM_THUMB2)
-
-static double fdlibmPow(double x, double y);
-
-static ALWAYS_INLINE bool isDenormal(double x)
-{
- static const uint64_t signbit = 0x8000000000000000ULL;
- static const uint64_t minNormal = 0x0001000000000000ULL;
- return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 < minNormal - 1;
-}
-
-static ALWAYS_INLINE bool isEdgeCase(double x)
-{
- static const uint64_t signbit = 0x8000000000000000ULL;
- static const uint64_t infinity = 0x7fffffffffffffffULL;
- return (bitwise_cast<uint64_t>(x) & ~signbit) - 1 >= infinity - 1;
-}
-
-static ALWAYS_INLINE double mathPow(double x, double y)
-{
- if (!isDenormal(x) && !isDenormal(y)) {
- double libmResult = pow(x,y);
- if (libmResult || isEdgeCase(x) || isEdgeCase(y))
- return libmResult;
- }
- return fdlibmPow(x,y);
-}
-
-#else
-
-ALWAYS_INLINE double mathPow(double x, double y)
-{
- return pow(x, y);
-}
-
-#endif
-
EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec)
{
// ECMA 15.8.2.1.13
@@ -256,11 +259,7 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec)
double arg = exec->argument(0).toNumber(exec);
double arg2 = exec->argument(1).toNumber(exec);
- if (std::isnan(arg2))
- return JSValue::encode(jsNaN());
- if (std::isinf(arg2) && fabs(arg) == 1)
- return JSValue::encode(jsNaN());
- return JSValue::encode(jsNumber(mathPow(arg, arg2)));
+ return JSValue::encode(JSValue(operationMathPow(arg, arg2)));
}
EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec)
@@ -270,9 +269,17 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec)
EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec)
{
+ return JSValue::encode(jsNumber(jsRound(exec->argument(0).toNumber(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncSign(ExecState* exec)
+{
double arg = exec->argument(0).toNumber(exec);
- double integer = ceil(arg);
- return JSValue::encode(jsNumber(integer - (integer - arg > 0.5)));
+ if (std::isnan(arg))
+ return JSValue::encode(jsNaN());
+ if (!arg)
+ return JSValue::encode(std::signbit(arg) ? jsNumber(-0.0) : jsNumber(0));
+ return JSValue::encode(jsNumber(std::signbit(arg) ? -1 : 1));
}
EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState* exec)
@@ -367,354 +374,4 @@ EncodedJSValue JSC_HOST_CALL mathProtoFuncTrunc(ExecState*exec)
return JSValue::encode(jsNumber(exec->argument(0).toIntegerPreserveNaN(exec)));
}
-
-#if PLATFORM(IOS) && CPU(ARM_THUMB2)
-
-// The following code is taken from netlib.org:
-// http://www.netlib.org/fdlibm/fdlibm.h
-// http://www.netlib.org/fdlibm/e_pow.c
-// http://www.netlib.org/fdlibm/s_scalbn.c
-//
-// And was originally distributed under the following license:
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/*
- * ====================================================
- * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-/* __ieee754_pow(x,y) return x**y
- *
- * n
- * Method: Let x = 2 * (1+f)
- * 1. Compute and return log2(x) in two pieces:
- * log2(x) = w1 + w2,
- * where w1 has 53-24 = 29 bit trailing zeros.
- * 2. Perform y*log2(x) = n+y' by simulating muti-precision
- * arithmetic, where |y'|<=0.5.
- * 3. Return x**y = 2**n*exp(y'*log2)
- *
- * Special cases:
- * 1. (anything) ** 0 is 1
- * 2. (anything) ** 1 is itself
- * 3. (anything) ** NAN is NAN
- * 4. NAN ** (anything except 0) is NAN
- * 5. +-(|x| > 1) ** +INF is +INF
- * 6. +-(|x| > 1) ** -INF is +0
- * 7. +-(|x| < 1) ** +INF is +0
- * 8. +-(|x| < 1) ** -INF is +INF
- * 9. +-1 ** +-INF is NAN
- * 10. +0 ** (+anything except 0, NAN) is +0
- * 11. -0 ** (+anything except 0, NAN, odd integer) is +0
- * 12. +0 ** (-anything except 0, NAN) is +INF
- * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF
- * 14. -0 ** (odd integer) = -( +0 ** (odd integer) )
- * 15. +INF ** (+anything except 0,NAN) is +INF
- * 16. +INF ** (-anything except 0,NAN) is +0
- * 17. -INF ** (anything) = -0 ** (-anything)
- * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
- * 19. (-anything except 0 and inf) ** (non-integer) is NAN
- *
- * Accuracy:
- * pow(x,y) returns x**y nearly rounded. In particular
- * pow(integer,integer)
- * always returns the correct integer provided it is
- * representable.
- *
- * Constants :
- * The hexadecimal values are the intended ones for the following
- * constants. The decimal values may be used, provided that the
- * compiler will convert from decimal to binary accurately enough
- * to produce the hexadecimal values shown.
- */
-
-#define __HI(x) *(1+(int*)&x)
-#define __LO(x) *(int*)&x
-
-static const double
-bp[] = {1.0, 1.5,},
-dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
-dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
-zero = 0.0,
-one = 1.0,
-two = 2.0,
-two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */
-huge = 1.0e300,
-tiny = 1.0e-300,
- /* for scalbn */
-two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
-twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
- /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
-L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
-L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
-L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
-L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
-L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
-L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
-P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
-P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
-P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
-P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
-P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
-lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
-lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
-lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
-ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
-cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
-cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
-cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
-ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
-ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
-ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
-
-inline double fdlibmScalbn (double x, int n)
-{
- int k,hx,lx;
- hx = __HI(x);
- lx = __LO(x);
- k = (hx&0x7ff00000)>>20; /* extract exponent */
- if (k==0) { /* 0 or subnormal x */
- if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
- x *= two54;
- hx = __HI(x);
- k = ((hx&0x7ff00000)>>20) - 54;
- if (n< -50000) return tiny*x; /*underflow*/
- }
- if (k==0x7ff) return x+x; /* NaN or Inf */
- k = k+n;
- if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */
- if (k > 0) /* normal result */
- {__HI(x) = (hx&0x800fffff)|(k<<20); return x;}
- if (k <= -54) {
- if (n > 50000) /* in case integer overflow in n+k */
- return huge*copysign(huge,x); /*overflow*/
- else return tiny*copysign(tiny,x); /*underflow*/
- }
- k += 54; /* subnormal result */
- __HI(x) = (hx&0x800fffff)|(k<<20);
- return x*twom54;
-}
-
-double fdlibmPow(double x, double y)
-{
- double z,ax,z_h,z_l,p_h,p_l;
- double y1,t1,t2,r,s,t,u,v,w;
- int i0,i1,i,j,k,yisint,n;
- int hx,hy,ix,iy;
- unsigned lx,ly;
-
- i0 = ((*(int*)&one)>>29)^1; i1=1-i0;
- hx = __HI(x); lx = __LO(x);
- hy = __HI(y); ly = __LO(y);
- ix = hx&0x7fffffff; iy = hy&0x7fffffff;
-
- /* y==zero: x**0 = 1 */
- if((iy|ly)==0) return one;
-
- /* +-NaN return x+y */
- if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
- iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0)))
- return x+y;
-
- /* determine if y is an odd int when x < 0
- * yisint = 0 ... y is not an integer
- * yisint = 1 ... y is an odd int
- * yisint = 2 ... y is an even int
- */
- yisint = 0;
- if(hx<0) {
- if(iy>=0x43400000) yisint = 2; /* even integer y */
- else if(iy>=0x3ff00000) {
- k = (iy>>20)-0x3ff; /* exponent */
- if(k>20) {
- j = ly>>(52-k);
- if(static_cast<unsigned>(j<<(52-k))==ly) yisint = 2-(j&1);
- } else if(ly==0) {
- j = iy>>(20-k);
- if((j<<(20-k))==iy) yisint = 2-(j&1);
- }
- }
- }
-
- /* special value of y */
- if(ly==0) {
- if (iy==0x7ff00000) { /* y is +-inf */
- if(((ix-0x3ff00000)|lx)==0)
- return y - y; /* inf**+-1 is NaN */
- else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
- return (hy>=0)? y: zero;
- else /* (|x|<1)**-,+inf = inf,0 */
- return (hy<0)?-y: zero;
- }
- if(iy==0x3ff00000) { /* y is +-1 */
- if(hy<0) return one/x; else return x;
- }
- if(hy==0x40000000) return x*x; /* y is 2 */
- if(hy==0x3fe00000) { /* y is 0.5 */
- if(hx>=0) /* x >= +0 */
- return sqrt(x);
- }
- }
-
- ax = fabs(x);
- /* special value of x */
- if(lx==0) {
- if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
- z = ax; /*x is +-0,+-inf,+-1*/
- if(hy<0) z = one/z; /* z = (1/|x|) */
- if(hx<0) {
- if(((ix-0x3ff00000)|yisint)==0) {
- z = (z-z)/(z-z); /* (-1)**non-int is NaN */
- } else if(yisint==1)
- z = -z; /* (x<0)**odd = -(|x|**odd) */
- }
- return z;
- }
- }
-
- n = (hx>>31)+1;
-
- /* (x<0)**(non-int) is NaN */
- if((n|yisint)==0) return (x-x)/(x-x);
-
- s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
- if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
-
- /* |y| is huge */
- if(iy>0x41e00000) { /* if |y| > 2**31 */
- if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */
- if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny;
- if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny;
- }
- /* over/underflow if x is not close to one */
- if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny;
- if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny;
- /* now |1-x| is tiny <= 2**-20, suffice to compute
- log(x) by x-x^2/2+x^3/3-x^4/4 */
- t = ax-one; /* t has 20 trailing zeros */
- w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));
- u = ivln2_h*t; /* ivln2_h has 21 sig. bits */
- v = t*ivln2_l-w*ivln2;
- t1 = u+v;
- __LO(t1) = 0;
- t2 = v-(t1-u);
- } else {
- double ss,s2,s_h,s_l,t_h,t_l;
- n = 0;
- /* take care subnormal number */
- if(ix<0x00100000)
- {ax *= two53; n -= 53; ix = __HI(ax); }
- n += ((ix)>>20)-0x3ff;
- j = ix&0x000fffff;
- /* determine interval */
- ix = j|0x3ff00000; /* normalize ix */
- if(j<=0x3988E) k=0; /* |x|<sqrt(3/2) */
- else if(j<0xBB67A) k=1; /* |x|<sqrt(3) */
- else {k=0;n+=1;ix -= 0x00100000;}
- __HI(ax) = ix;
-
- /* compute ss = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
- u = ax-bp[k]; /* bp[0]=1.0, bp[1]=1.5 */
- v = one/(ax+bp[k]);
- ss = u*v;
- s_h = ss;
- __LO(s_h) = 0;
- /* t_h=ax+bp[k] High */
- t_h = zero;
- __HI(t_h)=((ix>>1)|0x20000000)+0x00080000+(k<<18);
- t_l = ax - (t_h-bp[k]);
- s_l = v*((u-s_h*t_h)-s_h*t_l);
- /* compute log(ax) */
- s2 = ss*ss;
- r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
- r += s_l*(s_h+ss);
- s2 = s_h*s_h;
- t_h = 3.0+s2+r;
- __LO(t_h) = 0;
- t_l = r-((t_h-3.0)-s2);
- /* u+v = ss*(1+...) */
- u = s_h*t_h;
- v = s_l*t_h+t_l*ss;
- /* 2/(3log2)*(ss+...) */
- p_h = u+v;
- __LO(p_h) = 0;
- p_l = v-(p_h-u);
- z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */
- z_l = cp_l*p_h+p_l*cp+dp_l[k];
- /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */
- t = (double)n;
- t1 = (((z_h+z_l)+dp_h[k])+t);
- __LO(t1) = 0;
- t2 = z_l-(((t1-t)-dp_h[k])-z_h);
- }
-
- /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
- y1 = y;
- __LO(y1) = 0;
- p_l = (y-y1)*t1+y*t2;
- p_h = y1*t1;
- z = p_l+p_h;
- j = __HI(z);
- i = __LO(z);
- if (j>=0x40900000) { /* z >= 1024 */
- if(((j-0x40900000)|i)!=0) /* if z > 1024 */
- return s*huge*huge; /* overflow */
- else {
- if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */
- }
- } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */
- if(((j-0xc090cc00)|i)!=0) /* z < -1075 */
- return s*tiny*tiny; /* underflow */
- else {
- if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */
- }
- }
- /*
- * compute 2**(p_h+p_l)
- */
- i = j&0x7fffffff;
- k = (i>>20)-0x3ff;
- n = 0;
- if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */
- n = j+(0x00100000>>(k+1));
- k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */
- t = zero;
- __HI(t) = (n&~(0x000fffff>>k));
- n = ((n&0x000fffff)|0x00100000)>>(20-k);
- if(j<0) n = -n;
- p_h -= t;
- }
- t = p_l+p_h;
- __LO(t) = 0;
- u = t*lg2_h;
- v = (p_l-(t-p_h))*lg2+t*lg2_l;
- z = u+v;
- w = v-(z-u);
- t = z*z;
- t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
- r = (z*t1)/(t1-two)-(w+z*w);
- z = one-(r-z);
- j = __HI(z);
- j += (n<<20);
- if((j>>20)<=0) z = fdlibmScalbn(z,n); /* subnormal output */
- else __HI(z) += (n<<20);
- return s*z;
-}
-
-#endif
-
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/MathObject.h b/Source/JavaScriptCore/runtime/MathObject.h
index 4b2a5bbec..9d1c181c0 100644
--- a/Source/JavaScriptCore/runtime/MathObject.h
+++ b/Source/JavaScriptCore/runtime/MathObject.h
@@ -25,31 +25,34 @@
namespace JSC {
- class MathObject : public JSNonFinalObject {
- private:
- MathObject(VM&, Structure*);
-
- public:
- typedef JSNonFinalObject Base;
-
- static MathObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
- {
- MathObject* object = new (NotNull, allocateCell<MathObject>(vm.heap)) MathObject(vm, structure);
- object->finishCreation(vm, globalObject);
- return object;
- }
-
- DECLARE_INFO;
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
-
- protected:
- void finishCreation(VM&, JSGlobalObject*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags;
- };
+class MathObject : public JSNonFinalObject {
+private:
+ MathObject(VM&, Structure*);
+
+public:
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static MathObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+ {
+ MathObject* object = new (NotNull, allocateCell<MathObject>(vm.heap)) MathObject(vm, structure);
+ object->finishCreation(vm, globalObject);
+ return object;
+ }
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+protected:
+ void finishCreation(VM&, JSGlobalObject*);
+};
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState*);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NameInstance.cpp b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp
index dbbf0e2f6..ba2cc4574 100644
--- a/Source/JavaScriptCore/runtime/NameInstance.cpp
+++ b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 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,24 +24,26 @@
*/
#include "config.h"
-#include "NameInstance.h"
+#include "MemoryStatistics.h"
-#include "JSScope.h"
-#include "Operations.h"
+#include "ExecutableAllocator.h"
+#include "VM.h"
+#include "JSStack.h"
namespace JSC {
-const ClassInfo NameInstance::s_info = { "Name", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(NameInstance) };
-
-NameInstance::NameInstance(VM& vm, Structure* structure, JSString* nameString)
- : Base(vm, structure)
+GlobalMemoryStatistics globalMemoryStatistics()
{
- m_nameString.set(vm, this, nameString);
+ GlobalMemoryStatistics stats;
+
+ stats.stackBytes = JSStack::committedByteCount();
+#if ENABLE(ASSEMBLER)
+ stats.JITBytes = ExecutableAllocator::committedByteCount();
+#endif
+
+ return stats;
}
-void NameInstance::destroy(JSCell* cell)
-{
- static_cast<NameInstance*>(cell)->NameInstance::~NameInstance();
}
-} // namespace JSC
+
diff --git a/Source/JavaScriptCore/runtime/MemoryStatistics.h b/Source/JavaScriptCore/runtime/MemoryStatistics.h
index 79cec9c21..36f04f7bd 100644
--- a/Source/JavaScriptCore/runtime/MemoryStatistics.h
+++ b/Source/JavaScriptCore/runtime/MemoryStatistics.h
@@ -34,7 +34,7 @@ namespace JSC {
struct GlobalMemoryStatistics {
size_t stackBytes;
- size_t JITBytes;
+ size_t JITBytes = 0;
};
JS_EXPORT_PRIVATE GlobalMemoryStatistics globalMemoryStatistics();
diff --git a/Source/JavaScriptCore/runtime/ModuleLoaderObject.cpp b/Source/JavaScriptCore/runtime/ModuleLoaderObject.cpp
new file mode 100644
index 000000000..37b8afc77
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ModuleLoaderObject.cpp
@@ -0,0 +1,394 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "ModuleLoaderObject.h"
+
+#include "BuiltinNames.h"
+#include "CodeProfiling.h"
+#include "Error.h"
+#include "Exception.h"
+#include "JSCInlines.h"
+#include "JSGlobalObjectFunctions.h"
+#include "JSInternalPromise.h"
+#include "JSInternalPromiseDeferred.h"
+#include "JSMap.h"
+#include "JSModuleEnvironment.h"
+#include "JSModuleRecord.h"
+#include "ModuleAnalyzer.h"
+#include "Nodes.h"
+#include "Parser.h"
+#include "ParserError.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL moduleLoaderObjectParseModule(ExecState*);
+static EncodedJSValue JSC_HOST_CALL moduleLoaderObjectRequestedModules(ExecState*);
+static EncodedJSValue JSC_HOST_CALL moduleLoaderObjectEvaluate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL moduleLoaderObjectModuleDeclarationInstantiation(ExecState*);
+static EncodedJSValue JSC_HOST_CALL moduleLoaderObjectResolve(ExecState*);
+static EncodedJSValue JSC_HOST_CALL moduleLoaderObjectFetch(ExecState*);
+static EncodedJSValue JSC_HOST_CALL moduleLoaderObjectTranslate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL moduleLoaderObjectInstantiate(ExecState*);
+
+}
+
+#include "ModuleLoaderObject.lut.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ModuleLoaderObject);
+
+const ClassInfo ModuleLoaderObject::s_info = { "ModuleLoader", &Base::s_info, &moduleLoaderObjectTable, CREATE_METHOD_TABLE(ModuleLoaderObject) };
+
+/* Source for ModuleLoaderObject.lut.h
+@begin moduleLoaderObjectTable
+ setStateToMax JSBuiltin DontEnum|Function 2
+ newRegistryEntry JSBuiltin DontEnum|Function 1
+ ensureRegistered JSBuiltin DontEnum|Function 1
+ forceFulfillPromise JSBuiltin DontEnum|Function 2
+ fulfillFetch JSBuiltin DontEnum|Function 2
+ fulfillTranslate JSBuiltin DontEnum|Function 2
+ fulfillInstantiate JSBuiltin DontEnum|Function 2
+ commitInstantiated JSBuiltin DontEnum|Function 3
+ instantiation JSBuiltin DontEnum|Function 3
+ requestFetch JSBuiltin DontEnum|Function 1
+ requestTranslate JSBuiltin DontEnum|Function 1
+ requestInstantiate JSBuiltin DontEnum|Function 1
+ requestResolveDependencies JSBuiltin DontEnum|Function 1
+ requestInstantiateAll JSBuiltin DontEnum|Function 1
+ requestLink JSBuiltin DontEnum|Function 1
+ requestReady JSBuiltin DontEnum|Function 1
+ link JSBuiltin DontEnum|Function 1
+ moduleDeclarationInstantiation moduleLoaderObjectModuleDeclarationInstantiation DontEnum|Function 2
+ moduleEvaluation JSBuiltin DontEnum|Function 2
+ evaluate moduleLoaderObjectEvaluate DontEnum|Function 2
+ provide JSBuiltin DontEnum|Function 3
+ loadAndEvaluateModule JSBuiltin DontEnum|Function 2
+ loadModule JSBuiltin DontEnum|Function 2
+ linkAndEvaluateModule JSBuiltin DontEnum|Function 1
+ parseModule moduleLoaderObjectParseModule DontEnum|Function 2
+ requestedModules moduleLoaderObjectRequestedModules DontEnum|Function 1
+ resolve moduleLoaderObjectResolve DontEnum|Function 1
+ fetch moduleLoaderObjectFetch DontEnum|Function 1
+ translate moduleLoaderObjectTranslate DontEnum|Function 2
+ instantiate moduleLoaderObjectInstantiate DontEnum|Function 2
+@end
+*/
+
+ModuleLoaderObject::ModuleLoaderObject(VM& vm, Structure* structure)
+ : JSNonFinalObject(vm, structure)
+{
+}
+
+void ModuleLoaderObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+
+ // Constant values for the state.
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "Fetch"), jsNumber(Status::Fetch));
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "Translate"), jsNumber(Status::Translate));
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "Instantiate"), jsNumber(Status::Instantiate));
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "ResolveDependencies"), jsNumber(Status::ResolveDependencies));
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "Link"), jsNumber(Status::Link));
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "Ready"), jsNumber(Status::Ready));
+
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "registry"), JSMap::create(vm, globalObject->mapStructure()));
+}
+
+bool ModuleLoaderObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<Base>(exec, moduleLoaderObjectTable, jsCast<ModuleLoaderObject*>(object), propertyName, slot);
+}
+
+// ------------------------------ Functions --------------------------------
+
+static String printableModuleKey(ExecState* exec, JSValue key)
+{
+ if (key.isString() || key.isSymbol())
+ return key.toPropertyKey(exec).impl();
+ return exec->propertyNames().emptyIdentifier.impl();
+}
+
+JSValue ModuleLoaderObject::provide(ExecState* exec, JSValue key, Status status, const String& source)
+{
+ JSObject* function = jsCast<JSObject*>(get(exec, exec->propertyNames().builtinNames().providePublicName()));
+ CallData callData;
+ CallType callType = JSC::getCallData(function, callData);
+ ASSERT(callType != CallTypeNone);
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(key);
+ arguments.append(jsNumber(status));
+ arguments.append(jsString(exec, source));
+
+ return call(exec, function, callType, callData, this, arguments);
+}
+
+JSInternalPromise* ModuleLoaderObject::loadAndEvaluateModule(ExecState* exec, JSValue moduleName, JSValue referrer)
+{
+ JSObject* function = jsCast<JSObject*>(get(exec, exec->propertyNames().builtinNames().loadAndEvaluateModulePublicName()));
+ CallData callData;
+ CallType callType = JSC::getCallData(function, callData);
+ ASSERT(callType != CallTypeNone);
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(moduleName);
+ arguments.append(referrer);
+
+ return jsCast<JSInternalPromise*>(call(exec, function, callType, callData, this, arguments));
+}
+
+JSInternalPromise* ModuleLoaderObject::loadModule(ExecState* exec, JSValue moduleName, JSValue referrer)
+{
+ JSObject* function = jsCast<JSObject*>(get(exec, exec->propertyNames().builtinNames().loadModulePublicName()));
+ CallData callData;
+ CallType callType = JSC::getCallData(function, callData);
+ ASSERT(callType != CallTypeNone);
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(moduleName);
+ arguments.append(referrer);
+
+ return jsCast<JSInternalPromise*>(call(exec, function, callType, callData, this, arguments));
+}
+
+JSInternalPromise* ModuleLoaderObject::linkAndEvaluateModule(ExecState* exec, JSValue moduleKey)
+{
+ JSObject* function = jsCast<JSObject*>(get(exec, exec->propertyNames().builtinNames().linkAndEvaluateModulePublicName()));
+ CallData callData;
+ CallType callType = JSC::getCallData(function, callData);
+ ASSERT(callType != CallTypeNone);
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(moduleKey);
+
+ return jsCast<JSInternalPromise*>(call(exec, function, callType, callData, this, arguments));
+}
+
+JSInternalPromise* ModuleLoaderObject::resolve(ExecState* exec, JSValue name, JSValue referrer)
+{
+ if (Options::dumpModuleLoadingState())
+ dataLog("Loader [resolve] ", printableModuleKey(exec, name), "\n");
+
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ if (globalObject->globalObjectMethodTable()->moduleLoaderResolve)
+ return globalObject->globalObjectMethodTable()->moduleLoaderResolve(globalObject, exec, name, referrer);
+ JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
+ deferred->resolve(exec, name);
+ return deferred->promise();
+}
+
+JSInternalPromise* ModuleLoaderObject::fetch(ExecState* exec, JSValue key)
+{
+ if (Options::dumpModuleLoadingState())
+ dataLog("Loader [fetch] ", printableModuleKey(exec, key), "\n");
+
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ if (globalObject->globalObjectMethodTable()->moduleLoaderFetch)
+ return globalObject->globalObjectMethodTable()->moduleLoaderFetch(globalObject, exec, key);
+ JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
+ String moduleKey = key.toString(exec)->value(exec);
+ if (exec->hadException()) {
+ JSValue exception = exec->exception()->value();
+ exec->clearException();
+ deferred->reject(exec, exception);
+ return deferred->promise();
+ }
+ deferred->reject(exec, createError(exec, makeString("Could not open the module '", moduleKey, "'.")));
+ return deferred->promise();
+}
+
+JSInternalPromise* ModuleLoaderObject::translate(ExecState* exec, JSValue key, JSValue payload)
+{
+ if (Options::dumpModuleLoadingState())
+ dataLog("Loader [translate] ", printableModuleKey(exec, key), "\n");
+
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ if (globalObject->globalObjectMethodTable()->moduleLoaderTranslate)
+ return globalObject->globalObjectMethodTable()->moduleLoaderTranslate(globalObject, exec, key, payload);
+ JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
+ deferred->resolve(exec, payload);
+ return deferred->promise();
+}
+
+JSInternalPromise* ModuleLoaderObject::instantiate(ExecState* exec, JSValue key, JSValue source)
+{
+ if (Options::dumpModuleLoadingState())
+ dataLog("Loader [instantiate] ", printableModuleKey(exec, key), "\n");
+
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ if (globalObject->globalObjectMethodTable()->moduleLoaderInstantiate)
+ return globalObject->globalObjectMethodTable()->moduleLoaderInstantiate(globalObject, exec, key, source);
+ JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
+ deferred->resolve(exec, jsUndefined());
+ return deferred->promise();
+}
+
+JSValue ModuleLoaderObject::evaluate(ExecState* exec, JSValue key, JSValue moduleRecordValue)
+{
+ if (Options::dumpModuleLoadingState())
+ dataLog("Loader [evaluate] ", printableModuleKey(exec, key), "\n");
+
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ if (globalObject->globalObjectMethodTable()->moduleLoaderEvaluate)
+ return globalObject->globalObjectMethodTable()->moduleLoaderEvaluate(globalObject, exec, key, moduleRecordValue);
+
+ JSModuleRecord* moduleRecord = jsDynamicCast<JSModuleRecord*>(moduleRecordValue);
+ if (!moduleRecord)
+ return jsUndefined();
+ return moduleRecord->evaluate(exec);
+}
+
+EncodedJSValue JSC_HOST_CALL moduleLoaderObjectParseModule(ExecState* exec)
+{
+ VM& vm = exec->vm();
+ const Identifier moduleKey = exec->argument(0).toPropertyKey(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ String source = exec->argument(1).toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ SourceCode sourceCode = makeSource(source, moduleKey.impl());
+
+ CodeProfiling profile(sourceCode);
+
+ ParserError error;
+ std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>(
+ &vm, sourceCode, Identifier(), JSParserBuiltinMode::NotBuiltin,
+ JSParserStrictMode::Strict, SourceParseMode::ModuleAnalyzeMode, SuperBinding::NotNeeded, error);
+
+ if (error.isValid()) {
+ throwVMError(exec, error.toErrorObject(exec->lexicalGlobalObject(), sourceCode));
+ return JSValue::encode(jsUndefined());
+ }
+ ASSERT(moduleProgramNode);
+
+ ModuleAnalyzer moduleAnalyzer(exec, moduleKey, sourceCode, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables());
+ JSModuleRecord* moduleRecord = moduleAnalyzer.analyze(*moduleProgramNode);
+
+ return JSValue::encode(moduleRecord);
+}
+
+EncodedJSValue JSC_HOST_CALL moduleLoaderObjectRequestedModules(ExecState* exec)
+{
+ JSModuleRecord* moduleRecord = jsDynamicCast<JSModuleRecord*>(exec->argument(0));
+ if (!moduleRecord)
+ return JSValue::encode(constructEmptyArray(exec, nullptr));
+
+ JSArray* result = constructEmptyArray(exec, nullptr, moduleRecord->requestedModules().size());
+ size_t i = 0;
+ for (auto& key : moduleRecord->requestedModules())
+ result->putDirectIndex(exec, i++, jsString(exec, key.get()));
+
+ return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL moduleLoaderObjectModuleDeclarationInstantiation(ExecState* exec)
+{
+ JSModuleRecord* moduleRecord = jsDynamicCast<JSModuleRecord*>(exec->argument(0));
+ if (!moduleRecord)
+ return JSValue::encode(jsUndefined());
+
+ if (Options::dumpModuleLoadingState())
+ dataLog("Loader [link] ", moduleRecord->moduleKey(), "\n");
+
+ moduleRecord->link(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ return JSValue::encode(jsUndefined());
+}
+
+// ------------------------------ Hook Functions ---------------------------
+
+EncodedJSValue JSC_HOST_CALL moduleLoaderObjectResolve(ExecState* exec)
+{
+ // Hook point, Loader.resolve.
+ // https://whatwg.github.io/loader/#browser-resolve
+ // Take the name and resolve it to the unique identifier for the resource location.
+ // For example, take the "jquery" and return the URL for the resource.
+ ModuleLoaderObject* loader = jsDynamicCast<ModuleLoaderObject*>(exec->thisValue());
+ if (!loader)
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(loader->resolve(exec, exec->argument(0), exec->argument(1)));
+}
+
+EncodedJSValue JSC_HOST_CALL moduleLoaderObjectFetch(ExecState* exec)
+{
+ // Hook point, Loader.fetch
+ // https://whatwg.github.io/loader/#browser-fetch
+ // Take the key and fetch the resource actually.
+ // For example, JavaScriptCore shell can provide the hook fetching the resource
+ // from the local file system.
+ ModuleLoaderObject* loader = jsDynamicCast<ModuleLoaderObject*>(exec->thisValue());
+ if (!loader)
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(loader->fetch(exec, exec->argument(0)));
+}
+
+EncodedJSValue JSC_HOST_CALL moduleLoaderObjectTranslate(ExecState* exec)
+{
+ // Hook point, Loader.translate
+ // https://whatwg.github.io/loader/#browser-translate
+ // Take the key and the fetched source code and translate it to the ES6 source code.
+ // Typically it is used by the transpilers.
+ ModuleLoaderObject* loader = jsDynamicCast<ModuleLoaderObject*>(exec->thisValue());
+ if (!loader)
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(loader->translate(exec, exec->argument(0), exec->argument(1)));
+}
+
+EncodedJSValue JSC_HOST_CALL moduleLoaderObjectInstantiate(ExecState* exec)
+{
+ // Hook point, Loader.instantiate
+ // https://whatwg.github.io/loader/#browser-instantiate
+ // Take the key and the translated source code, and instantiate the module record
+ // by parsing the module source code.
+ // It has the chance to provide the optional module instance that is different from
+ // the ordinary one.
+ ModuleLoaderObject* loader = jsDynamicCast<ModuleLoaderObject*>(exec->thisValue());
+ if (!loader)
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(loader->instantiate(exec, exec->argument(0), exec->argument(1)));
+}
+
+// ------------------- Additional Hook Functions ---------------------------
+
+EncodedJSValue JSC_HOST_CALL moduleLoaderObjectEvaluate(ExecState* exec)
+{
+ // To instrument and retrieve the errors raised from the module execution,
+ // we inserted the hook point here.
+
+ ModuleLoaderObject* loader = jsDynamicCast<ModuleLoaderObject*>(exec->thisValue());
+ if (!loader)
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(loader->evaluate(exec, exec->argument(0), exec->argument(1)));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ModuleLoaderObject.h b/Source/JavaScriptCore/runtime/ModuleLoaderObject.h
new file mode 100644
index 000000000..becaf1026
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ModuleLoaderObject.h
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#ifndef ModuleLoaderObject_h
+#define ModuleLoaderObject_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class JSInternalPromise;
+
+class ModuleLoaderObject : public JSNonFinalObject {
+private:
+ ModuleLoaderObject(VM&, Structure*);
+public:
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ enum Status {
+ Fetch = 1,
+ Translate = 2,
+ Instantiate = 3,
+ ResolveDependencies = 4,
+ Link = 5,
+ Ready = 6,
+ };
+
+ static ModuleLoaderObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+ {
+ ModuleLoaderObject* object = new (NotNull, allocateCell<ModuleLoaderObject>(vm.heap)) ModuleLoaderObject(vm, structure);
+ object->finishCreation(vm, globalObject);
+ return object;
+ }
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ // APIs to control the module loader.
+ JSValue provide(ExecState*, JSValue key, Status, const String&);
+ JSInternalPromise* loadAndEvaluateModule(ExecState*, JSValue moduleName, JSValue referrer);
+ JSInternalPromise* loadModule(ExecState*, JSValue moduleName, JSValue referrer);
+ JSInternalPromise* linkAndEvaluateModule(ExecState*, JSValue moduleKey);
+
+ // Platform dependent hooked APIs.
+ JSInternalPromise* resolve(ExecState*, JSValue name, JSValue referrer);
+ JSInternalPromise* fetch(ExecState*, JSValue key);
+ JSInternalPromise* translate(ExecState*, JSValue key, JSValue payload);
+ JSInternalPromise* instantiate(ExecState*, JSValue key, JSValue source);
+
+ // Additional platform dependent hooked APIs.
+ JSValue evaluate(ExecState*, JSValue key, JSValue moduleRecord);
+
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+
+protected:
+ void finishCreation(VM&, JSGlobalObject*);
+};
+
+} // namespace JSC
+
+#endif // ModuleLoaderObject_h
diff --git a/Source/JavaScriptCore/runtime/NamePrototype.cpp b/Source/JavaScriptCore/runtime/NamePrototype.cpp
deleted file mode 100644
index ccbb41bc5..000000000
--- a/Source/JavaScriptCore/runtime/NamePrototype.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#include "config.h"
-#include "NamePrototype.h"
-
-#include "Error.h"
-#include "Operations.h"
-
-namespace JSC {
-
-static EncodedJSValue JSC_HOST_CALL privateNameProtoFuncToString(ExecState*);
-
-}
-
-#include "NamePrototype.lut.h"
-
-namespace JSC {
-
-const ClassInfo NamePrototype::s_info = { "Name", &Base::s_info, 0, ExecState::privateNamePrototypeTable, CREATE_METHOD_TABLE(NamePrototype) };
-
-/* Source for NamePrototype.lut.h
-@begin privateNamePrototypeTable
- toString privateNameProtoFuncToString DontEnum|Function 0
-@end
-*/
-
-NamePrototype::NamePrototype(ExecState* exec, Structure* structure)
- : Base(exec->vm(), structure, jsEmptyString(exec))
-{
-}
-
-void NamePrototype::finishCreation(VM& vm)
-{
- Base::finishCreation(vm);
- ASSERT(inherits(info()));
-}
-
-bool NamePrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
-{
- return getStaticFunctionSlot<Base>(exec, ExecState::privateNamePrototypeTable(exec->vm()), jsCast<NamePrototype*>(object), propertyName, slot);
-}
-
-// ------------------------------ Functions ---------------------------
-
-EncodedJSValue JSC_HOST_CALL privateNameProtoFuncToString(ExecState* exec)
-{
- JSValue thisValue = exec->hostThisValue();
- if (!thisValue.isObject())
- return throwVMTypeError(exec);
-
- JSObject* thisObject = asObject(thisValue);
- if (!thisObject->inherits(NameInstance::info()))
- return throwVMTypeError(exec);
-
- return JSValue::encode(jsCast<NameInstance*>(thisObject)->nameString());
-}
-
-} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp
index d5e728c2c..1b88a0dc1 100644
--- a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.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
@@ -25,39 +25,47 @@
#include "JSFunction.h"
#include "JSString.h"
#include "NativeErrorPrototype.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(NativeErrorConstructor);
-const ClassInfo NativeErrorConstructor::s_info = { "Function", &InternalFunction::s_info, 0, 0, CREATE_METHOD_TABLE(NativeErrorConstructor) };
+const ClassInfo NativeErrorConstructor::s_info = { "Function", &InternalFunction::s_info, 0, CREATE_METHOD_TABLE(NativeErrorConstructor) };
NativeErrorConstructor::NativeErrorConstructor(VM& vm, Structure* structure)
: InternalFunction(vm, structure)
{
}
+void NativeErrorConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, Structure* prototypeStructure, const String& name)
+{
+ Base::finishCreation(vm, name);
+ ASSERT(inherits(info()));
+
+ NativeErrorPrototype* prototype = NativeErrorPrototype::create(vm, globalObject, prototypeStructure, name, this);
+
+ putDirect(vm, vm.propertyNames->length, jsNumber(1), DontDelete | ReadOnly | DontEnum); // ECMA 15.11.7.5
+ putDirect(vm, vm.propertyNames->prototype, prototype, DontDelete | ReadOnly | DontEnum);
+ m_errorStructure.set(vm, this, ErrorInstance::createStructure(vm, globalObject, prototype));
+ ASSERT(m_errorStructure);
+ ASSERT(m_errorStructure->isObject());
+}
+
void NativeErrorConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
NativeErrorConstructor* thisObject = jsCast<NativeErrorConstructor*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
- InternalFunction::visitChildren(thisObject, visitor);
+ Base::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_errorStructure);
}
EncodedJSValue JSC_HOST_CALL Interpreter::constructWithNativeErrorConstructor(ExecState* exec)
{
JSValue message = exec->argument(0);
- Structure* errorStructure = static_cast<NativeErrorConstructor*>(exec->callee())->errorStructure();
+ Structure* errorStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), jsCast<NativeErrorConstructor*>(exec->callee())->errorStructure());
ASSERT(errorStructure);
- Vector<StackFrame> stackTrace;
- exec->vm().interpreter->getStackTrace(stackTrace, std::numeric_limits<size_t>::max());
- stackTrace.remove(0);
- return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, stackTrace));
+ return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, nullptr, TypeNothing, false));
}
ConstructType NativeErrorConstructor::getConstructData(JSCell*, ConstructData& constructData)
@@ -70,10 +78,7 @@ EncodedJSValue JSC_HOST_CALL Interpreter::callNativeErrorConstructor(ExecState*
{
JSValue message = exec->argument(0);
Structure* errorStructure = static_cast<NativeErrorConstructor*>(exec->callee())->errorStructure();
- Vector<StackFrame> stackTrace;
- exec->vm().interpreter->getStackTrace(stackTrace, std::numeric_limits<size_t>::max());
- stackTrace.remove(0);
- return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, stackTrace));
+ return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, nullptr, TypeNothing, false));
}
CallType NativeErrorConstructor::getCallData(JSCell*, CallData& callData)
diff --git a/Source/JavaScriptCore/runtime/NativeErrorConstructor.h b/Source/JavaScriptCore/runtime/NativeErrorConstructor.h
index 740d3f933..b582ef392 100644
--- a/Source/JavaScriptCore/runtime/NativeErrorConstructor.h
+++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.h
@@ -26,54 +26,41 @@
namespace JSC {
- class ErrorInstance;
- class FunctionPrototype;
- class NativeErrorPrototype;
+class ErrorInstance;
+class FunctionPrototype;
+class NativeErrorPrototype;
- class NativeErrorConstructor : public InternalFunction {
- public:
- typedef InternalFunction Base;
+class NativeErrorConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
- static NativeErrorConstructor* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, Structure* prototypeStructure, const String& name)
- {
- NativeErrorConstructor* constructor = new (NotNull, allocateCell<NativeErrorConstructor>(vm.heap)) NativeErrorConstructor(vm, structure);
- constructor->finishCreation(vm, globalObject, prototypeStructure, name);
- return constructor;
- }
-
- DECLARE_INFO;
+ static NativeErrorConstructor* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, Structure* prototypeStructure, const String& name)
+ {
+ NativeErrorConstructor* constructor = new (NotNull, allocateCell<NativeErrorConstructor>(vm.heap)) NativeErrorConstructor(vm, structure);
+ constructor->finishCreation(vm, globalObject, prototypeStructure, name);
+ return constructor;
+ }
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
+ DECLARE_INFO;
- Structure* errorStructure() { return m_errorStructure.get(); }
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
- protected:
- void finishCreation(VM& vm, JSGlobalObject* globalObject, Structure* prototypeStructure, const String& name)
- {
- Base::finishCreation(vm, name);
- ASSERT(inherits(info()));
+ Structure* errorStructure() { return m_errorStructure.get(); }
- NativeErrorPrototype* prototype = NativeErrorPrototype::create(vm, globalObject, prototypeStructure, name, this);
+protected:
+ void finishCreation(VM&, JSGlobalObject*, Structure* prototypeStructure, const String& name);
- putDirect(vm, vm.propertyNames->length, jsNumber(1), DontDelete | ReadOnly | DontEnum); // ECMA 15.11.7.5
- putDirect(vm, vm.propertyNames->prototype, prototype, DontDelete | ReadOnly | DontEnum);
- m_errorStructure.set(vm, this, ErrorInstance::createStructure(vm, globalObject, prototype));
- ASSERT(m_errorStructure);
- ASSERT(m_errorStructure->isObject());
- }
+private:
+ NativeErrorConstructor(VM&, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+ static void visitChildren(JSCell*, SlotVisitor&);
- private:
- NativeErrorConstructor(VM&, Structure*);
- static const unsigned StructureFlags = OverridesVisitChildren | InternalFunction::StructureFlags;
- static ConstructType getConstructData(JSCell*, ConstructData&);
- static CallType getCallData(JSCell*, CallData&);
- static void visitChildren(JSCell*, SlotVisitor&);
-
- WriteBarrier<Structure> m_errorStructure;
- };
+ WriteBarrier<Structure> m_errorStructure;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp
index 3dea2093d..967ac5f8f 100644
--- a/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp
@@ -24,7 +24,7 @@
#include "JSGlobalObject.h"
#include "JSString.h"
#include "NativeErrorConstructor.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
diff --git a/Source/JavaScriptCore/runtime/NativeErrorPrototype.h b/Source/JavaScriptCore/runtime/NativeErrorPrototype.h
index 9326c5ccb..5812e6363 100644
--- a/Source/JavaScriptCore/runtime/NativeErrorPrototype.h
+++ b/Source/JavaScriptCore/runtime/NativeErrorPrototype.h
@@ -24,25 +24,26 @@
#include "ErrorPrototype.h"
namespace JSC {
- class NativeErrorConstructor;
-
- class NativeErrorPrototype : public ErrorPrototype {
- private:
- NativeErrorPrototype(VM&, Structure*);
-
- public:
- typedef ErrorPrototype Base;
-
- static NativeErrorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, const String& name, NativeErrorConstructor* constructor)
- {
- NativeErrorPrototype* prototype = new (NotNull, allocateCell<NativeErrorPrototype>(vm.heap)) NativeErrorPrototype(vm, structure);
- prototype->finishCreation(vm, globalObject, name, constructor);
- return prototype;
- }
-
- protected:
- void finishCreation(VM&, JSGlobalObject*, const String& nameAndMessage, NativeErrorConstructor*);
- };
+
+class NativeErrorConstructor;
+
+class NativeErrorPrototype : public ErrorPrototype {
+private:
+ NativeErrorPrototype(VM&, Structure*);
+
+public:
+ typedef ErrorPrototype Base;
+
+ static NativeErrorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, const String& name, NativeErrorConstructor* constructor)
+ {
+ NativeErrorPrototype* prototype = new (NotNull, allocateCell<NativeErrorPrototype>(vm.heap)) NativeErrorPrototype(vm, structure);
+ prototype->finishCreation(vm, globalObject, name, constructor);
+ return prototype;
+ }
+
+protected:
+ void finishCreation(VM&, JSGlobalObject*, const String& nameAndMessage, NativeErrorConstructor*);
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NativeStdFunctionCell.cpp b/Source/JavaScriptCore/runtime/NativeStdFunctionCell.cpp
new file mode 100644
index 000000000..581f31aed
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NativeStdFunctionCell.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "NativeStdFunctionCell.h"
+
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSFunctionInlines.h"
+#include "SlotVisitorInlines.h"
+
+namespace JSC {
+
+const ClassInfo NativeStdFunctionCell::s_info = { "NativeStdFunctionCell", nullptr, nullptr, CREATE_METHOD_TABLE(NativeStdFunctionCell) };
+
+NativeStdFunctionCell* NativeStdFunctionCell::create(VM& vm, NativeStdFunction&& function)
+{
+ NativeStdFunctionCell* nativeFunction = new (NotNull, allocateCell<NativeStdFunctionCell>(vm.heap)) NativeStdFunctionCell(vm, WTFMove(function));
+ nativeFunction->finishCreation(vm);
+ return nativeFunction;
+}
+
+
+NativeStdFunctionCell::NativeStdFunctionCell(VM& vm, NativeStdFunction&& function)
+ : Base(vm, vm.nativeStdFunctionCellStructure.get())
+ , m_function(WTFMove(function))
+{
+}
+
+void NativeStdFunctionCell::destroy(JSCell* cell)
+{
+ NativeStdFunctionCell* nativeFunction = static_cast<NativeStdFunctionCell*>(cell);
+ nativeFunction->NativeStdFunctionCell::~NativeStdFunctionCell();
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/NativeStdFunctionCell.h b/Source/JavaScriptCore/runtime/NativeStdFunctionCell.h
new file mode 100644
index 000000000..ba4a6ae4d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NativeStdFunctionCell.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifndef NativeStdFunctionCell_h
+#define NativeStdFunctionCell_h
+
+#include "JSCell.h"
+#include "JSNativeStdFunction.h"
+
+namespace JSC {
+
+class NativeStdFunctionCell : public JSCell {
+public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+ static const bool needsDestruction = true;
+
+ static NativeStdFunctionCell* create(VM&, NativeStdFunction&&);
+
+ static void destroy(JSCell*);
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+ }
+
+ DECLARE_INFO;
+
+ const NativeStdFunction& function() const { return m_function; }
+
+private:
+ NativeStdFunctionCell(VM&, NativeStdFunction&&);
+
+ NativeStdFunction m_function;
+};
+
+} // namespace JSC
+
+#endif // NativeStdFunctionCell_h
diff --git a/Source/JavaScriptCore/runtime/MapIteratorConstructor.cpp b/Source/JavaScriptCore/runtime/NullGetterFunction.cpp
index fbc6c8b73..4243e5c41 100644
--- a/Source/JavaScriptCore/runtime/MapIteratorConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/NullGetterFunction.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple, Inc. All rights reserved.
+ * Copyright (C) 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
@@ -20,26 +20,33 @@
* 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 "MapIteratorConstructor.h"
+#include "NullGetterFunction.h"
#include "JSCJSValueInlines.h"
-#include "JSCellInlines.h"
-#include "JSGlobalObject.h"
-#include "JSMapIterator.h"
-#include "MapIteratorPrototype.h"
+#include "JSCInlines.h"
namespace JSC {
-const ClassInfo MapIteratorConstructor::s_info = { "MapIterator Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(MapIteratorConstructor) };
+const ClassInfo NullGetterFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(NullGetterFunction) };
-void MapIteratorConstructor::finishCreation(VM& vm, MapIteratorPrototype* prototype)
+static EncodedJSValue JSC_HOST_CALL callReturnUndefined(ExecState*)
{
- Base::finishCreation(vm);
- putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly);
+ return JSValue::encode(jsUndefined());
+}
+
+CallType NullGetterFunction::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callReturnUndefined;
+ return CallTypeHost;
+}
+
+ConstructType NullGetterFunction::getConstructData(JSCell*, ConstructData&)
+{
+ return ConstructTypeNone;
}
}
diff --git a/Source/JavaScriptCore/runtime/NullGetterFunction.h b/Source/JavaScriptCore/runtime/NullGetterFunction.h
new file mode 100644
index 000000000..d95feb731
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NullGetterFunction.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef NullGetterFunction_h
+#define NullGetterFunction_h
+
+#include "InternalFunction.h"
+
+namespace JSC {
+
+class NullGetterFunction : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+
+ static NullGetterFunction* create(VM& vm, Structure* structure)
+ {
+ NullGetterFunction* function = new (NotNull, allocateCell< NullGetterFunction>(vm.heap)) NullGetterFunction(vm, structure);
+ function->finishCreation(vm, String());
+ return function;
+ }
+
+ DECLARE_EXPORT_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+private:
+ NullGetterFunction(VM& vm, Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+};
+
+}
+
+#endif // NullGetterFunction_h
diff --git a/Source/JavaScriptCore/runtime/NullSetterFunction.cpp b/Source/JavaScriptCore/runtime/NullSetterFunction.cpp
new file mode 100644
index 000000000..059b74f51
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NullSetterFunction.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "NullSetterFunction.h"
+
+#include "CodeBlock.h"
+#include "Error.h"
+#include "JSCInlines.h"
+#include "JSCJSValueInlines.h"
+#include "StackVisitor.h"
+
+namespace JSC {
+
+const ClassInfo NullSetterFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(NullSetterFunction) };
+
+
+class GetCallerStrictnessFunctor {
+public:
+ GetCallerStrictnessFunctor()
+ : m_iterations(0)
+ , m_callerIsStrict(false)
+ {
+ }
+
+ StackVisitor::Status operator()(StackVisitor& visitor)
+ {
+ ++m_iterations;
+ if (m_iterations < 2)
+ return StackVisitor::Continue;
+
+ CodeBlock* codeBlock = visitor->codeBlock();
+ m_callerIsStrict = codeBlock && codeBlock->isStrictMode();
+ return StackVisitor::Done;
+ }
+
+ bool callerIsStrict() const { return m_callerIsStrict; }
+
+private:
+ int m_iterations;
+ bool m_callerIsStrict;
+};
+
+static bool callerIsStrict(ExecState* exec)
+{
+ GetCallerStrictnessFunctor iter;
+ exec->iterate(iter);
+ return iter.callerIsStrict();
+}
+
+static EncodedJSValue JSC_HOST_CALL callReturnUndefined(ExecState* exec)
+{
+ if (callerIsStrict(exec))
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Setting a property that has only a getter")));
+ return JSValue::encode(jsUndefined());
+}
+
+CallType NullSetterFunction::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callReturnUndefined;
+ return CallTypeHost;
+}
+
+ConstructType NullSetterFunction::getConstructData(JSCell*, ConstructData&)
+{
+ return ConstructTypeNone;
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/NullSetterFunction.h b/Source/JavaScriptCore/runtime/NullSetterFunction.h
new file mode 100644
index 000000000..ccdc6f1dd
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NullSetterFunction.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef NullSetterFunction_h
+#define NullSetterFunction_h
+
+#include "InternalFunction.h"
+
+namespace JSC {
+
+class NullSetterFunction : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+
+ static NullSetterFunction* create(VM& vm, Structure* structure)
+ {
+ NullSetterFunction* function = new (NotNull, allocateCell< NullSetterFunction>(vm.heap)) NullSetterFunction(vm, structure);
+ function->finishCreation(vm, String());
+ return function;
+ }
+
+ DECLARE_EXPORT_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+private:
+ NullSetterFunction(VM& vm, Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+};
+
+}
+
+#endif // NullSetterFunction_h
diff --git a/Source/JavaScriptCore/runtime/NumberConstructor.cpp b/Source/JavaScriptCore/runtime/NumberConstructor.cpp
index 8e858a24f..3782a84af 100644
--- a/Source/JavaScriptCore/runtime/NumberConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/NumberConstructor.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org)
- * Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2011, 2015-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
@@ -25,35 +25,24 @@
#include "Lookup.h"
#include "NumberObject.h"
#include "NumberPrototype.h"
-#include "Operations.h"
+#include "JSCInlines.h"
+#include "JSGlobalObjectFunctions.h"
+#include "StructureInlines.h"
namespace JSC {
-static EncodedJSValue numberConstructorNaNValue(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue numberConstructorNegInfinity(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue numberConstructorPosInfinity(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue numberConstructorMaxValue(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue numberConstructorMinValue(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
+static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsFinite(ExecState*);
+static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsInteger(ExecState*);
+static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsNaN(ExecState*);
+static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsSafeInteger(ExecState*);
} // namespace JSC
-#include "NumberConstructor.lut.h"
-
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(NumberConstructor);
-const ClassInfo NumberConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::numberConstructorTable, CREATE_METHOD_TABLE(NumberConstructor) };
-
-/* Source for NumberConstructor.lut.h
-@begin numberConstructorTable
- NaN numberConstructorNaNValue DontEnum|DontDelete|ReadOnly
- NEGATIVE_INFINITY numberConstructorNegInfinity DontEnum|DontDelete|ReadOnly
- POSITIVE_INFINITY numberConstructorPosInfinity DontEnum|DontDelete|ReadOnly
- MAX_VALUE numberConstructorMaxValue DontEnum|DontDelete|ReadOnly
- MIN_VALUE numberConstructorMinValue DontEnum|DontDelete|ReadOnly
-@end
-*/
+const ClassInfo NumberConstructor::s_info = { "Function", &InternalFunction::s_info, 0, CREATE_METHOD_TABLE(NumberConstructor) };
NumberConstructor::NumberConstructor(VM& vm, Structure* structure)
: InternalFunction(vm, structure)
@@ -70,43 +59,30 @@ void NumberConstructor::finishCreation(VM& vm, NumberPrototype* numberPrototype)
// no. of arguments for constructor
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
-}
-
-bool NumberConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
-{
- return getStaticValueSlot<NumberConstructor, InternalFunction>(exec, ExecState::numberConstructorTable(exec->vm()), jsCast<NumberConstructor*>(object), propertyName, slot);
-}
-
-static EncodedJSValue numberConstructorNaNValue(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName)
-{
- return JSValue::encode(jsNaN());
-}
-
-static EncodedJSValue numberConstructorNegInfinity(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName)
-{
- return JSValue::encode(jsNumber(-std::numeric_limits<double>::infinity()));
-}
-
-static EncodedJSValue numberConstructorPosInfinity(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName)
-{
- return JSValue::encode(jsNumber(std::numeric_limits<double>::infinity()));
-}
-
-static EncodedJSValue numberConstructorMaxValue(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName)
-{
- return JSValue::encode(jsNumber(1.7976931348623157E+308));
-}
-static EncodedJSValue numberConstructorMinValue(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName)
-{
- return JSValue::encode(jsNumber(5E-324));
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "EPSILON"), jsDoubleNumber(std::numeric_limits<double>::epsilon()), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MAX_VALUE"), jsDoubleNumber(1.7976931348623157E+308), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MIN_VALUE"), jsDoubleNumber(5E-324), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MAX_SAFE_INTEGER"), jsDoubleNumber(9007199254740991.0), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MIN_SAFE_INTEGER"), jsDoubleNumber(-9007199254740991.0), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "NEGATIVE_INFINITY"), jsDoubleNumber(-std::numeric_limits<double>::infinity()), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "POSITIVE_INFINITY"), jsDoubleNumber(std::numeric_limits<double>::infinity()), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "NaN"), jsNaN(), DontDelete | DontEnum | ReadOnly);
+
+ putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "isFinite"), 1, numberConstructorFuncIsFinite, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "isInteger"), 1, numberConstructorFuncIsInteger, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "isNaN"), 1, numberConstructorFuncIsNaN, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "isSafeInteger"), 1, numberConstructorFuncIsSafeInteger, NoIntrinsic, DontEnum);
+ putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "parseFloat"), 1, globalFuncParseFloat, NoIntrinsic, DontEnum);
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, "parseInt"), numberPrototype->globalObject()->parseIntFunction(), DontEnum);
}
// ECMA 15.7.1
static EncodedJSValue JSC_HOST_CALL constructWithNumberConstructor(ExecState* exec)
{
- NumberObject* object = NumberObject::create(exec->vm(), asInternalFunction(exec->callee())->globalObject()->numberObjectStructure());
double n = exec->argumentCount() ? exec->uncheckedArgument(0).toNumber(exec) : 0;
+ NumberObject* object = NumberObject::create(exec->vm(), InternalFunction::createSubclassStructure(exec, exec->newTarget(), asInternalFunction(exec->callee())->globalObject()->numberObjectStructure()));
+
object->setInternalValue(exec->vm(), jsNumber(n));
return JSValue::encode(object);
}
@@ -129,4 +105,50 @@ CallType NumberConstructor::getCallData(JSCell*, CallData& callData)
return CallTypeHost;
}
+// ECMA-262 20.1.2.2
+static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsFinite(ExecState* exec)
+{
+ JSValue argument = exec->argument(0);
+ return JSValue::encode(jsBoolean(argument.isNumber() && (argument.isInt32() || std::isfinite(argument.asDouble()))));
+}
+
+// ECMA-262 20.1.2.3
+static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsInteger(ExecState* exec)
+{
+ JSValue argument = exec->argument(0);
+ bool isInteger;
+ if (argument.isInt32())
+ isInteger = true;
+ else if (!argument.isDouble())
+ isInteger = false;
+ else {
+ double number = argument.asDouble();
+ isInteger = std::isfinite(number) && trunc(number) == number;
+ }
+ return JSValue::encode(jsBoolean(isInteger));
+}
+
+// ECMA-262 20.1.2.4
+static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsNaN(ExecState* exec)
+{
+ JSValue argument = exec->argument(0);
+ return JSValue::encode(jsBoolean(argument.isDouble() && std::isnan(argument.asDouble())));
+}
+
+// ECMA-262 20.1.2.5
+static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsSafeInteger(ExecState* exec)
+{
+ JSValue argument = exec->argument(0);
+ bool isInteger;
+ if (argument.isInt32())
+ isInteger = true;
+ else if (!argument.isDouble())
+ isInteger = false;
+ else {
+ double number = argument.asDouble();
+ isInteger = trunc(number) == number && std::abs(number) <= 9007199254740991.0;
+ }
+ return JSValue::encode(jsBoolean(isInteger));
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NumberConstructor.h b/Source/JavaScriptCore/runtime/NumberConstructor.h
index 6c8ed89fe..9f444eb0f 100644
--- a/Source/JavaScriptCore/runtime/NumberConstructor.h
+++ b/Source/JavaScriptCore/runtime/NumberConstructor.h
@@ -25,40 +25,36 @@
namespace JSC {
- class NumberPrototype;
-
- class NumberConstructor : public InternalFunction {
- public:
- typedef InternalFunction Base;
-
- static NumberConstructor* create(VM& vm, Structure* structure, NumberPrototype* numberPrototype)
- {
- NumberConstructor* constructor = new (NotNull, allocateCell<NumberConstructor>(vm.heap)) NumberConstructor(vm, structure);
- constructor->finishCreation(vm, numberPrototype);
- return constructor;
- }
-
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- JSValue getValueProperty(ExecState*, int token) const;
-
- DECLARE_INFO;
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
- {
- return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info());
- }
-
- enum { NaNValue, NegInfinity, PosInfinity, MaxValue, MinValue };
-
- protected:
- void finishCreation(VM&, NumberPrototype*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | InternalFunction::StructureFlags;
-
- private:
- NumberConstructor(VM&, Structure*);
- static ConstructType getConstructData(JSCell*, ConstructData&);
- static CallType getCallData(JSCell*, CallData&);
- };
+class NumberPrototype;
+class GetterSetter;
+
+class NumberConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | ImplementsHasInstance | ImplementsDefaultHasInstance;
+
+ static NumberConstructor* create(VM& vm, Structure* structure, NumberPrototype* numberPrototype, GetterSetter*)
+ {
+ NumberConstructor* constructor = new (NotNull, allocateCell<NumberConstructor>(vm.heap)) NumberConstructor(vm, structure);
+ constructor->finishCreation(vm, numberPrototype);
+ return constructor;
+ }
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(vm, globalObject, proto, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+protected:
+ void finishCreation(VM&, NumberPrototype*);
+
+private:
+ NumberConstructor(VM&, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NumberObject.cpp b/Source/JavaScriptCore/runtime/NumberObject.cpp
index a77d45f4f..31350ccbd 100644
--- a/Source/JavaScriptCore/runtime/NumberObject.cpp
+++ b/Source/JavaScriptCore/runtime/NumberObject.cpp
@@ -24,13 +24,13 @@
#include "JSGlobalObject.h"
#include "NumberPrototype.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(NumberObject);
-const ClassInfo NumberObject::s_info = { "Number", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(NumberObject) };
+const ClassInfo NumberObject::s_info = { "Number", &JSWrapperObject::s_info, 0, CREATE_METHOD_TABLE(NumberObject) };
NumberObject::NumberObject(VM& vm, Structure* structure)
: JSWrapperObject(vm, structure)
diff --git a/Source/JavaScriptCore/runtime/NumberObject.h b/Source/JavaScriptCore/runtime/NumberObject.h
index 4bdf2819f..d979dd48a 100644
--- a/Source/JavaScriptCore/runtime/NumberObject.h
+++ b/Source/JavaScriptCore/runtime/NumberObject.h
@@ -25,30 +25,30 @@
namespace JSC {
- class NumberObject : public JSWrapperObject {
- protected:
- NumberObject(VM&, Structure*);
- void finishCreation(VM&);
-
- public:
- typedef JSWrapperObject Base;
-
- static NumberObject* create(VM& vm, Structure* structure)
- {
- NumberObject* number = new (NotNull, allocateCell<NumberObject>(vm.heap)) NumberObject(vm, structure);
- number->finishCreation(vm);
- return number;
- }
-
- DECLARE_EXPORT_INFO;
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(NumberObjectType, StructureFlags), info());
- }
- };
-
- JS_EXPORT_PRIVATE NumberObject* constructNumber(ExecState*, JSGlobalObject*, JSValue);
+class NumberObject : public JSWrapperObject {
+protected:
+ NumberObject(VM&, Structure*);
+ void finishCreation(VM&);
+
+public:
+ typedef JSWrapperObject Base;
+
+ static NumberObject* create(VM& vm, Structure* structure)
+ {
+ NumberObject* number = new (NotNull, allocateCell<NumberObject>(vm.heap)) NumberObject(vm, structure);
+ number->finishCreation(vm);
+ return number;
+ }
+
+ DECLARE_EXPORT_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(NumberObjectType, StructureFlags), info());
+ }
+};
+
+JS_EXPORT_PRIVATE NumberObject* constructNumber(ExecState*, JSGlobalObject*, JSValue);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.cpp b/Source/JavaScriptCore/runtime/NumberPrototype.cpp
index 141024ac3..592932d84 100644
--- a/Source/JavaScriptCore/runtime/NumberPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/NumberPrototype.cpp
@@ -24,10 +24,11 @@
#include "BigInteger.h"
#include "Error.h"
+#include "JSCBuiltins.h"
+#include "JSCInlines.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "JSString.h"
-#include "Operations.h"
#include "Uint16WithFraction.h"
#include <wtf/dtoa.h>
#include <wtf/Assertions.h>
@@ -55,7 +56,7 @@ static EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*);
namespace JSC {
-const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, 0, ExecState::numberPrototypeTable, CREATE_METHOD_TABLE(NumberPrototype) };
+const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, &numberPrototypeTable, CREATE_METHOD_TABLE(NumberPrototype) };
/* Source for NumberPrototype.lut.h
@begin numberPrototypeTable
@@ -75,17 +76,23 @@ NumberPrototype::NumberPrototype(VM& vm, Structure* structure)
{
}
-void NumberPrototype::finishCreation(VM& vm, JSGlobalObject*)
+void NumberPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
{
Base::finishCreation(vm);
setInternalValue(vm, jsNumber(0));
+#if ENABLE(INTL)
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toLocaleString", numberPrototypeToLocaleStringCodeGenerator, DontEnum);
+#else
+ UNUSED_PARAM(globalObject);
+#endif // ENABLE(INTL)
+
ASSERT(inherits(info()));
}
bool NumberPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
{
- return getStaticFunctionSlot<NumberObject>(exec, ExecState::numberPrototypeTable(exec->vm()), jsCast<NumberPrototype*>(object), propertyName, slot);
+ return getStaticFunctionSlot<NumberObject>(exec, numberPrototypeTable, jsCast<NumberPrototype*>(object), propertyName, slot);
}
// ------------------------------ Functions ---------------------------
@@ -102,7 +109,7 @@ static ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double& x)
return true;
}
- if (thisValue.isCell() && thisValue.asCell()->structure()->typeInfo().isNumberObject()) {
+ if (thisValue.isCell() && thisValue.asCell()->type() == NumberObjectType) {
x = static_cast<const NumberObject*>(thisValue.asCell())->internalValue().asNumber();
return true;
}
@@ -365,7 +372,7 @@ static String toStringWithRadix(int32_t number, unsigned radix)
EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec)
{
double x;
- if (!toThisNumber(exec->hostThisValue(), x))
+ if (!toThisNumber(exec->thisValue(), x))
return throwVMTypeError(exec);
// Get the argument.
@@ -376,7 +383,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec)
// Handle NaN and Infinity.
if (!std::isfinite(x))
- return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x)));
+ return JSValue::encode(jsNontrivialString(exec, String::numberToStringECMAScript(x)));
// Round if the argument is not undefined, always format as exponential.
char buffer[WTF::NumberToStringBufferLength];
@@ -396,7 +403,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec)
EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec)
{
double x;
- if (!toThisNumber(exec->hostThisValue(), x))
+ if (!toThisNumber(exec->thisValue(), x))
return throwVMTypeError(exec);
// Get the argument.
@@ -429,7 +436,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec)
EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec)
{
double x;
- if (!toThisNumber(exec->hostThisValue(), x))
+ if (!toThisNumber(exec->thisValue(), x))
return throwVMTypeError(exec);
// Get the argument.
@@ -444,7 +451,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec)
// Handle NaN and Infinity.
if (!std::isfinite(x))
- return JSValue::encode(jsString(exec, String::numberToStringECMAScript(x)));
+ return JSValue::encode(jsNontrivialString(exec, String::numberToStringECMAScript(x)));
NumberToStringBuffer buffer;
return JSValue::encode(jsString(exec, String(numberToFixedPrecisionString(x, significantFigures, buffer))));
@@ -486,7 +493,7 @@ static inline EncodedJSValue integerValueToString(ExecState* exec, int32_t radix
EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
{
double doubleValue;
- if (!toThisNumber(exec->hostThisValue(), doubleValue))
+ if (!toThisNumber(exec->thisValue(), doubleValue))
return throwVMTypeError(exec);
int32_t radix = extractRadixFromArgs(exec);
@@ -503,7 +510,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
}
if (!std::isfinite(doubleValue))
- return JSValue::encode(jsString(exec, String::numberToStringECMAScript(doubleValue)));
+ return JSValue::encode(jsNontrivialString(exec, String::numberToStringECMAScript(doubleValue)));
RadixBuffer s;
return JSValue::encode(jsString(exec, toStringWithRadix(s, doubleValue, radix)));
@@ -512,7 +519,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec)
{
double x;
- if (!toThisNumber(exec->hostThisValue(), x))
+ if (!toThisNumber(exec->thisValue(), x))
return throwVMTypeError(exec);
return JSValue::encode(jsNumber(x).toString(exec));
@@ -521,7 +528,7 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec)
EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec)
{
double x;
- if (!toThisNumber(exec->hostThisValue(), x))
+ if (!toThisNumber(exec->thisValue(), x))
return throwVMTypeError(exec);
return JSValue::encode(jsNumber(x));
}
diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.h b/Source/JavaScriptCore/runtime/NumberPrototype.h
index 723544faa..45acd8fb1 100644
--- a/Source/JavaScriptCore/runtime/NumberPrototype.h
+++ b/Source/JavaScriptCore/runtime/NumberPrototype.h
@@ -25,32 +25,32 @@
namespace JSC {
- class NumberPrototype : public NumberObject {
- public:
- typedef NumberObject Base;
-
- static NumberPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
- {
- NumberPrototype* prototype = new (NotNull, allocateCell<NumberPrototype>(vm.heap)) NumberPrototype(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(NumberObjectType, StructureFlags), info());
- }
-
- protected:
- void finishCreation(VM&, JSGlobalObject*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NumberObject::StructureFlags;
-
- private:
- NumberPrototype(VM&, Structure*);
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- };
+class NumberPrototype : public NumberObject {
+public:
+ typedef NumberObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static NumberPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+ {
+ NumberPrototype* prototype = new (NotNull, allocateCell<NumberPrototype>(vm.heap)) NumberPrototype(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(NumberObjectType, StructureFlags), info());
+ }
+
+protected:
+ void finishCreation(VM&, JSGlobalObject*);
+
+private:
+ NumberPrototype(VM&, Structure*);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NumericStrings.h b/Source/JavaScriptCore/runtime/NumericStrings.h
index 3bb5b91c8..ac8d41603 100644
--- a/Source/JavaScriptCore/runtime/NumericStrings.h
+++ b/Source/JavaScriptCore/runtime/NumericStrings.h
@@ -32,66 +32,66 @@
namespace JSC {
- class NumericStrings {
- public:
- ALWAYS_INLINE String add(double d)
- {
- CacheEntry<double>& entry = lookup(d);
- if (d == entry.key && !entry.value.isNull())
- return entry.value;
- entry.key = d;
- entry.value = String::numberToStringECMAScript(d);
+class NumericStrings {
+public:
+ ALWAYS_INLINE String add(double d)
+ {
+ CacheEntry<double>& entry = lookup(d);
+ if (d == entry.key && !entry.value.isNull())
return entry.value;
- }
+ entry.key = d;
+ entry.value = String::numberToStringECMAScript(d);
+ return entry.value;
+ }
- ALWAYS_INLINE String add(int i)
- {
- if (static_cast<unsigned>(i) < cacheSize)
- return lookupSmallString(static_cast<unsigned>(i));
- CacheEntry<int>& entry = lookup(i);
- if (i == entry.key && !entry.value.isNull())
- return entry.value;
- entry.key = i;
- entry.value = String::number(i);
+ ALWAYS_INLINE String add(int i)
+ {
+ if (static_cast<unsigned>(i) < cacheSize)
+ return lookupSmallString(static_cast<unsigned>(i));
+ CacheEntry<int>& entry = lookup(i);
+ if (i == entry.key && !entry.value.isNull())
return entry.value;
- }
+ entry.key = i;
+ entry.value = String::number(i);
+ return entry.value;
+ }
- ALWAYS_INLINE String add(unsigned i)
- {
- if (i < cacheSize)
- return lookupSmallString(static_cast<unsigned>(i));
- CacheEntry<unsigned>& entry = lookup(i);
- if (i == entry.key && !entry.value.isNull())
- return entry.value;
- entry.key = i;
- entry.value = String::number(i);
+ ALWAYS_INLINE String add(unsigned i)
+ {
+ if (i < cacheSize)
+ return lookupSmallString(static_cast<unsigned>(i));
+ CacheEntry<unsigned>& entry = lookup(i);
+ if (i == entry.key && !entry.value.isNull())
return entry.value;
- }
- private:
- static const size_t cacheSize = 64;
+ entry.key = i;
+ entry.value = String::number(i);
+ return entry.value;
+ }
+private:
+ static const size_t cacheSize = 64;
- template<typename T>
- struct CacheEntry {
- T key;
- String value;
- };
+ template<typename T>
+ struct CacheEntry {
+ T key;
+ String value;
+ };
- CacheEntry<double>& lookup(double d) { return doubleCache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; }
- CacheEntry<int>& lookup(int i) { return intCache[WTF::IntHash<int>::hash(i) & (cacheSize - 1)]; }
- CacheEntry<unsigned>& lookup(unsigned i) { return unsignedCache[WTF::IntHash<unsigned>::hash(i) & (cacheSize - 1)]; }
- ALWAYS_INLINE const String& lookupSmallString(unsigned i)
- {
- ASSERT(i < cacheSize);
- if (smallIntCache[i].isNull())
- smallIntCache[i] = String::number(i);
- return smallIntCache[i];
- }
+ CacheEntry<double>& lookup(double d) { return doubleCache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; }
+ CacheEntry<int>& lookup(int i) { return intCache[WTF::IntHash<int>::hash(i) & (cacheSize - 1)]; }
+ CacheEntry<unsigned>& lookup(unsigned i) { return unsignedCache[WTF::IntHash<unsigned>::hash(i) & (cacheSize - 1)]; }
+ ALWAYS_INLINE const String& lookupSmallString(unsigned i)
+ {
+ ASSERT(i < cacheSize);
+ if (smallIntCache[i].isNull())
+ smallIntCache[i] = String::number(i);
+ return smallIntCache[i];
+ }
- std::array<CacheEntry<double>, cacheSize> doubleCache;
- std::array<CacheEntry<int>, cacheSize> intCache;
- std::array<CacheEntry<unsigned>, cacheSize> unsignedCache;
- std::array<String, cacheSize> smallIntCache;
- };
+ std::array<CacheEntry<double>, cacheSize> doubleCache;
+ std::array<CacheEntry<int>, cacheSize> intCache;
+ std::array<CacheEntry<unsigned>, cacheSize> unsignedCache;
+ std::array<String, cacheSize> smallIntCache;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
index 72169e7d2..aa8334e6b 100644
--- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
@@ -22,35 +22,36 @@
#include "ObjectConstructor.h"
#include "ButterflyInlines.h"
-#include "CallFrameInlines.h"
#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "ExceptionHelpers.h"
-#include "JSFunction.h"
#include "JSArray.h"
+#include "JSCInlines.h"
+#include "JSFunction.h"
#include "JSGlobalObject.h"
+#include "JSGlobalObjectFunctions.h"
#include "Lookup.h"
#include "ObjectPrototype.h"
-#include "Operations.h"
#include "PropertyDescriptor.h"
#include "PropertyNameArray.h"
#include "StackVisitor.h"
+#include "Symbol.h"
namespace JSC {
-static EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*);
-static EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*);
-static EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*);
-static EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState*);
-static EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*);
-static EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*);
-static EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState*);
-static EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState*);
-static EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState*);
-static EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState*);
-static EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState*);
-static EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState*);
-static EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorSetPrototypeOf(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorIs(ExecState*);
}
@@ -60,12 +61,14 @@ namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ObjectConstructor);
-const ClassInfo ObjectConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::objectConstructorTable, CREATE_METHOD_TABLE(ObjectConstructor) };
+const ClassInfo ObjectConstructor::s_info = { "Function", &InternalFunction::s_info, &objectConstructorTable, CREATE_METHOD_TABLE(ObjectConstructor) };
/* Source for ObjectConstructor.lut.h
@begin objectConstructorTable
getPrototypeOf objectConstructorGetPrototypeOf DontEnum|Function 1
+ setPrototypeOf objectConstructorSetPrototypeOf DontEnum|Function 2
getOwnPropertyDescriptor objectConstructorGetOwnPropertyDescriptor DontEnum|Function 2
+ getOwnPropertyDescriptors objectConstructorGetOwnPropertyDescriptors DontEnum|Function 1
getOwnPropertyNames objectConstructorGetOwnPropertyNames DontEnum|Function 1
keys objectConstructorKeys DontEnum|Function 1
defineProperty objectConstructorDefineProperty DontEnum|Function 3
@@ -77,6 +80,8 @@ const ClassInfo ObjectConstructor::s_info = { "Function", &InternalFunction::s_i
isSealed objectConstructorIsSealed DontEnum|Function 1
isFrozen objectConstructorIsFrozen DontEnum|Function 1
isExtensible objectConstructorIsExtensible DontEnum|Function 1
+ is objectConstructorIs DontEnum|Function 2
+ assign JSBuiltin DontEnum|Function 2
@end
*/
@@ -85,18 +90,30 @@ ObjectConstructor::ObjectConstructor(VM& vm, Structure* structure)
{
}
-void ObjectConstructor::finishCreation(VM& vm, ObjectPrototype* objectPrototype)
+void ObjectConstructor::finishCreation(VM& vm, JSGlobalObject* globalObject, ObjectPrototype* objectPrototype)
{
- Base::finishCreation(vm, Identifier(&vm, "Object").string());
+ Base::finishCreation(vm, objectPrototype->classInfo()->className);
// ECMA 15.2.3.1
putDirectWithoutTransition(vm, vm.propertyNames->prototype, objectPrototype, DontEnum | DontDelete | ReadOnly);
// no. of arguments for constructor
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
+
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("getOwnPropertySymbols", objectConstructorGetOwnPropertySymbols, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->getPrototypeOfPrivateName, objectConstructorGetPrototypeOf, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->getOwnPropertyNamesPrivateName, objectConstructorGetOwnPropertyNames, DontEnum, 1);
+}
+
+JSFunction* ObjectConstructor::addDefineProperty(ExecState* exec, JSGlobalObject* globalObject)
+{
+ VM& vm = exec->vm();
+ JSFunction* definePropertyFunction = JSFunction::create(vm, globalObject, 3, vm.propertyNames->defineProperty.string(), objectConstructorDefineProperty);
+ putDirectWithoutTransition(vm, vm.propertyNames->defineProperty, definePropertyFunction, DontEnum);
+ return definePropertyFunction;
}
bool ObjectConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
{
- return getStaticFunctionSlot<JSObject>(exec, ExecState::objectConstructorTable(exec->vm()), jsCast<ObjectConstructor*>(object), propertyName, slot);
+ return getStaticFunctionSlot<JSObject>(exec, objectConstructorTable, jsCast<ObjectConstructor*>(object), propertyName, slot);
}
static ALWAYS_INLINE JSObject* constructObject(ExecState* exec)
@@ -136,11 +153,11 @@ public:
ObjectConstructorGetPrototypeOfFunctor(JSObject* object)
: m_hasSkippedFirstFrame(false)
, m_object(object)
- , m_result(JSValue::encode(jsUndefined()))
+ , m_result(jsUndefined())
{
}
- EncodedJSValue result() const { return m_result; }
+ JSValue result() const { return m_result; }
StackVisitor::Status operator()(StackVisitor& visitor)
{
@@ -149,40 +166,70 @@ public:
return StackVisitor::Continue;
}
- if (m_object->allowsAccessFrom(visitor->callFrame()))
- m_result = JSValue::encode(m_object->prototype());
- return StackVisitor::Done;
-}
+ if (m_object->allowsAccessFrom(visitor->callFrame()))
+ m_result = m_object->prototype();
+ return StackVisitor::Done;
+ }
private:
bool m_hasSkippedFirstFrame;
JSObject* m_object;
- EncodedJSValue m_result;
+ JSValue m_result;
};
-EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec)
+JSValue objectConstructorGetPrototypeOf(ExecState* exec, JSObject* object)
{
- if (!exec->argument(0).isObject())
- return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested prototype of a value that is not an object.")));
- JSObject* object = asObject(exec->argument(0));
ObjectConstructorGetPrototypeOfFunctor functor(object);
exec->iterate(functor);
return functor.result();
}
-EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec)
{
- if (!exec->argument(0).isObject())
- return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested property descriptor of a value that is not an object.")));
- String propertyName = exec->argument(1).toString(exec)->value(exec);
+ JSObject* object = exec->argument(0).toObject(exec);
if (exec->hadException())
- return JSValue::encode(jsNull());
- JSObject* object = asObject(exec->argument(0));
- PropertyDescriptor descriptor;
- if (!object->getOwnPropertyDescriptor(exec, Identifier(exec, propertyName), descriptor))
return JSValue::encode(jsUndefined());
+ return JSValue::encode(objectConstructorGetPrototypeOf(exec, object));
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorSetPrototypeOf(ExecState* exec)
+{
+ JSValue objectValue = exec->argument(0);
+ if (objectValue.isUndefinedOrNull())
+ return throwVMTypeError(exec);
+
+ JSValue protoValue = exec->argument(1);
+ if (!protoValue.isObject() && !protoValue.isNull())
+ return throwVMTypeError(exec);
+
+ JSObject* object = objectValue.toObject(exec);
if (exec->hadException())
+ return JSValue::encode(objectValue);
+
+ if (!checkProtoSetterAccessAllowed(exec, object))
+ return JSValue::encode(objectValue);
+
+ if (object->prototype() == protoValue)
+ return JSValue::encode(objectValue);
+
+ if (!object->isExtensible())
+ return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
+
+ if (!object->setPrototypeWithCycleCheck(exec, protoValue)) {
+ exec->vm().throwException(exec, createError(exec, ASCIILiteral("cyclic __proto__ value")));
return JSValue::encode(jsUndefined());
+ }
+
+ return JSValue::encode(objectValue);
+}
+
+JSValue objectConstructorGetOwnPropertyDescriptor(ExecState* exec, JSObject* object, const Identifier& propertyName)
+{
+ PropertyDescriptor descriptor;
+ if (!object->getOwnPropertyDescriptor(exec, propertyName, descriptor))
+ return jsUndefined();
+ if (exec->hadException())
+ return jsUndefined();
JSObject* description = constructEmptyObject(exec);
if (!descriptor.isAccessorDescriptor()) {
@@ -198,39 +245,85 @@ EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState
description->putDirect(exec->vm(), exec->propertyNames().enumerable, jsBoolean(descriptor.enumerable()), 0);
description->putDirect(exec->vm(), exec->propertyNames().configurable, jsBoolean(descriptor.configurable()), 0);
- return JSValue::encode(description);
+ return description;
+}
+
+JSValue objectConstructorGetOwnPropertyDescriptors(ExecState* exec, JSObject* object)
+{
+ PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
+ object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
+ if (exec->hadException())
+ return jsUndefined();
+
+ JSObject* descriptors = constructEmptyObject(exec);
+
+ for (auto& propertyName : properties) {
+ JSValue fromDescriptor = objectConstructorGetOwnPropertyDescriptor(exec, object, propertyName);
+ if (exec->hadException())
+ return jsUndefined();
+
+ descriptors->putDirect(exec->vm(), propertyName, fromDescriptor, 0);
+ }
+
+ return descriptors;
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec)
+{
+ JSObject* object = exec->argument(0).toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ auto propertyName = exec->argument(1).toPropertyKey(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(objectConstructorGetOwnPropertyDescriptor(exec, object, propertyName));
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptors(ExecState* exec)
+{
+ JSObject* object = exec->argument(0).toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(objectConstructorGetOwnPropertyDescriptors(exec, object));
}
// FIXME: Use the enumeration cache.
EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exec)
{
- if (!exec->argument(0).isObject())
- return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested property names of a value that is not an object.")));
- PropertyNameArray properties(exec);
- asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, IncludeDontEnumProperties);
- JSArray* names = constructEmptyArray(exec, 0);
- size_t numProperties = properties.size();
- for (size_t i = 0; i < numProperties; i++)
- names->push(exec, jsOwnedString(exec, properties[i].string()));
- return JSValue::encode(names);
+ JSObject* object = exec->argument(0).toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+ return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Include));
+}
+
+// FIXME: Use the enumeration cache.
+EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertySymbols(ExecState* exec)
+{
+ JSObject* object = exec->argument(0).toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+ return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::Symbols, DontEnumPropertiesMode::Include));
}
// FIXME: Use the enumeration cache.
EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec)
{
- if (!exec->argument(0).isObject())
- return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested keys of a value that is not an object.")));
- PropertyNameArray properties(exec);
- asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, ExcludeDontEnumProperties);
- JSArray* keys = constructEmptyArray(exec, 0);
- size_t numProperties = properties.size();
- for (size_t i = 0; i < numProperties; i++)
- keys->push(exec, jsOwnedString(exec, properties[i].string()));
- return JSValue::encode(keys);
+ JSObject* object = exec->argument(0).toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+ return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Exclude));
+}
+
+EncodedJSValue JSC_HOST_CALL ownEnumerablePropertyKeys(ExecState* exec)
+{
+ JSObject* object = exec->argument(0).toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+ return JSValue::encode(ownPropertyKeys(exec, object, PropertyNameMode::StringsAndSymbols, DontEnumPropertiesMode::Exclude));
}
// ES5 8.10.5 ToPropertyDescriptor
-static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor& desc)
+bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor& desc)
{
if (!in.isObject()) {
exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Property description must be an object.")));
@@ -238,14 +331,14 @@ static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor
}
JSObject* description = asObject(in);
- PropertySlot enumerableSlot(description);
+ PropertySlot enumerableSlot(description, PropertySlot::InternalMethodType::HasProperty);
if (description->getPropertySlot(exec, exec->propertyNames().enumerable, enumerableSlot)) {
desc.setEnumerable(enumerableSlot.getValue(exec, exec->propertyNames().enumerable).toBoolean(exec));
if (exec->hadException())
return false;
}
- PropertySlot configurableSlot(description);
+ PropertySlot configurableSlot(description, PropertySlot::InternalMethodType::HasProperty);
if (description->getPropertySlot(exec, exec->propertyNames().configurable, configurableSlot)) {
desc.setConfigurable(configurableSlot.getValue(exec, exec->propertyNames().configurable).toBoolean(exec));
if (exec->hadException())
@@ -253,21 +346,21 @@ static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor
}
JSValue value;
- PropertySlot valueSlot(description);
+ PropertySlot valueSlot(description, PropertySlot::InternalMethodType::HasProperty);
if (description->getPropertySlot(exec, exec->propertyNames().value, valueSlot)) {
desc.setValue(valueSlot.getValue(exec, exec->propertyNames().value));
if (exec->hadException())
return false;
}
- PropertySlot writableSlot(description);
+ PropertySlot writableSlot(description, PropertySlot::InternalMethodType::HasProperty);
if (description->getPropertySlot(exec, exec->propertyNames().writable, writableSlot)) {
desc.setWritable(writableSlot.getValue(exec, exec->propertyNames().writable).toBoolean(exec));
if (exec->hadException())
return false;
}
- PropertySlot getSlot(description);
+ PropertySlot getSlot(description, PropertySlot::InternalMethodType::HasProperty);
if (description->getPropertySlot(exec, exec->propertyNames().get, getSlot)) {
JSValue get = getSlot.getValue(exec, exec->propertyNames().get);
if (exec->hadException())
@@ -282,7 +375,7 @@ static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor
desc.setGetter(get);
}
- PropertySlot setSlot(description);
+ PropertySlot setSlot(description, PropertySlot::InternalMethodType::HasProperty);
if (description->getPropertySlot(exec, exec->propertyNames().set, setSlot)) {
JSValue set = setSlot.getValue(exec, exec->propertyNames().set);
if (exec->hadException())
@@ -317,7 +410,7 @@ EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState* exec)
if (!exec->argument(0).isObject())
return throwVMError(exec, createTypeError(exec, ASCIILiteral("Properties can only be defined on Objects.")));
JSObject* O = asObject(exec->argument(0));
- String propertyName = exec->argument(1).toString(exec)->value(exec);
+ auto propertyName = exec->argument(1).toPropertyKey(exec);
if (exec->hadException())
return JSValue::encode(jsNull());
PropertyDescriptor descriptor;
@@ -325,14 +418,14 @@ EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState* exec)
return JSValue::encode(jsNull());
ASSERT((descriptor.attributes() & Accessor) || (!descriptor.isAccessorDescriptor()));
ASSERT(!exec->hadException());
- O->methodTable()->defineOwnProperty(O, exec, Identifier(exec, propertyName), descriptor, true);
+ O->methodTable(exec->vm())->defineOwnProperty(O, exec, propertyName, descriptor, true);
return JSValue::encode(O);
}
static JSValue defineProperties(ExecState* exec, JSObject* object, JSObject* properties)
{
- PropertyNameArray propertyNames(exec);
- asObject(properties)->methodTable()->getOwnPropertyNames(asObject(properties), exec, propertyNames, ExcludeDontEnumProperties);
+ PropertyNameArray propertyNames(exec, PropertyNameMode::StringsAndSymbols);
+ asObject(properties)->methodTable(exec->vm())->getOwnPropertyNames(asObject(properties), exec, propertyNames, EnumerationMode(DontEnumPropertiesMode::Exclude));
size_t numProperties = propertyNames.size();
Vector<PropertyDescriptor> descriptors;
MarkedArgumentBuffer markBuffer;
@@ -355,7 +448,10 @@ static JSValue defineProperties(ExecState* exec, JSObject* object, JSObject* pro
}
}
for (size_t i = 0; i < numProperties; i++) {
- object->methodTable()->defineOwnProperty(object, exec, propertyNames[i], descriptors[i], true);
+ Identifier propertyName = propertyNames[i];
+ if (exec->propertyNames().isPrivateName(propertyName))
+ continue;
+ object->methodTable(exec->vm())->defineOwnProperty(object, exec, propertyName, descriptors[i], true);
if (exec->hadException())
return jsNull();
}
@@ -386,10 +482,10 @@ EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec)
EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec)
{
- // 1. If Type(O) is not Object throw a TypeError exception.
+ // 1. If Type(O) is not Object, return O.
JSValue obj = exec->argument(0);
if (!obj.isObject())
- return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.seal can only be called on Objects.")));
+ return JSValue::encode(obj);
JSObject* object = asObject(obj);
if (isJSFinalObject(object)) {
@@ -398,18 +494,21 @@ EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec)
}
// 2. For each named own property name P of O,
- PropertyNameArray properties(exec);
- object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties);
+ PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
+ object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
PropertyNameArray::const_iterator end = properties.end();
for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
+ Identifier propertyName = *iter;
+ if (exec->propertyNames().isPrivateName(propertyName))
+ continue;
// a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
PropertyDescriptor desc;
- if (!object->getOwnPropertyDescriptor(exec, *iter, desc))
+ if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
continue;
// b. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
desc.setConfigurable(false);
// c. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
- object->methodTable()->defineOwnProperty(object, exec, *iter, desc, true);
+ object->methodTable(exec->vm())->defineOwnProperty(object, exec, propertyName, desc, true);
if (exec->hadException())
return JSValue::encode(obj);
}
@@ -421,27 +520,24 @@ EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec)
return JSValue::encode(obj);
}
-EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec)
+JSObject* objectConstructorFreeze(ExecState* exec, JSObject* object)
{
- // 1. If Type(O) is not Object throw a TypeError exception.
- JSValue obj = exec->argument(0);
- if (!obj.isObject())
- return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.freeze can only be called on Objects.")));
- JSObject* object = asObject(obj);
-
- if (isJSFinalObject(object) && !hasIndexedProperties(object->structure()->indexingType())) {
+ if (isJSFinalObject(object) && !hasIndexedProperties(object->indexingType())) {
object->freeze(exec->vm());
- return JSValue::encode(obj);
+ return object;
}
// 2. For each named own property name P of O,
- PropertyNameArray properties(exec);
- object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties);
+ PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
+ object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
PropertyNameArray::const_iterator end = properties.end();
for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
+ Identifier propertyName = *iter;
+ if (exec->propertyNames().isPrivateName(propertyName))
+ continue;
// a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
PropertyDescriptor desc;
- if (!object->getOwnPropertyDescriptor(exec, *iter, desc))
+ if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
continue;
// b. If IsDataDescriptor(desc) is true, then
// i. If desc.[[Writable]] is true, set desc.[[Writable]] to false.
@@ -450,46 +546,58 @@ EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec)
// c. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
desc.setConfigurable(false);
// d. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
- object->methodTable()->defineOwnProperty(object, exec, *iter, desc, true);
+ object->methodTable(exec->vm())->defineOwnProperty(object, exec, propertyName, desc, true);
if (exec->hadException())
- return JSValue::encode(obj);
+ return object;
}
// 3. Set the [[Extensible]] internal property of O to false.
object->preventExtensions(exec->vm());
// 4. Return O.
- return JSValue::encode(obj);
+ return object;
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec)
+{
+ // 1. If Type(O) is not Object, return O.
+ JSValue obj = exec->argument(0);
+ if (!obj.isObject())
+ return JSValue::encode(obj);
+ return JSValue::encode(objectConstructorFreeze(exec, asObject(obj)));
}
EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState* exec)
{
JSValue obj = exec->argument(0);
if (!obj.isObject())
- return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.preventExtensions can only be called on Objects.")));
+ return JSValue::encode(obj);
asObject(obj)->preventExtensions(exec->vm());
return JSValue::encode(obj);
}
EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec)
{
- // 1. If Type(O) is not Object throw a TypeError exception.
+ // 1. If Type(O) is not Object, return true.
JSValue obj = exec->argument(0);
if (!obj.isObject())
- return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.isSealed can only be called on Objects.")));
+ return JSValue::encode(jsBoolean(true));
JSObject* object = asObject(obj);
if (isJSFinalObject(object))
return JSValue::encode(jsBoolean(object->isSealed(exec->vm())));
// 2. For each named own property name P of O,
- PropertyNameArray properties(exec);
- object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties);
+ PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
+ object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
PropertyNameArray::const_iterator end = properties.end();
for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
+ Identifier propertyName = *iter;
+ if (exec->propertyNames().isPrivateName(propertyName))
+ continue;
// a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
PropertyDescriptor desc;
- if (!object->getOwnPropertyDescriptor(exec, *iter, desc))
+ if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
continue;
// b. If desc.[[Configurable]] is true, then return false.
if (desc.configurable())
@@ -503,23 +611,26 @@ EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec)
EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState* exec)
{
- // 1. If Type(O) is not Object throw a TypeError exception.
+ // 1. If Type(O) is not Object, return true.
JSValue obj = exec->argument(0);
if (!obj.isObject())
- return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.isFrozen can only be called on Objects.")));
+ return JSValue::encode(jsBoolean(true));
JSObject* object = asObject(obj);
if (isJSFinalObject(object))
return JSValue::encode(jsBoolean(object->isFrozen(exec->vm())));
// 2. For each named own property name P of O,
- PropertyNameArray properties(exec);
- object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties);
+ PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
+ object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
PropertyNameArray::const_iterator end = properties.end();
for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
+ Identifier propertyName = *iter;
+ if (exec->propertyNames().isPrivateName(propertyName))
+ continue;
// a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
PropertyDescriptor desc;
- if (!object->getOwnPropertyDescriptor(exec, *iter, desc))
+ if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
continue;
// b. If IsDataDescriptor(desc) is true then
// i. If desc.[[Writable]] is true, return false. c. If desc.[[Configurable]] is true, then return false.
@@ -536,8 +647,66 @@ EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState* exec)
{
JSValue obj = exec->argument(0);
if (!obj.isObject())
- return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.isExtensible can only be called on Objects.")));
+ return JSValue::encode(jsBoolean(false));
return JSValue::encode(jsBoolean(asObject(obj)->isExtensible()));
}
+EncodedJSValue JSC_HOST_CALL objectConstructorIs(ExecState* exec)
+{
+ return JSValue::encode(jsBoolean(sameValue(exec, exec->argument(0), exec->argument(1))));
+}
+
+// FIXME: Use the enumeration cache.
+JSArray* ownPropertyKeys(ExecState* exec, JSObject* object, PropertyNameMode propertyNameMode, DontEnumPropertiesMode dontEnumPropertiesMode)
+{
+ PropertyNameArray properties(exec, propertyNameMode);
+ object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(dontEnumPropertiesMode));
+
+ JSArray* keys = constructEmptyArray(exec, 0);
+
+ switch (propertyNameMode) {
+ case PropertyNameMode::Strings: {
+ size_t numProperties = properties.size();
+ for (size_t i = 0; i < numProperties; i++) {
+ const auto& identifier = properties[i];
+ ASSERT(!identifier.isSymbol());
+ keys->push(exec, jsOwnedString(exec, identifier.string()));
+ }
+ break;
+ }
+
+ case PropertyNameMode::Symbols: {
+ size_t numProperties = properties.size();
+ for (size_t i = 0; i < numProperties; i++) {
+ const auto& identifier = properties[i];
+ ASSERT(identifier.isSymbol());
+ if (!exec->propertyNames().isPrivateName(identifier))
+ keys->push(exec, Symbol::create(exec->vm(), static_cast<SymbolImpl&>(*identifier.impl())));
+ }
+ break;
+ }
+
+ case PropertyNameMode::StringsAndSymbols: {
+ Vector<Identifier, 16> propertySymbols;
+ size_t numProperties = properties.size();
+ for (size_t i = 0; i < numProperties; i++) {
+ const auto& identifier = properties[i];
+ if (identifier.isSymbol()) {
+ if (!exec->propertyNames().isPrivateName(identifier))
+ propertySymbols.append(identifier);
+ } else
+ keys->push(exec, jsOwnedString(exec, identifier.string()));
+ }
+
+ // To ensure the order defined in the spec (9.1.12), we append symbols at the last elements of keys.
+ for (const auto& identifier : propertySymbols)
+ keys->push(exec, Symbol::create(exec->vm(), static_cast<SymbolImpl&>(*identifier.impl())));
+
+ break;
+ }
+ }
+
+ return keys;
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.h b/Source/JavaScriptCore/runtime/ObjectConstructor.h
index 4a6b4711b..6a12f5681 100644
--- a/Source/JavaScriptCore/runtime/ObjectConstructor.h
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.h
@@ -27,62 +27,77 @@
namespace JSC {
- class ObjectPrototype;
+EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptors(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertySymbols(ExecState*);
+EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState*);
+EncodedJSValue JSC_HOST_CALL ownEnumerablePropertyKeys(ExecState*);
- class ObjectConstructor : public InternalFunction {
- public:
- typedef InternalFunction Base;
+class ObjectPrototype;
- static ObjectConstructor* create(VM& vm, Structure* structure, ObjectPrototype* objectPrototype)
- {
- ObjectConstructor* constructor = new (NotNull, allocateCell<ObjectConstructor>(vm.heap)) ObjectConstructor(vm, structure);
- constructor->finishCreation(vm, objectPrototype);
- return constructor;
- }
+class ObjectConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
-
- DECLARE_INFO;
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
-
- protected:
- void finishCreation(VM& vm, ObjectPrototype*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
-
- private:
- ObjectConstructor(VM&, Structure*);
- static ConstructType getConstructData(JSCell*, ConstructData&);
- static CallType getCallData(JSCell*, CallData&);
- };
-
- inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure)
+ static ObjectConstructor* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, ObjectPrototype* objectPrototype)
{
- return JSFinalObject::create(exec, structure);
+ ObjectConstructor* constructor = new (NotNull, allocateCell<ObjectConstructor>(vm.heap)) ObjectConstructor(vm, structure);
+ constructor->finishCreation(vm, globalObject, objectPrototype);
+ return constructor;
}
- inline JSObject* constructEmptyObject(ExecState* exec, JSObject* prototype, unsigned inlineCapacity)
- {
- JSGlobalObject* globalObject = exec->lexicalGlobalObject();
- PrototypeMap& prototypeMap = globalObject->vm().prototypeMap;
- Structure* structure = prototypeMap.emptyObjectStructureForPrototype(
- prototype, inlineCapacity);
- return constructEmptyObject(exec, structure);
- }
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- inline JSObject* constructEmptyObject(ExecState* exec, JSObject* prototype)
- {
- return constructEmptyObject(exec, prototype, JSFinalObject::defaultInlineCapacity());
- }
+ DECLARE_INFO;
- inline JSObject* constructEmptyObject(ExecState* exec)
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return constructEmptyObject(exec, exec->lexicalGlobalObject()->objectPrototype());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}
+ JSFunction* addDefineProperty(ExecState*, JSGlobalObject*);
+
+protected:
+ void finishCreation(VM&, JSGlobalObject*, ObjectPrototype*);
+
+private:
+ ObjectConstructor(VM&, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+};
+
+inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure)
+{
+ return JSFinalObject::create(exec, structure);
+}
+
+inline JSObject* constructEmptyObject(ExecState* exec, JSObject* prototype, unsigned inlineCapacity)
+{
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ PrototypeMap& prototypeMap = globalObject->vm().prototypeMap;
+ Structure* structure = prototypeMap.emptyObjectStructureForPrototype(
+ prototype, inlineCapacity);
+ return constructEmptyObject(exec, structure);
+}
+
+inline JSObject* constructEmptyObject(ExecState* exec, JSObject* prototype)
+{
+ return constructEmptyObject(exec, prototype, JSFinalObject::defaultInlineCapacity());
+}
+
+inline JSObject* constructEmptyObject(ExecState* exec)
+{
+ return constructEmptyObject(exec, exec->lexicalGlobalObject()->objectPrototype());
+}
+
+JSObject* objectConstructorFreeze(ExecState*, JSObject*);
+JSValue objectConstructorGetPrototypeOf(ExecState*, JSObject*);
+JSValue objectConstructorGetOwnPropertyDescriptor(ExecState*, JSObject*, const Identifier&);
+JSValue objectConstructorGetOwnPropertyDescriptors(ExecState*, JSObject*);
+JSArray* ownPropertyKeys(ExecState*, JSObject*, PropertyNameMode, DontEnumPropertiesMode);
+bool toPropertyDescriptor(ExecState*, JSValue, PropertyDescriptor&);
+
} // namespace JSC
#endif // ObjectConstructor_h
diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
index 9bfbe9741..4cb86eee7 100644
--- a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
@@ -25,8 +25,9 @@
#include "GetterSetter.h"
#include "JSFunction.h"
#include "JSString.h"
-#include "JSStringBuilder.h"
-#include "Operations.h"
+#include "JSCInlines.h"
+#include "PropertySlot.h"
+#include "StructureInlines.h"
#include "StructureRareDataInlines.h"
namespace JSC {
@@ -43,7 +44,7 @@ static EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState*);
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ObjectPrototype);
-const ClassInfo ObjectPrototype::s_info = { "Object", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(ObjectPrototype) };
+const ClassInfo ObjectPrototype::s_info = { "Object", &JSNonFinalObject::s_info, 0, CREATE_METHOD_TABLE(ObjectPrototype) };
ObjectPrototype::ObjectPrototype(VM& vm, Structure* stucture)
: JSNonFinalObject(vm, stucture)
@@ -56,16 +57,16 @@ void ObjectPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
ASSERT(inherits(info()));
vm.prototypeMap.addPrototype(this);
- JSC_NATIVE_FUNCTION(vm.propertyNames->toString, objectProtoFuncToString, DontEnum, 0);
- JSC_NATIVE_FUNCTION(vm.propertyNames->toLocaleString, objectProtoFuncToLocaleString, DontEnum, 0);
- JSC_NATIVE_FUNCTION(vm.propertyNames->valueOf, objectProtoFuncValueOf, DontEnum, 0);
- JSC_NATIVE_FUNCTION(vm.propertyNames->hasOwnProperty, objectProtoFuncHasOwnProperty, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->propertyIsEnumerable, objectProtoFuncPropertyIsEnumerable, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->isPrototypeOf, objectProtoFuncIsPrototypeOf, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->__defineGetter__, objectProtoFuncDefineGetter, DontEnum, 2);
- JSC_NATIVE_FUNCTION(vm.propertyNames->__defineSetter__, objectProtoFuncDefineSetter, DontEnum, 2);
- JSC_NATIVE_FUNCTION(vm.propertyNames->__lookupGetter__, objectProtoFuncLookupGetter, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->__lookupSetter__, objectProtoFuncLookupSetter, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toString, objectProtoFuncToString, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toLocaleString, objectProtoFuncToLocaleString, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->valueOf, objectProtoFuncValueOf, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->hasOwnProperty, objectProtoFuncHasOwnProperty, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->propertyIsEnumerable, objectProtoFuncPropertyIsEnumerable, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->isPrototypeOf, objectProtoFuncIsPrototypeOf, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->__defineGetter__, objectProtoFuncDefineGetter, DontEnum, 2);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->__defineSetter__, objectProtoFuncDefineSetter, DontEnum, 2);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->__lookupGetter__, objectProtoFuncLookupGetter, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->__lookupSetter__, objectProtoFuncLookupSetter, DontEnum, 1);
}
ObjectPrototype* ObjectPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
@@ -79,19 +80,22 @@ ObjectPrototype* ObjectPrototype::create(VM& vm, JSGlobalObject* globalObject, S
EncodedJSValue JSC_HOST_CALL objectProtoFuncValueOf(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode);
+ JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
return JSValue::encode(thisValue.toObject(exec));
}
EncodedJSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode);
- return JSValue::encode(jsBoolean(thisValue.toObject(exec)->hasOwnProperty(exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec)))));
+ JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
+ auto propertyName = exec->argument(0).toPropertyKey(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(jsBoolean(thisValue.toObject(exec)->hasOwnProperty(exec, propertyName)));
}
EncodedJSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode);
+ JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
JSObject* thisObj = thisValue.toObject(exec);
if (!exec->argument(0).isObject())
@@ -110,7 +114,7 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState* exec)
EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState* exec)
{
- JSObject* thisObject = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
+ JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
if (exec->hadException())
return JSValue::encode(jsUndefined());
@@ -119,18 +123,24 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState* exec)
if (getCallData(get, callData) == CallTypeNone)
return throwVMError(exec, createTypeError(exec, ASCIILiteral("invalid getter usage")));
+ auto propertyName = exec->argument(0).toPropertyKey(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
PropertyDescriptor descriptor;
descriptor.setGetter(get);
descriptor.setEnumerable(true);
descriptor.setConfigurable(true);
- thisObject->methodTable()->defineOwnProperty(thisObject, exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec)), descriptor, false);
+
+ bool shouldThrow = false;
+ thisObject->methodTable(exec->vm())->defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
return JSValue::encode(jsUndefined());
}
EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState* exec)
{
- JSObject* thisObject = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
+ JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
if (exec->hadException())
return JSValue::encode(jsUndefined());
@@ -139,48 +149,84 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState* exec)
if (getCallData(set, callData) == CallTypeNone)
return throwVMError(exec, createTypeError(exec, ASCIILiteral("invalid setter usage")));
+ auto propertyName = exec->argument(0).toPropertyKey(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
PropertyDescriptor descriptor;
descriptor.setSetter(set);
descriptor.setEnumerable(true);
descriptor.setConfigurable(true);
- thisObject->methodTable()->defineOwnProperty(thisObject, exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec)), descriptor, false);
+
+ bool shouldThrow = false;
+ thisObject->methodTable(exec->vm())->defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
return JSValue::encode(jsUndefined());
}
EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState* exec)
{
- JSObject* thisObject = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
+ JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- PropertySlot slot(thisObject);
- if (thisObject->getPropertySlot(exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec)), slot)
- && slot.isAccessor())
- return JSValue::encode(slot.getterSetter()->getter());
+ auto propertyName = exec->argument(0).toPropertyKey(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
+ if (thisObject->getPropertySlot(exec, propertyName, slot)) {
+ if (slot.isAccessor()) {
+ GetterSetter* getterSetter = slot.getterSetter();
+ return getterSetter->isGetterNull() ? JSValue::encode(jsUndefined()) : JSValue::encode(getterSetter->getter());
+ }
+ if (slot.attributes() & CustomAccessor) {
+ PropertyDescriptor descriptor;
+ ASSERT(slot.slotBase());
+ if (slot.slotBase()->getOwnPropertyDescriptor(exec, propertyName, descriptor))
+ return descriptor.getterPresent() ? JSValue::encode(descriptor.getter()) : JSValue::encode(jsUndefined());
+ }
+ }
return JSValue::encode(jsUndefined());
}
EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState* exec)
{
- JSObject* thisObject = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
+ JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ auto propertyName = exec->argument(0).toPropertyKey(exec);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- PropertySlot slot(thisObject);
- if (thisObject->getPropertySlot(exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec)), slot)
- && slot.isAccessor())
- return JSValue::encode(slot.getterSetter()->setter());
+ PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry);
+ if (thisObject->getPropertySlot(exec, propertyName, slot)) {
+ if (slot.isAccessor()) {
+ GetterSetter* getterSetter = slot.getterSetter();
+ return getterSetter->isSetterNull() ? JSValue::encode(jsUndefined()) : JSValue::encode(getterSetter->setter());
+ }
+ if (slot.attributes() & CustomAccessor) {
+ PropertyDescriptor descriptor;
+ ASSERT(slot.slotBase());
+ if (slot.slotBase()->getOwnPropertyDescriptor(exec, propertyName, descriptor))
+ return descriptor.setterPresent() ? JSValue::encode(descriptor.setter()) : JSValue::encode(jsUndefined());
+ }
+ }
return JSValue::encode(jsUndefined());
}
EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState* exec)
{
- JSObject* thisObject = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
- Identifier propertyName(exec, exec->argument(0).toString(exec)->value(exec));
+ auto propertyName = exec->argument(0).toPropertyKey(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
PropertyDescriptor descriptor;
bool enumerable = thisObject->getOwnPropertyDescriptor(exec, propertyName, descriptor) && descriptor.enumerable();
return JSValue::encode(jsBoolean(enumerable));
@@ -190,7 +236,7 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState* exec
EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec)
{
// 1. Let O be the result of calling ToObject passing the this value as the argument.
- JSObject* object = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec);
+ JSObject* object = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
if (exec->hadException())
return JSValue::encode(jsUndefined());
@@ -209,20 +255,38 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec)
EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue().toThis(exec, StrictMode);
+ VM& vm = exec->vm();
+ JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
if (thisValue.isUndefinedOrNull())
- return JSValue::encode(jsNontrivialString(exec, String(thisValue.isUndefined() ? ASCIILiteral("[object Undefined]") : ASCIILiteral("[object Null]"))));
+ return JSValue::encode(thisValue.isUndefined() ? vm.smallStrings.undefinedObjectString() : vm.smallStrings.nullObjectString());
JSObject* thisObject = thisValue.toObject(exec);
- JSString* result = thisObject->structure()->objectToStringValue();
+ JSString* result = thisObject->structure(vm)->objectToStringValue();
if (!result) {
- RefPtr<StringImpl> newString = WTF::tryMakeString("[object ", thisObject->methodTable()->className(thisObject), "]");
+ PropertyName toStringTagSymbol = exec->propertyNames().toStringTagSymbol;
+ PropertySlot toStringTagSlot(thisObject, PropertySlot::InternalMethodType::Get);
+ if (thisObject->getPropertySlot(exec, toStringTagSymbol, toStringTagSlot)) {
+ JSValue stringTag = toStringTagSlot.getValue(exec, toStringTagSymbol);
+ if (stringTag.isString()) {
+ JSRopeString::RopeBuilder ropeBuilder(vm);
+ ropeBuilder.append(vm.smallStrings.objectStringStart());
+ ropeBuilder.append(jsCast<JSString*>(stringTag));
+ ropeBuilder.append(vm.smallStrings.singleCharacterString(']'));
+ result = ropeBuilder.release();
+
+ thisObject->structure(vm)->setObjectToStringValue(exec, vm, result, toStringTagSlot);
+ return JSValue::encode(result);
+ }
+ }
+
+ String newString = WTF::tryMakeString("[object ", thisObject->methodTable(exec->vm())->className(thisObject), "]");
if (!newString)
return JSValue::encode(throwOutOfMemoryError(exec));
- result = jsNontrivialString(exec, newString.release());
- thisObject->structure()->setObjectToStringValue(exec->vm(), thisObject, result);
+ result = jsNontrivialString(&vm, newString);
+ thisObject->structure(vm)->setObjectToStringValue(exec, vm, result, toStringTagSlot);
}
+
return JSValue::encode(result);
}
diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.h b/Source/JavaScriptCore/runtime/ObjectPrototype.h
index 75a2a95a1..34238a9f4 100644
--- a/Source/JavaScriptCore/runtime/ObjectPrototype.h
+++ b/Source/JavaScriptCore/runtime/ObjectPrototype.h
@@ -25,27 +25,27 @@
namespace JSC {
- class ObjectPrototype : public JSNonFinalObject {
- public:
- typedef JSNonFinalObject Base;
+class ObjectPrototype : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
- static ObjectPrototype* create(VM&, JSGlobalObject*, Structure*);
+ static ObjectPrototype* create(VM&, JSGlobalObject*, Structure*);
- DECLARE_INFO;
+ DECLARE_INFO;
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
- protected:
- void finishCreation(VM&, JSGlobalObject*);
+protected:
+ void finishCreation(VM&, JSGlobalObject*);
- private:
- ObjectPrototype(VM&, Structure*);
- };
+private:
+ ObjectPrototype(VM&, Structure*);
+};
- JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*);
+JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Operations.cpp b/Source/JavaScriptCore/runtime/Operations.cpp
index f0ffd5668..5732cfd0c 100644
--- a/Source/JavaScriptCore/runtime/Operations.cpp
+++ b/Source/JavaScriptCore/runtime/Operations.cpp
@@ -23,6 +23,7 @@
#include "Operations.h"
#include "Error.h"
+#include "JSCInlines.h"
#include "JSObject.h"
#include "JSString.h"
#include <wtf/MathExtras.h>
@@ -64,15 +65,22 @@ JSValue jsTypeStringForValue(VM& vm, JSGlobalObject* globalObject, JSValue v)
return vm.smallStrings.numberString();
if (v.isString())
return vm.smallStrings.stringString();
+ if (v.isSymbol())
+ return vm.smallStrings.symbolString();
if (v.isObject()) {
+ JSObject* object = asObject(v);
// Return "undefined" for objects that should be treated
// as null when doing comparisons.
- if (asObject(v)->structure()->masqueradesAsUndefined(globalObject))
+ if (object->structure(vm)->masqueradesAsUndefined(globalObject))
return vm.smallStrings.undefinedString();
- CallData callData;
- JSObject* object = asObject(v);
- if (object->methodTable()->getCallData(object, callData) != CallTypeNone)
+ if (object->type() == JSFunctionType)
return vm.smallStrings.functionString();
+ if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
+ CallData callData;
+ JSObject* object = asObject(v);
+ if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
+ return vm.smallStrings.functionString();
+ }
}
return vm.smallStrings.objectString();
}
@@ -82,20 +90,20 @@ JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v)
return jsTypeStringForValue(callFrame->vm(), callFrame->lexicalGlobalObject(), v);
}
-bool jsIsObjectType(CallFrame* callFrame, JSValue v)
+bool jsIsObjectTypeOrNull(CallFrame* callFrame, JSValue v)
{
if (!v.isCell())
return v.isNull();
- JSType type = v.asCell()->structure()->typeInfo().type();
- if (type == StringType)
+ JSType type = v.asCell()->type();
+ if (type == StringType || type == SymbolType)
return false;
if (type >= ObjectType) {
- if (asObject(v)->structure()->masqueradesAsUndefined(callFrame->lexicalGlobalObject()))
+ if (asObject(v)->structure(callFrame->vm())->masqueradesAsUndefined(callFrame->lexicalGlobalObject()))
return false;
CallData callData;
JSObject* object = asObject(v);
- if (object->methodTable()->getCallData(object, callData) != CallTypeNone)
+ if (object->methodTable(callFrame->vm())->getCallData(object, callData) != CallTypeNone)
return false;
}
return true;
diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h
index cee00ebf4..057f59471 100644
--- a/Source/JavaScriptCore/runtime/Operations.h
+++ b/Source/JavaScriptCore/runtime/Operations.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2002, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2002, 2005, 2006, 2007, 2008, 2009, 2013, 2014 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
@@ -22,23 +22,16 @@
#ifndef Operations_h
#define Operations_h
+#include "CallFrame.h"
#include "ExceptionHelpers.h"
-#include "GCIncomingRefCountedInlines.h"
-#include "Interpreter.h"
-#include "JSArrayBufferViewInlines.h"
-#include "JSCJSValueInlines.h"
-#include "JSFunctionInlines.h"
-#include "JSProxy.h"
-#include "JSString.h"
-#include "SlotVisitorInlines.h"
-#include "StructureInlines.h"
+#include "JSCJSValue.h"
namespace JSC {
NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue);
JSValue jsTypeStringForValue(CallFrame*, JSValue);
JSValue jsTypeStringForValue(VM&, JSGlobalObject*, JSValue);
-bool jsIsObjectType(CallFrame*, JSValue);
+bool jsIsObjectTypeOrNull(CallFrame*, JSValue);
bool jsIsFunctionType(JSValue);
ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2)
@@ -201,85 +194,28 @@ ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2)
#define InvalidPrototypeChain (std::numeric_limits<size_t>::max())
-inline size_t normalizePrototypeChainForChainAccess(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, PropertyOffset& slotOffset)
-{
- JSCell* cell = base.asCell();
- size_t count = 0;
-
- while (!slotBase || slotBase != cell) {
- if (cell->isProxy())
- return InvalidPrototypeChain;
-
- const TypeInfo& typeInfo = cell->structure()->typeInfo();
- if (typeInfo.hasImpureGetOwnPropertySlot() && !typeInfo.newImpurePropertyFiresWatchpoints())
- return InvalidPrototypeChain;
-
- JSValue v = cell->structure()->prototypeForLookup(callFrame);
-
- // If we didn't find slotBase in base's prototype chain, then base
- // must be a proxy for another object.
-
- if (v.isNull()) {
- if (!slotBase)
- return count;
- return InvalidPrototypeChain;
- }
-
- cell = v.asCell();
-
- // Since we're accessing a prototype in a loop, it's a good bet that it
- // should not be treated as a dictionary.
- if (cell->structure()->isDictionary()) {
- asObject(cell)->flattenDictionaryObject(callFrame->vm());
- if (slotBase == cell)
- slotOffset = cell->structure()->get(callFrame->vm(), propertyName);
- }
-
- ++count;
- }
-
- return count;
-}
-
-inline size_t normalizePrototypeChain(CallFrame* callFrame, JSCell* base)
+inline size_t normalizePrototypeChain(CallFrame* callFrame, Structure* structure)
{
+ VM& vm = callFrame->vm();
size_t count = 0;
while (1) {
- if (base->isProxy())
+ if (structure->isProxy())
return InvalidPrototypeChain;
-
- JSValue v = base->structure()->prototypeForLookup(callFrame);
+ JSValue v = structure->prototypeForLookup(callFrame);
if (v.isNull())
return count;
- base = v.asCell();
-
+ JSCell* base = v.asCell();
+ structure = base->structure(vm);
// Since we're accessing a prototype in a loop, it's a good bet that it
// should not be treated as a dictionary.
- if (base->structure()->isDictionary())
- asObject(base)->flattenDictionaryObject(callFrame->vm());
+ if (structure->isDictionary())
+ structure->flattenDictionaryStructure(vm, asObject(base));
++count;
}
}
-inline bool isPrototypeChainNormalized(JSGlobalObject* globalObject, Structure* structure)
-{
- for (;;) {
- if (structure->typeInfo().type() == ProxyType)
- return false;
-
- JSValue v = structure->prototypeForLookup(globalObject);
- if (v.isNull())
- return true;
-
- structure = v.asCell()->structure();
-
- if (structure->isDictionary())
- return false;
- }
-}
-
} // namespace JSC
#endif // Operations_h
diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp
index aa8ccc751..812002005 100644
--- a/Source/JavaScriptCore/runtime/Options.cpp
+++ b/Source/JavaScriptCore/runtime/Options.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2012, 2014-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
@@ -26,20 +26,31 @@
#include "config.h"
#include "Options.h"
-#include "HeapStatistics.h"
#include <algorithm>
#include <limits>
+#include <math.h>
+#include <mutex>
#include <stdlib.h>
#include <string.h>
+#include <wtf/ASCIICType.h>
+#include <wtf/Compiler.h>
+#include <wtf/DataLog.h>
#include <wtf/NumberOfCores.h>
-#include <wtf/PageBlock.h>
#include <wtf/StdLibExtras.h>
#include <wtf/StringExtras.h>
+#include <wtf/text/StringBuilder.h>
-#if OS(DARWIN) && ENABLE(PARALLEL_GC)
-#include <sys/sysctl.h>
+#if PLATFORM(COCOA)
+#include <crt_externs.h>
#endif
+#if OS(WINDOWS)
+#include "MacroAssemblerX86.h"
+#endif
+
+#define USE_OPTIONS_FILE 0
+#define OPTIONS_FILENAME "/tmp/jsc.options"
+
namespace JSC {
static bool parse(const char* string, bool& value)
@@ -75,43 +86,87 @@ static bool parse(const char* string, OptionRange& value)
return value.init(string);
}
+static bool parse(const char* string, const char*& value)
+{
+ if (!strlen(string))
+ string = nullptr;
+ value = string;
+ return true;
+}
+
+static bool parse(const char* string, GCLogging::Level& value)
+{
+ if (!strcasecmp(string, "none") || !strcasecmp(string, "no") || !strcasecmp(string, "false") || !strcmp(string, "0")) {
+ value = GCLogging::None;
+ return true;
+ }
+
+ if (!strcasecmp(string, "basic") || !strcasecmp(string, "yes") || !strcasecmp(string, "true") || !strcmp(string, "1")) {
+ value = GCLogging::Basic;
+ return true;
+ }
+
+ if (!strcasecmp(string, "verbose") || !strcmp(string, "2")) {
+ value = GCLogging::Verbose;
+ return true;
+ }
+
+ return false;
+}
+
template<typename T>
-void overrideOptionWithHeuristic(T& variable, const char* name)
+bool overrideOptionWithHeuristic(T& variable, const char* name)
{
-#if !OS(WINCE)
const char* stringValue = getenv(name);
if (!stringValue)
- return;
+ return false;
if (parse(stringValue, variable))
- return;
+ return true;
fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue);
-#endif
+ return false;
}
-static unsigned computeNumberOfWorkerThreads(int maxNumberOfWorkerThreads)
+bool Options::overrideAliasedOptionWithHeuristic(const char* name)
+{
+ const char* stringValue = getenv(name);
+ if (!stringValue)
+ return false;
+
+ String aliasedOption;
+ aliasedOption = String(&name[4]) + "=" + stringValue;
+ if (Options::setOption(aliasedOption.utf8().data()))
+ return true;
+
+ fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue);
+ return false;
+}
+
+static unsigned computeNumberOfWorkerThreads(int maxNumberOfWorkerThreads, int minimum = 1)
{
int cpusToUse = std::min(WTF::numberOfProcessorCores(), maxNumberOfWorkerThreads);
// Be paranoid, it is the OS we're dealing with, after all.
ASSERT(cpusToUse >= 1);
- if (cpusToUse < 1)
- cpusToUse = 1;
-
- return cpusToUse;
+ return std::max(cpusToUse, minimum);
+}
+
+static int32_t computePriorityDeltaOfWorkerThreads(int32_t twoCorePriorityDelta, int32_t multiCorePriorityDelta)
+{
+ if (WTF::numberOfProcessorCores() <= 2)
+ return twoCorePriorityDelta;
+
+ return multiCorePriorityDelta;
}
static unsigned computeNumberOfGCMarkers(unsigned maxNumberOfGCMarkers)
{
-#if ENABLE(PARALLEL_GC)
return computeNumberOfWorkerThreads(maxNumberOfGCMarkers);
-#else
- UNUSED_PARAM(maxNumberOfGCMarkers);
- return 1;
-#endif
}
+const char* const OptionRange::s_nullRangeStr = "<null>";
+
bool OptionRange::init(const char* rangeString)
{
// rangeString should be in the form of [!]<low>[:<high>]
@@ -119,14 +174,16 @@ bool OptionRange::init(const char* rangeString)
bool invert = false;
- if (m_state > Uninitialized)
- return true;
-
if (!rangeString) {
m_state = InitError;
return false;
}
+ if (!strcmp(rangeString, s_nullRangeStr)) {
+ m_state = Uninitialized;
+ return true;
+ }
+
m_rangeString = rangeString;
if (*rangeString == '!') {
@@ -165,74 +222,322 @@ bool OptionRange::isInRange(unsigned count)
return m_state == Normal ? false : true;
}
+void OptionRange::dump(PrintStream& out) const
+{
+ out.print(m_rangeString);
+}
+
Options::Entry Options::s_options[Options::numberOfOptions];
+Options::Entry Options::s_defaultOptions[Options::numberOfOptions];
// Realize the names for each of the options:
const Options::EntryInfo Options::s_optionsInfo[Options::numberOfOptions] = {
-#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
- { #name_, Options::type_##Type },
+#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \
+ { #name_, description_, Options::Type::type_##Type },
JSC_OPTIONS(FOR_EACH_OPTION)
#undef FOR_EACH_OPTION
};
-void Options::initialize()
+static void scaleJITPolicy()
{
- // Initialize each of the options with their default values:
-#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
- name_() = defaultValue_;
- JSC_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
-
-#if USE(CF) || OS(UNIX)
- objectsAreImmortal() = !!getenv("JSImmortalZombieEnabled");
- useZombieMode() = !!getenv("JSImmortalZombieEnabled") || !!getenv("JSZombieEnabled");
-
- gcMaxHeapSize() = getenv("GCMaxHeapSize") ? HeapStatistics::parseMemoryAmount(getenv("GCMaxHeapSize")) : 0;
- recordGCPauseTimes() = !!getenv("JSRecordGCPauseTimes");
- logHeapStatisticsAtExit() = gcMaxHeapSize() || recordGCPauseTimes();
-#endif
-
- // Allow environment vars to override options if applicable.
- // The evn var should be the name of the option prefixed with
- // "JSC_".
-#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
- overrideOptionWithHeuristic(name_(), "JSC_" #name_);
- JSC_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
+ auto& scaleFactor = Options::jitPolicyScale();
+ if (scaleFactor > 1.0)
+ scaleFactor = 1.0;
+ else if (scaleFactor < 0.0)
+ scaleFactor = 0.0;
+
+ struct OptionToScale {
+ Options::OptionID id;
+ int32_t minVal;
+ };
+
+ static const OptionToScale optionsToScale[] = {
+ { Options::thresholdForJITAfterWarmUpID, 0 },
+ { Options::thresholdForJITSoonID, 0 },
+ { Options::thresholdForOptimizeAfterWarmUpID, 1 },
+ { Options::thresholdForOptimizeAfterLongWarmUpID, 1 },
+ { Options::thresholdForOptimizeSoonID, 1 },
+ { Options::thresholdForFTLOptimizeSoonID, 2 },
+ { Options::thresholdForFTLOptimizeAfterWarmUpID, 2 }
+ };
+
+ const int numberOfOptionsToScale = sizeof(optionsToScale) / sizeof(OptionToScale);
+ for (int i = 0; i < numberOfOptionsToScale; i++) {
+ Option option(optionsToScale[i].id);
+ ASSERT(option.type() == Options::Type::int32Type);
+ option.int32Val() *= scaleFactor;
+ option.int32Val() = std::max(option.int32Val(), optionsToScale[i].minVal);
+ }
+}
-#if 0
- ; // Deconfuse editors that do auto indentation
+static void recomputeDependentOptions()
+{
+#if !defined(NDEBUG)
+ Options::validateDFGExceptionHandling() = true;
#endif
-
#if !ENABLE(JIT)
- useJIT() = false;
- useDFGJIT() = false;
+ Options::useLLInt() = true;
+ Options::useJIT() = false;
+ Options::useDFGJIT() = false;
+ Options::useFTLJIT() = false;
#endif
#if !ENABLE(YARR_JIT)
- useRegExpJIT() = false;
+ Options::useRegExpJIT() = false;
#endif
-
- // Do range checks where needed and make corrections to the options:
- ASSERT(thresholdForOptimizeAfterLongWarmUp() >= thresholdForOptimizeAfterWarmUp());
- ASSERT(thresholdForOptimizeAfterWarmUp() >= thresholdForOptimizeSoon());
- ASSERT(thresholdForOptimizeAfterWarmUp() >= 0);
+#if !ENABLE(CONCURRENT_JIT)
+ Options::useConcurrentJIT() = false;
+#endif
+#if !ENABLE(DFG_JIT)
+ Options::useDFGJIT() = false;
+ Options::useFTLJIT() = false;
+#endif
+#if !ENABLE(FTL_JIT)
+ Options::useFTLJIT() = false;
+#endif
+#if OS(WINDOWS) && CPU(X86)
+ // Disable JIT on Windows if SSE2 is not present
+ if (!MacroAssemblerX86::supportsFloatingPoint())
+ Options::useJIT() = false;
+#endif
+ if (Options::dumpDisassembly()
+ || Options::dumpDFGDisassembly()
+ || Options::dumpFTLDisassembly()
+ || Options::dumpBytecodeAtDFGTime()
+ || Options::dumpGraphAtEachPhase()
+ || Options::dumpDFGGraphAtEachPhase()
+ || Options::dumpDFGFTLGraphAtEachPhase()
+ || Options::dumpB3GraphAtEachPhase()
+ || Options::dumpAirGraphAtEachPhase()
+ || Options::verboseCompilation()
+ || Options::verboseFTLCompilation()
+ || Options::logCompilationChanges()
+ || Options::validateGraph()
+ || Options::validateGraphAtEachPhase()
+ || Options::verboseOSR()
+ || Options::verboseCompilationQueue()
+ || Options::reportCompileTimes()
+ || Options::reportFTLCompileTimes()
+ || Options::verboseCFA()
+ || Options::verboseFTLFailure())
+ Options::alwaysComputeHash() = true;
+
+ if (Option(Options::jitPolicyScaleID).isOverridden())
+ scaleJITPolicy();
+
+ if (Options::forceEagerCompilation()) {
+ Options::thresholdForJITAfterWarmUp() = 10;
+ Options::thresholdForJITSoon() = 10;
+ Options::thresholdForOptimizeAfterWarmUp() = 20;
+ Options::thresholdForOptimizeAfterLongWarmUp() = 20;
+ Options::thresholdForOptimizeSoon() = 20;
+ Options::thresholdForFTLOptimizeAfterWarmUp() = 20;
+ Options::thresholdForFTLOptimizeSoon() = 20;
+ Options::maximumEvalCacheableSourceLength() = 150000;
+ Options::useConcurrentJIT() = false;
+ }
+ if (Options::useMaximalFlushInsertionPhase()) {
+ Options::useOSREntryToDFG() = false;
+ Options::useOSREntryToFTL() = false;
+ }
// Compute the maximum value of the reoptimization retry counter. This is simply
// the largest value at which we don't overflow the execute counter, when using it
// to left-shift the execution counter by this amount. Currently the value ends
// up being 18, so this loop is not so terrible; it probably takes up ~100 cycles
// total on a 32-bit processor.
- reoptimizationRetryCounterMax() = 0;
- while ((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << (reoptimizationRetryCounterMax() + 1)) <= static_cast<int64_t>(std::numeric_limits<int32>::max()))
- reoptimizationRetryCounterMax()++;
+ Options::reoptimizationRetryCounterMax() = 0;
+ while ((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << (Options::reoptimizationRetryCounterMax() + 1)) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()))
+ Options::reoptimizationRetryCounterMax()++;
+
+ ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) > 0);
+ ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()));
+}
+
+void Options::initialize()
+{
+ static std::once_flag initializeOptionsOnceFlag;
+
+ std::call_once(
+ initializeOptionsOnceFlag,
+ [] {
+ // Initialize each of the options with their default values:
+#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \
+ name_() = defaultValue_; \
+ name_##Default() = defaultValue_;
+ JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+
+ // Allow environment vars to override options if applicable.
+ // The evn var should be the name of the option prefixed with
+ // "JSC_".
+#if PLATFORM(COCOA)
+ bool hasBadOptions = false;
+ for (char** envp = *_NSGetEnviron(); *envp; envp++) {
+ const char* env = *envp;
+ if (!strncmp("JSC_", env, 4)) {
+ if (!Options::setOption(&env[4])) {
+ dataLog("ERROR: invalid option: ", *envp, "\n");
+ hasBadOptions = true;
+ }
+ }
+ }
+ if (hasBadOptions && Options::validateOptions())
+ CRASH();
+#else // PLATFORM(COCOA)
+#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \
+ overrideOptionWithHeuristic(name_(), "JSC_" #name_);
+ JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+#endif // PLATFORM(COCOA)
+
+#define FOR_EACH_OPTION(aliasedName_, unaliasedName_, equivalence_) \
+ overrideAliasedOptionWithHeuristic("JSC_" #aliasedName_);
+ JSC_ALIASED_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+
+#if 0
+ ; // Deconfuse editors that do auto indentation
+#endif
+
+ recomputeDependentOptions();
+
+#if USE(OPTIONS_FILE)
+ {
+ const char* filename = OPTIONS_FILENAME;
+ FILE* optionsFile = fopen(filename, "r");
+ if (!optionsFile) {
+ dataLogF("Failed to open file %s. Did you add the file-read-data entitlement to WebProcess.sb?\n", filename);
+ return;
+ }
+
+ StringBuilder builder;
+ char* line;
+ char buffer[BUFSIZ];
+ while ((line = fgets(buffer, sizeof(buffer), optionsFile)))
+ builder.append(buffer);
+
+ const char* optionsStr = builder.toString().utf8().data();
+ dataLogF("Setting options: %s\n", optionsStr);
+ setOptions(optionsStr);
+
+ int result = fclose(optionsFile);
+ if (result)
+ dataLogF("Failed to close file %s: %s\n", filename, strerror(errno));
+ }
+#endif
+
+ // Do range checks where needed and make corrections to the options:
+ ASSERT(Options::thresholdForOptimizeAfterLongWarmUp() >= Options::thresholdForOptimizeAfterWarmUp());
+ ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= Options::thresholdForOptimizeSoon());
+ ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= 0);
- ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << reoptimizationRetryCounterMax()) > 0);
- ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << reoptimizationRetryCounterMax()) <= static_cast<int64_t>(std::numeric_limits<int32>::max()));
+ dumpOptionsIfNeeded();
+ ensureOptionsAreCoherent();
+ });
+}
+
+void Options::dumpOptionsIfNeeded()
+{
+ if (Options::dumpOptions()) {
+ DumpLevel level = static_cast<DumpLevel>(Options::dumpOptions());
+ if (level > DumpLevel::Verbose)
+ level = DumpLevel::Verbose;
+
+ const char* title = nullptr;
+ switch (level) {
+ case DumpLevel::None:
+ break;
+ case DumpLevel::Overridden:
+ title = "Overridden JSC options:";
+ break;
+ case DumpLevel::All:
+ title = "All JSC options:";
+ break;
+ case DumpLevel::Verbose:
+ title = "All JSC options with descriptions:";
+ break;
+ }
+
+ StringBuilder builder;
+ dumpAllOptions(builder, level, title, nullptr, " ", "\n", DumpDefaults);
+ dataLog(builder.toString());
+ }
+}
+
+bool Options::setOptions(const char* optionsStr)
+{
+ Vector<char*> options;
+
+ size_t length = strlen(optionsStr);
+ char* optionsStrCopy = WTF::fastStrDup(optionsStr);
+ char* end = optionsStrCopy + length;
+ char* p = optionsStrCopy;
+
+ while (p < end) {
+ // Skip white space.
+ while (p < end && isASCIISpace(*p))
+ p++;
+ if (p == end)
+ break;
+
+ char* optionStart = p;
+ p = strstr(p, "=");
+ if (!p) {
+ dataLogF("'=' not found in option string: %p\n", optionStart);
+ return false;
+ }
+ p++;
+
+ char* valueBegin = p;
+ bool hasStringValue = false;
+ const int minStringLength = 2; // The min is an empty string i.e. 2 double quotes.
+ if ((p + minStringLength < end) && (*p == '"')) {
+ p = strstr(p + 1, "\"");
+ if (!p) {
+ dataLogF("Missing trailing '\"' in option string: %p\n", optionStart);
+ return false; // End of string not found.
+ }
+ hasStringValue = true;
+ }
+
+ // Find next white space.
+ while (p < end && !isASCIISpace(*p))
+ p++;
+ if (!p)
+ p = end; // No more " " separator. Hence, this is the last arg.
+
+ // If we have a well-formed string value, strip the quotes.
+ if (hasStringValue) {
+ char* valueEnd = p;
+ ASSERT((*valueBegin == '"') && ((valueEnd - valueBegin) >= minStringLength) && (valueEnd[-1] == '"'));
+ memmove(valueBegin, valueBegin + 1, valueEnd - valueBegin - minStringLength);
+ valueEnd[-minStringLength] = '\0';
+ }
+
+ // Strip leading -- if present.
+ if ((p - optionStart > 2) && optionStart[0] == '-' && optionStart[1] == '-')
+ optionStart += 2;
+
+ *p++ = '\0';
+ options.append(optionStart);
+ }
+
+ bool success = true;
+ for (auto& option : options) {
+ bool optionSuccess = setOption(option);
+ if (!optionSuccess) {
+ dataLogF("Failed to set option : %s\n", option);
+ success = false;
+ }
+ }
+
+ dumpOptionsIfNeeded();
+ return success;
}
// Parses a single command line option in the format "<optionName>=<value>"
// (no spaces allowed) and set the specified option if appropriate.
-bool Options::setOption(const char* arg)
+bool Options::setOptionWithoutAlias(const char* arg)
{
// arg should look like this:
// <jscOptionName>=<appropriate value>
@@ -244,55 +549,215 @@ bool Options::setOption(const char* arg)
// For each option, check if the specify arg is a match. If so, set the arg
// if the value makes sense. Otherwise, move on to checking the next option.
-#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
- if (!strncmp(arg, #name_, equalStr - arg)) { \
- type_ value; \
- value = 0; \
- bool success = parse(valueStr, value); \
- if (success) { \
- name_() = value; \
- return true; \
- } \
- return false; \
+#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \
+ if (strlen(#name_) == static_cast<size_t>(equalStr - arg) \
+ && !strncmp(arg, #name_, equalStr - arg)) { \
+ type_ value; \
+ value = (defaultValue_); \
+ bool success = parse(valueStr, value); \
+ if (success) { \
+ name_() = value; \
+ recomputeDependentOptions(); \
+ return true; \
+ } \
+ return false; \
}
JSC_OPTIONS(FOR_EACH_OPTION)
#undef FOR_EACH_OPTION
- return false; // No option matched.
+ return false; // No option matched.
+}
+
+static bool invertBoolOptionValue(const char* valueStr, const char*& invertedValueStr)
+{
+ bool boolValue;
+ if (!parse(valueStr, boolValue))
+ return false;
+ invertedValueStr = boolValue ? "false" : "true";
+ return true;
}
-void Options::dumpAllOptions(FILE* stream)
+
+bool Options::setAliasedOption(const char* arg)
{
- fprintf(stream, "JSC runtime options:\n");
- for (int id = 0; id < numberOfOptions; id++)
- dumpOption(static_cast<OptionID>(id), stream, " ", "\n");
+ // arg should look like this:
+ // <jscOptionName>=<appropriate value>
+ const char* equalStr = strchr(arg, '=');
+ if (!equalStr)
+ return false;
+
+#if COMPILER(CLANG)
+#if __has_warning("-Wtautological-compare")
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wtautological-compare"
+#endif
+#endif
+
+ // For each option, check if the specify arg is a match. If so, set the arg
+ // if the value makes sense. Otherwise, move on to checking the next option.
+#define FOR_EACH_OPTION(aliasedName_, unaliasedName_, equivalence) \
+ if (strlen(#aliasedName_) == static_cast<size_t>(equalStr - arg) \
+ && !strncmp(arg, #aliasedName_, equalStr - arg)) { \
+ String unaliasedOption(#unaliasedName_); \
+ if (equivalence == SameOption) \
+ unaliasedOption = unaliasedOption + equalStr; \
+ else { \
+ ASSERT(equivalence == InvertedOption); \
+ const char* invertedValueStr = nullptr; \
+ if (!invertBoolOptionValue(equalStr + 1, invertedValueStr)) \
+ return false; \
+ unaliasedOption = unaliasedOption + "=" + invertedValueStr; \
+ } \
+ return setOptionWithoutAlias(unaliasedOption.utf8().data()); \
+ }
+
+ JSC_ALIASED_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+
+#if COMPILER(CLANG)
+#if __has_warning("-Wtautological-compare")
+#pragma clang diagnostic pop
+#endif
+#endif
+
+ return false; // No option matched.
}
-void Options::dumpOption(OptionID id, FILE* stream, const char* header, const char* footer)
+bool Options::setOption(const char* arg)
+{
+ bool success = setOptionWithoutAlias(arg);
+ if (success)
+ return true;
+ return setAliasedOption(arg);
+}
+
+
+void Options::dumpAllOptions(StringBuilder& builder, DumpLevel level, const char* title,
+ const char* separator, const char* optionHeader, const char* optionFooter, DumpDefaultsOption dumpDefaultsOption)
+{
+ if (title) {
+ builder.append(title);
+ builder.append('\n');
+ }
+
+ for (int id = 0; id < numberOfOptions; id++) {
+ if (separator && id)
+ builder.append(separator);
+ dumpOption(builder, level, static_cast<OptionID>(id), optionHeader, optionFooter, dumpDefaultsOption);
+ }
+}
+
+void Options::dumpAllOptionsInALine(StringBuilder& builder)
+{
+ dumpAllOptions(builder, DumpLevel::All, nullptr, " ", nullptr, nullptr, DontDumpDefaults);
+}
+
+void Options::dumpAllOptions(FILE* stream, DumpLevel level, const char* title)
+{
+ StringBuilder builder;
+ dumpAllOptions(builder, level, title, nullptr, " ", "\n", DumpDefaults);
+ fprintf(stream, "%s", builder.toString().utf8().data());
+}
+
+void Options::dumpOption(StringBuilder& builder, DumpLevel level, OptionID id,
+ const char* header, const char* footer, DumpDefaultsOption dumpDefaultsOption)
{
if (id >= numberOfOptions)
return; // Illegal option.
- fprintf(stream, "%s%s: ", header, s_optionsInfo[id].name);
- switch (s_optionsInfo[id].type) {
- case boolType:
- fprintf(stream, "%s", s_options[id].u.boolVal?"true":"false");
+ Option option(id);
+ bool wasOverridden = option.isOverridden();
+ bool needsDescription = (level == DumpLevel::Verbose && option.description());
+
+ if (level == DumpLevel::Overridden && !wasOverridden)
+ return;
+
+ if (header)
+ builder.append(header);
+ builder.append(option.name());
+ builder.append('=');
+ option.dump(builder);
+
+ if (wasOverridden && (dumpDefaultsOption == DumpDefaults)) {
+ builder.append(" (default: ");
+ option.defaultOption().dump(builder);
+ builder.append(")");
+ }
+
+ if (needsDescription) {
+ builder.append(" ... ");
+ builder.append(option.description());
+ }
+
+ builder.append(footer);
+}
+
+void Options::ensureOptionsAreCoherent()
+{
+ bool coherent = true;
+ if (!(useLLInt() || useJIT())) {
+ coherent = false;
+ dataLog("INCOHERENT OPTIONS: at least one of useLLInt or useJIT must be true\n");
+ }
+ if (!coherent)
+ CRASH();
+}
+
+void Option::dump(StringBuilder& builder) const
+{
+ switch (type()) {
+ case Options::Type::boolType:
+ builder.append(m_entry.boolVal ? "true" : "false");
+ break;
+ case Options::Type::unsignedType:
+ builder.appendNumber(m_entry.unsignedVal);
break;
- case unsignedType:
- fprintf(stream, "%u", s_options[id].u.unsignedVal);
+ case Options::Type::doubleType:
+ builder.appendNumber(m_entry.doubleVal);
break;
- case doubleType:
- fprintf(stream, "%lf", s_options[id].u.doubleVal);
+ case Options::Type::int32Type:
+ builder.appendNumber(m_entry.int32Val);
break;
- case int32Type:
- fprintf(stream, "%d", s_options[id].u.int32Val);
+ case Options::Type::optionRangeType:
+ builder.append(m_entry.optionRangeVal.rangeString());
break;
- case optionRangeType:
- fprintf(stream, "%s", s_options[id].u.optionRangeVal.rangeString());
+ case Options::Type::optionStringType: {
+ const char* option = m_entry.optionStringVal;
+ if (!option)
+ option = "";
+ builder.append('"');
+ builder.append(option);
+ builder.append('"');
break;
}
- fprintf(stream, "%s", footer);
+ case Options::Type::gcLogLevelType: {
+ builder.append(GCLogging::levelAsString(m_entry.gcLogLevelVal));
+ break;
+ }
+ }
+}
+
+bool Option::operator==(const Option& other) const
+{
+ switch (type()) {
+ case Options::Type::boolType:
+ return m_entry.boolVal == other.m_entry.boolVal;
+ case Options::Type::unsignedType:
+ return m_entry.unsignedVal == other.m_entry.unsignedVal;
+ case Options::Type::doubleType:
+ return (m_entry.doubleVal == other.m_entry.doubleVal) || (std::isnan(m_entry.doubleVal) && std::isnan(other.m_entry.doubleVal));
+ case Options::Type::int32Type:
+ return m_entry.int32Val == other.m_entry.int32Val;
+ case Options::Type::optionRangeType:
+ return m_entry.optionRangeVal.rangeString() == other.m_entry.optionRangeVal.rangeString();
+ case Options::Type::optionStringType:
+ return (m_entry.optionStringVal == other.m_entry.optionStringVal)
+ || (m_entry.optionStringVal && other.m_entry.optionStringVal && !strcmp(m_entry.optionStringVal, other.m_entry.optionStringVal));
+ case Options::Type::gcLogLevelType:
+ return m_entry.gcLogLevelVal == other.m_entry.gcLogLevelVal;
+ }
+ return false;
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h
index c88b3ac6c..1bd19bbd1 100644
--- a/Source/JavaScriptCore/runtime/Options.h
+++ b/Source/JavaScriptCore/runtime/Options.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-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,9 +26,17 @@
#ifndef Options_h
#define Options_h
+#include "GCLogging.h"
#include "JSExportMacros.h"
#include <stdint.h>
#include <stdio.h>
+#include <wtf/PrintStream.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WTF {
+class StringBuilder;
+}
+using WTF::StringBuilder;
namespace JSC {
@@ -77,9 +85,13 @@ public:
bool init(const char*);
bool isInRange(unsigned);
- const char* rangeString() { return (m_state > InitError) ? m_rangeString : "<null>"; }
+ const char* rangeString() const { return (m_state > InitError) ? m_rangeString : s_nullRangeStr; }
+
+ void dump(PrintStream& out) const;
private:
+ static const char* const s_nullRangeStr;
+
RangeState m_state;
const char* m_rangeString;
unsigned m_lowLimit;
@@ -87,203 +99,491 @@ private:
};
typedef OptionRange optionRange;
+typedef const char* optionString;
#define JSC_OPTIONS(v) \
- v(bool, useLLInt, true) \
- v(bool, useJIT, true) \
- v(bool, useDFGJIT, true) \
- v(bool, useRegExpJIT, true) \
- \
- v(bool, crashIfCantAllocateJITMemory, false) \
- \
- v(bool, forceDFGCodeBlockLiveness, false) \
- \
- v(bool, dumpGeneratedBytecodes, false) \
- v(bool, dumpBytecodeLivenessResults, false) \
- v(bool, validateBytecode, false) \
- \
- /* showDisassembly implies showDFGDisassembly. */ \
- v(bool, showDisassembly, false) \
- v(bool, showDFGDisassembly, false) \
- v(bool, showAllDFGNodes, false) \
- v(optionRange, bytecodeRangeToDFGCompile, 0) \
- v(bool, dumpBytecodeAtDFGTime, false) \
- v(bool, dumpGraphAtEachPhase, false) \
- v(bool, verboseCompilation, false) \
- v(bool, logCompilationChanges, false) \
- v(bool, printEachOSRExit, false) \
- v(bool, validateGraph, false) \
- v(bool, validateGraphAtEachPhase, false) \
- v(bool, verboseOSR, false) \
- v(bool, verboseCallLink, false) \
- v(bool, verboseCompilationQueue, false) \
- v(bool, reportCompileTimes, false) \
- v(bool, verboseCFA, false) \
- \
- v(bool, enableOSREntryInLoops, true) \
- \
- v(bool, useExperimentalFTL, false) \
- v(bool, useFTLTBAA, true) \
- v(bool, enableLLVMFastISel, false) \
- v(bool, useLLVMSmallCodeModel, false) \
- v(bool, dumpLLVMIR, false) \
- v(bool, validateFTLOSRExitLiveness, false) \
- v(bool, llvmAlwaysFailsBeforeCompile, false) \
- v(bool, llvmAlwaysFailsBeforeLink, false) \
- v(bool, llvmSimpleOpt, true) \
- v(unsigned, llvmBackendOptimizationLevel, 2) \
- v(unsigned, llvmOptimizationLevel, 2) \
- v(unsigned, llvmSizeLevel, 0) \
- v(bool, ftlCrashes, false) /* fool-proof way of checking that you ended up in the FTL. ;-) */\
- \
- v(bool, enableConcurrentJIT, true) \
- v(unsigned, numberOfCompilerThreads, computeNumberOfWorkerThreads(2) - 1) \
- \
- v(bool, enableProfiler, false) \
- \
- v(bool, forceUDis86Disassembler, false) \
- v(bool, forceLLVMDisassembler, false) \
- \
- v(bool, enableArchitectureSpecificOptimizations, true) \
- \
- v(unsigned, maximumOptimizationCandidateInstructionCount, 10000) \
- \
- v(unsigned, maximumFunctionForCallInlineCandidateInstructionCount, 180) \
- v(unsigned, maximumFunctionForClosureCallInlineCandidateInstructionCount, 100) \
- v(unsigned, maximumFunctionForConstructInlineCandidateInstructionCount, 100) \
+ v(bool, validateOptions, false, "crashes if mis-typed JSC options were passed to the VM") \
+ v(unsigned, dumpOptions, 0, "dumps JSC options (0 = None, 1 = Overridden only, 2 = All, 3 = Verbose)") \
+ \
+ v(bool, useLLInt, true, "allows the LLINT to be used if true") \
+ v(bool, useJIT, true, "allows the baseline JIT to be used if true") \
+ v(bool, useDFGJIT, true, "allows the DFG JIT to be used if true") \
+ v(bool, useRegExpJIT, true, "allows the RegExp JIT to be used if true") \
+ \
+ v(bool, reportMustSucceedExecutableAllocations, false, nullptr) \
+ \
+ v(unsigned, maxPerThreadStackUsage, 4 * MB, nullptr) \
+ v(unsigned, reservedZoneSize, 128 * KB, nullptr) \
+ v(unsigned, errorModeReservedZoneSize, 64 * KB, nullptr) \
+ \
+ v(bool, crashIfCantAllocateJITMemory, false, nullptr) \
+ v(unsigned, jitMemoryReservationSize, 0, "Set this number to change the executable allocation size in ExecutableAllocatorFixedVMPool. (In bytes.)") \
+ \
+ v(bool, forceCodeBlockLiveness, false, nullptr) \
+ v(bool, forceICFailure, false, nullptr) \
+ \
+ v(unsigned, repatchCountForCoolDown, 10, nullptr) \
+ v(unsigned, initialCoolDownCount, 20, nullptr) \
+ \
+ v(bool, dumpGeneratedBytecodes, false, nullptr) \
+ v(bool, dumpBytecodeLivenessResults, false, nullptr) \
+ v(bool, validateBytecode, false, nullptr) \
+ v(bool, forceDebuggerBytecodeGeneration, false, nullptr) \
+ v(bool, forceProfilerBytecodeGeneration, false, nullptr) \
+ \
+ v(bool, useFunctionDotArguments, true, nullptr) \
+ v(bool, useTailCalls, true, nullptr) \
+ \
+ /* dumpDisassembly implies dumpDFGDisassembly. */ \
+ v(bool, dumpDisassembly, false, "dumps disassembly of all JIT compiled code upon compilation") \
+ v(bool, asyncDisassembly, false, nullptr) \
+ v(bool, dumpDFGDisassembly, false, "dumps disassembly of DFG function upon compilation") \
+ v(bool, dumpFTLDisassembly, false, "dumps disassembly of FTL function upon compilation") \
+ v(bool, dumpAllDFGNodes, false, nullptr) \
+ v(optionRange, bytecodeRangeToDFGCompile, 0, "bytecode size range to allow DFG compilation on, e.g. 1:100") \
+ v(optionRange, bytecodeRangeToFTLCompile, 0, "bytecode size range to allow FTL compilation on, e.g. 1:100") \
+ v(optionString, dfgWhitelist, nullptr, "file with list of function signatures to allow DFG compilation on") \
+ v(bool, dumpSourceAtDFGTime, false, "dumps source code of JS function being DFG compiled") \
+ v(bool, dumpBytecodeAtDFGTime, false, "dumps bytecode of JS function being DFG compiled") \
+ v(bool, dumpGraphAfterParsing, false, nullptr) \
+ v(bool, dumpGraphAtEachPhase, false, nullptr) \
+ v(bool, dumpDFGGraphAtEachPhase, false, "dumps the DFG graph at each phase DFG of complitaion (note this excludes DFG graphs during FTL compilation)") \
+ v(bool, dumpDFGFTLGraphAtEachPhase, false, "dumps the DFG graph at each phase DFG of complitaion when compiling FTL code") \
+ v(bool, dumpB3GraphAtEachPhase, false, "dumps the B3 graph at each phase of compilation") \
+ v(bool, dumpAirGraphAtEachPhase, false, "dumps the Air graph at each phase of compilation") \
+ v(bool, verboseDFGByteCodeParsing, false, nullptr) \
+ v(bool, verboseCompilation, false, nullptr) \
+ v(bool, verboseFTLCompilation, false, nullptr) \
+ v(bool, logCompilationChanges, false, nullptr) \
+ v(bool, printEachOSRExit, false, nullptr) \
+ v(bool, validateGraph, false, nullptr) \
+ v(bool, validateGraphAtEachPhase, false, nullptr) \
+ v(bool, verboseValidationFailure, false, nullptr) \
+ v(bool, verboseOSR, false, nullptr) \
+ v(bool, verboseFTLOSRExit, false, nullptr) \
+ v(bool, verboseCallLink, false, nullptr) \
+ v(bool, verboseCompilationQueue, false, nullptr) \
+ v(bool, reportCompileTimes, false, "dumps JS function signature and the time it took to compile") \
+ v(bool, reportFTLCompileTimes, false, "dumps JS function signature and the time it took to FTL compile") \
+ v(bool, reportTotalCompileTimes, false, nullptr) \
+ v(bool, verboseCFA, false, nullptr) \
+ v(bool, verboseFTLToJSThunk, false, nullptr) \
+ v(bool, verboseFTLFailure, false, nullptr) \
+ v(bool, alwaysComputeHash, false, nullptr) \
+ v(bool, testTheFTL, false, nullptr) \
+ v(bool, verboseSanitizeStack, false, nullptr) \
+ v(bool, useGenerationalGC, true, nullptr) \
+ v(bool, eagerlyUpdateTopCallFrame, false, nullptr) \
+ \
+ v(bool, useOSREntryToDFG, true, nullptr) \
+ v(bool, useOSREntryToFTL, true, nullptr) \
+ \
+ v(bool, useFTLJIT, true, "allows the FTL JIT to be used if true") \
+ v(bool, useFTLTBAA, true, nullptr) \
+ v(bool, validateFTLOSRExitLiveness, false, nullptr) \
+ v(bool, b3AlwaysFailsBeforeCompile, false, nullptr) \
+ v(bool, b3AlwaysFailsBeforeLink, false, nullptr) \
+ v(bool, ftlCrashes, false, nullptr) /* fool-proof way of checking that you ended up in the FTL. ;-) */\
+ v(bool, clobberAllRegsInFTLICSlowPath, !ASSERT_DISABLED, nullptr) \
+ v(bool, useAccessInlining, true, nullptr) \
+ v(unsigned, maxAccessVariantListSize, 8, nullptr) \
+ v(bool, usePolyvariantDevirtualization, true, nullptr) \
+ v(bool, usePolymorphicAccessInlining, true, nullptr) \
+ v(bool, usePolymorphicCallInlining, true, nullptr) \
+ v(unsigned, maxPolymorphicCallVariantListSize, 15, nullptr) \
+ v(unsigned, maxPolymorphicCallVariantListSizeForTopTier, 5, nullptr) \
+ v(unsigned, maxPolymorphicCallVariantsForInlining, 5, nullptr) \
+ v(unsigned, frequentCallThreshold, 2, nullptr) \
+ v(double, minimumCallToKnownRate, 0.51, nullptr) \
+ v(bool, createPreHeaders, true, nullptr) \
+ v(bool, useMovHintRemoval, true, nullptr) \
+ v(bool, usePutStackSinking, true, nullptr) \
+ v(bool, useObjectAllocationSinking, true, nullptr) \
+ v(bool, useCopyBarrierOptimization, true, nullptr) \
+ \
+ v(bool, useConcurrentJIT, true, "allows the DFG / FTL compilation in threads other than the executing JS thread") \
+ v(unsigned, numberOfDFGCompilerThreads, computeNumberOfWorkerThreads(2, 2) - 1, nullptr) \
+ v(unsigned, numberOfFTLCompilerThreads, computeNumberOfWorkerThreads(8, 2) - 1, nullptr) \
+ v(int32, priorityDeltaOfDFGCompilerThreads, computePriorityDeltaOfWorkerThreads(-1, 0), nullptr) \
+ v(int32, priorityDeltaOfFTLCompilerThreads, computePriorityDeltaOfWorkerThreads(-2, 0), nullptr) \
+ \
+ v(bool, useProfiler, false, nullptr) \
+ \
+ v(bool, useArchitectureSpecificOptimizations, true, nullptr) \
+ \
+ v(bool, breakOnThrow, false, nullptr) \
+ \
+ v(unsigned, maximumOptimizationCandidateInstructionCount, 100000, nullptr) \
+ \
+ v(unsigned, maximumFunctionForCallInlineCandidateInstructionCount, 180, nullptr) \
+ v(unsigned, maximumFunctionForClosureCallInlineCandidateInstructionCount, 100, nullptr) \
+ v(unsigned, maximumFunctionForConstructInlineCandidateInstructionCount, 100, nullptr) \
+ \
+ v(unsigned, maximumFTLCandidateInstructionCount, 20000, nullptr) \
\
/* Depth of inline stack, so 1 = no inlining, 2 = one level, etc. */ \
- v(unsigned, maximumInliningDepth, 5) \
+ v(unsigned, maximumInliningDepth, 5, "maximum allowed inlining depth. Depth of 1 means no inlining") \
+ v(unsigned, maximumInliningRecursion, 2, nullptr) \
\
- v(unsigned, maximumBinaryStringSwitchCaseLength, 50) \
- v(unsigned, maximumBinaryStringSwitchTotalLength, 2000) \
+ /* Maximum size of a caller for enabling inlining. This is purely to protect us */\
+ /* from super long compiles that take a lot of memory. */\
+ v(unsigned, maximumInliningCallerSize, 10000, nullptr) \
\
- v(int32, thresholdForJITAfterWarmUp, 100) \
- v(int32, thresholdForJITSoon, 100) \
+ v(unsigned, maximumVarargsForInlining, 100, nullptr) \
\
- v(int32, thresholdForOptimizeAfterWarmUp, 1000) \
- v(int32, thresholdForOptimizeAfterLongWarmUp, 1000) \
- v(int32, thresholdForOptimizeSoon, 1000) \
- v(int32, executionCounterIncrementForLoop, 1) \
- v(int32, executionCounterIncrementForEntry, 15) \
+ v(bool, usePolyvariantCallInlining, true, nullptr) \
+ v(bool, usePolyvariantByIdInlining, true, nullptr) \
\
- v(int32, thresholdForFTLOptimizeAfterWarmUp, 25000) \
- v(int32, thresholdForFTLOptimizeSoon, 1000) \
- v(int32, ftlTierUpCounterIncrementForLoop, 1) \
- v(int32, ftlTierUpCounterIncrementForReturn, 15) \
- v(unsigned, ftlOSREntryFailureCountForReoptimization, 15) \
+ v(bool, useMaximalFlushInsertionPhase, false, "Setting to true allows the DFG's MaximalFlushInsertionPhase to run.") \
\
- v(int32, evalThresholdMultiplier, 10) \
+ v(unsigned, maximumBinaryStringSwitchCaseLength, 50, nullptr) \
+ v(unsigned, maximumBinaryStringSwitchTotalLength, 2000, nullptr) \
\
- v(bool, randomizeExecutionCountsBetweenCheckpoints, false) \
- v(int32, maximumExecutionCountsBetweenCheckpoints, 1000) \
+ v(double, jitPolicyScale, 1.0, "scale JIT thresholds to this specified ratio between 0.0 (compile ASAP) and 1.0 (compile like normal).") \
+ v(bool, forceEagerCompilation, false, nullptr) \
+ v(int32, thresholdForJITAfterWarmUp, 500, nullptr) \
+ v(int32, thresholdForJITSoon, 100, nullptr) \
\
- v(unsigned, likelyToTakeSlowCaseMinimumCount, 100) \
- v(unsigned, couldTakeSlowCaseMinimumCount, 10) \
+ v(int32, thresholdForOptimizeAfterWarmUp, 1000, nullptr) \
+ v(int32, thresholdForOptimizeAfterLongWarmUp, 1000, nullptr) \
+ v(int32, thresholdForOptimizeSoon, 1000, nullptr) \
+ v(int32, executionCounterIncrementForLoop, 1, nullptr) \
+ v(int32, executionCounterIncrementForEntry, 15, nullptr) \
\
- v(unsigned, osrExitCountForReoptimization, 100) \
- v(unsigned, osrExitCountForReoptimizationFromLoop, 5) \
+ v(int32, thresholdForFTLOptimizeAfterWarmUp, 100000, nullptr) \
+ v(int32, thresholdForFTLOptimizeSoon, 1000, nullptr) \
+ v(int32, ftlTierUpCounterIncrementForLoop, 1, nullptr) \
+ v(int32, ftlTierUpCounterIncrementForReturn, 15, nullptr) \
+ v(unsigned, ftlOSREntryFailureCountForReoptimization, 15, nullptr) \
+ v(unsigned, ftlOSREntryRetryThreshold, 100, nullptr) \
\
- v(unsigned, reoptimizationRetryCounterMax, 0) \
- v(unsigned, reoptimizationRetryCounterStep, 1) \
+ v(int32, evalThresholdMultiplier, 10, nullptr) \
+ v(unsigned, maximumEvalCacheableSourceLength, 256, nullptr) \
\
- v(unsigned, minimumOptimizationDelay, 1) \
- v(unsigned, maximumOptimizationDelay, 5) \
- v(double, desiredProfileLivenessRate, 0.75) \
- v(double, desiredProfileFullnessRate, 0.35) \
+ v(bool, randomizeExecutionCountsBetweenCheckpoints, false, nullptr) \
+ v(int32, maximumExecutionCountsBetweenCheckpointsForBaseline, 1000, nullptr) \
+ v(int32, maximumExecutionCountsBetweenCheckpointsForUpperTiers, 50000, nullptr) \
\
- v(double, doubleVoteRatioForDoubleFormat, 2) \
- v(double, structureCheckVoteRatioForHoisting, 1) \
- v(double, checkArrayVoteRatioForHoisting, 1) \
+ v(unsigned, likelyToTakeSlowCaseMinimumCount, 20, nullptr) \
+ v(unsigned, couldTakeSlowCaseMinimumCount, 10, nullptr) \
\
- v(unsigned, minimumNumberOfScansBetweenRebalance, 100) \
- v(unsigned, numberOfGCMarkers, computeNumberOfGCMarkers(7)) \
- v(unsigned, opaqueRootMergeThreshold, 1000) \
- v(double, minHeapUtilization, 0.8) \
- v(double, minCopiedBlockUtilization, 0.9) \
+ v(unsigned, osrExitCountForReoptimization, 100, nullptr) \
+ v(unsigned, osrExitCountForReoptimizationFromLoop, 5, nullptr) \
\
- v(bool, forceWeakRandomSeed, false) \
- v(unsigned, forcedWeakRandomSeed, 0) \
+ v(unsigned, reoptimizationRetryCounterMax, 0, nullptr) \
\
- v(bool, useZombieMode, false) \
- v(bool, objectsAreImmortal, false) \
- v(bool, showObjectStatistics, false) \
+ v(bool, assertICSizing, false, "crash if estimated IC sizes are inadequate") \
+ v(bool, dumpFailedICSizing, false, "dumps a log entry if estimated IC sizes are inadequate") \
\
- v(bool, logGC, false) \
- v(unsigned, gcMaxHeapSize, 0) \
- v(bool, recordGCPauseTimes, false) \
- v(bool, logHeapStatisticsAtExit, false)
+ v(unsigned, minimumOptimizationDelay, 1, nullptr) \
+ v(unsigned, maximumOptimizationDelay, 5, nullptr) \
+ v(double, desiredProfileLivenessRate, 0.75, nullptr) \
+ v(double, desiredProfileFullnessRate, 0.35, nullptr) \
+ \
+ v(double, doubleVoteRatioForDoubleFormat, 2, nullptr) \
+ v(double, structureCheckVoteRatioForHoisting, 1, nullptr) \
+ v(double, checkArrayVoteRatioForHoisting, 1, nullptr) \
+ \
+ v(unsigned, minimumNumberOfScansBetweenRebalance, 100, nullptr) \
+ v(unsigned, numberOfGCMarkers, computeNumberOfGCMarkers(7), nullptr) \
+ v(unsigned, opaqueRootMergeThreshold, 1000, nullptr) \
+ v(double, minHeapUtilization, 0.8, nullptr) \
+ v(double, minCopiedBlockUtilization, 0.9, nullptr) \
+ v(double, minMarkedBlockUtilization, 0.9, nullptr) \
+ v(unsigned, slowPathAllocsBetweenGCs, 0, "force a GC on every Nth slow path alloc, where N is specified by this option") \
+ \
+ v(double, percentCPUPerMBForFullTimer, 0.0003125, nullptr) \
+ v(double, percentCPUPerMBForEdenTimer, 0.0025, nullptr) \
+ v(double, collectionTimerMaxPercentCPU, 0.05, nullptr) \
+ \
+ v(bool, forceWeakRandomSeed, false, nullptr) \
+ v(unsigned, forcedWeakRandomSeed, 0, nullptr) \
+ \
+ v(bool, useZombieMode, false, "debugging option to scribble over dead objects with 0xdeadbeef") \
+ v(bool, useImmortalObjects, false, "debugging option to keep all objects alive forever") \
+ v(bool, dumpObjectStatistics, false, nullptr) \
+ \
+ v(gcLogLevel, logGC, GCLogging::None, "debugging option to log GC activity (0 = None, 1 = Basic, 2 = Verbose)") \
+ v(bool, useGC, true, nullptr) \
+ v(bool, gcAtEnd, false, "If true, the jsc CLI will do a GC before exiting") \
+ v(bool, forceGCSlowPaths, false, "If true, we will force all JIT fast allocations down their slow paths.")\
+ v(unsigned, gcMaxHeapSize, 0, nullptr) \
+ v(unsigned, forceRAMSize, 0, nullptr) \
+ v(bool, recordGCPauseTimes, false, nullptr) \
+ v(bool, logHeapStatisticsAtExit, false, nullptr) \
+ v(bool, useTypeProfiler, false, nullptr) \
+ v(bool, useControlFlowProfiler, false, nullptr) \
+ v(bool, useSamplingProfiler, false, nullptr) \
+ v(bool, alwaysGeneratePCToCodeOriginMap, false, "This will make sure we always generate a PCToCodeOriginMap for JITed code.") \
+ \
+ v(bool, verifyHeap, false, nullptr) \
+ v(unsigned, numberOfGCCyclesToRecordForVerification, 3, nullptr) \
+ \
+ v(bool, useExceptionFuzz, false, nullptr) \
+ v(unsigned, fireExceptionFuzzAt, 0, nullptr) \
+ v(bool, validateDFGExceptionHandling, false, "Causes the DFG to emit code validating exception handling for each node that can exit") /* This is true by default on Debug builds */\
+ \
+ v(bool, useExecutableAllocationFuzz, false, nullptr) \
+ v(unsigned, fireExecutableAllocationFuzzAt, 0, nullptr) \
+ v(unsigned, fireExecutableAllocationFuzzAtOrAfter, 0, nullptr) \
+ v(bool, verboseExecutableAllocationFuzz, false, nullptr) \
+ \
+ v(bool, useOSRExitFuzz, false, nullptr) \
+ v(unsigned, fireOSRExitFuzzAtStatic, 0, nullptr) \
+ v(unsigned, fireOSRExitFuzzAt, 0, nullptr) \
+ v(unsigned, fireOSRExitFuzzAtOrAfter, 0, nullptr) \
+ \
+ v(bool, logB3PhaseTimes, false, nullptr) \
+ v(double, rareBlockPenalty, 0.001, nullptr) \
+ v(bool, airSpillsEverything, false, nullptr) \
+ v(bool, logAirRegisterPressure, false, nullptr) \
+ v(unsigned, maxB3TailDupBlockSize, 3, nullptr) \
+ v(unsigned, maxB3TailDupBlockSuccessors, 3, nullptr) \
+ \
+ v(bool, useDollarVM, false, "installs the $vm debugging tool in global objects") \
+ v(optionString, functionOverrides, nullptr, "file with debugging overrides for function bodies") \
+ \
+ v(unsigned, watchdog, 0, "watchdog timeout (0 = Disabled, N = a timeout period of N milliseconds)") \
+ \
+ v(bool, dumpModuleRecord, false, nullptr) \
+ v(bool, dumpModuleLoadingState, false, nullptr) \
+ v(bool, exposeInternalModuleLoader, false, "expose the internal module loader object to the global space for debugging") \
+
+enum OptionEquivalence {
+ SameOption,
+ InvertedOption,
+};
+
+#define JSC_ALIASED_OPTIONS(v) \
+ v(enableFunctionDotArguments, useFunctionDotArguments, SameOption) \
+ v(enableTailCalls, useTailCalls, SameOption) \
+ v(showDisassembly, dumpDisassembly, SameOption) \
+ v(showDFGDisassembly, dumpDFGDisassembly, SameOption) \
+ v(showFTLDisassembly, dumpFTLDisassembly, SameOption) \
+ v(showAllDFGNodes, dumpAllDFGNodes, SameOption) \
+ v(alwaysDoFullCollection, useGenerationalGC, InvertedOption) \
+ v(enableOSREntryToDFG, useOSREntryToDFG, SameOption) \
+ v(enableOSREntryToFTL, useOSREntryToFTL, SameOption) \
+ v(enableAccessInlining, useAccessInlining, SameOption) \
+ v(enablePolyvariantDevirtualization, usePolyvariantDevirtualization, SameOption) \
+ v(enablePolymorphicAccessInlining, usePolymorphicAccessInlining, SameOption) \
+ v(enablePolymorphicCallInlining, usePolymorphicCallInlining, SameOption) \
+ v(enableMovHintRemoval, useMovHintRemoval, SameOption) \
+ v(enableObjectAllocationSinking, useObjectAllocationSinking, SameOption) \
+ v(enableCopyBarrierOptimization, useCopyBarrierOptimization, SameOption) \
+ v(enableConcurrentJIT, useConcurrentJIT, SameOption) \
+ v(enableProfiler, useProfiler, SameOption) \
+ v(enableArchitectureSpecificOptimizations, useArchitectureSpecificOptimizations, SameOption) \
+ v(enablePolyvariantCallInlining, usePolyvariantCallInlining, SameOption) \
+ v(enablePolyvariantByIdInlining, usePolyvariantByIdInlining, SameOption) \
+ v(enableMaximalFlushInsertionPhase, useMaximalFlushInsertionPhase, SameOption) \
+ v(objectsAreImmortal, useImmortalObjects, SameOption) \
+ v(showObjectStatistics, dumpObjectStatistics, SameOption) \
+ v(disableGC, useGC, InvertedOption) \
+ v(enableTypeProfiler, useTypeProfiler, SameOption) \
+ v(enableControlFlowProfiler, useControlFlowProfiler, SameOption) \
+ v(enableExceptionFuzz, useExceptionFuzz, SameOption) \
+ v(enableExecutableAllocationFuzz, useExecutableAllocationFuzz, SameOption) \
+ v(enableOSRExitFuzz, useOSRExitFuzz, SameOption) \
+ v(enableDollarVM, useDollarVM, SameOption) \
class Options {
public:
+ enum class DumpLevel {
+ None = 0,
+ Overridden,
+ All,
+ Verbose
+ };
+
// This typedef is to allow us to eliminate the '_' in the field name in
// union inside Entry. This is needed to keep the style checker happy.
typedef int32_t int32;
// Declare the option IDs:
enum OptionID {
-#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
- OPT_##name_,
+#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \
+ name_##ID,
JSC_OPTIONS(FOR_EACH_OPTION)
#undef FOR_EACH_OPTION
numberOfOptions
};
+ enum class Type {
+ boolType,
+ unsignedType,
+ doubleType,
+ int32Type,
+ optionRangeType,
+ optionStringType,
+ gcLogLevelType,
+ };
+
+ JS_EXPORT_PRIVATE static void initialize();
- static void initialize();
+ // Parses a string of options where each option is of the format "--<optionName>=<value>"
+ // and are separated by a space. The leading "--" is optional and will be ignored.
+ JS_EXPORT_PRIVATE static bool setOptions(const char* optionsList);
// Parses a single command line option in the format "<optionName>=<value>"
// (no spaces allowed) and set the specified option if appropriate.
JS_EXPORT_PRIVATE static bool setOption(const char* arg);
- JS_EXPORT_PRIVATE static void dumpAllOptions(FILE* stream = stdout);
- static void dumpOption(OptionID id, FILE* stream = stdout, const char* header = "", const char* footer = "");
+
+ JS_EXPORT_PRIVATE static void dumpAllOptions(FILE*, DumpLevel, const char* title = nullptr);
+ JS_EXPORT_PRIVATE static void dumpAllOptionsInALine(StringBuilder&);
+
+ JS_EXPORT_PRIVATE static void ensureOptionsAreCoherent();
// Declare accessors for each option:
-#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
- ALWAYS_INLINE static type_& name_() { return s_options[OPT_##name_].u.type_##Val; }
+#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \
+ ALWAYS_INLINE static type_& name_() { return s_options[name_##ID].type_##Val; } \
+ ALWAYS_INLINE static type_& name_##Default() { return s_defaultOptions[name_##ID].type_##Val; }
JSC_OPTIONS(FOR_EACH_OPTION)
#undef FOR_EACH_OPTION
private:
- enum EntryType {
- boolType,
- unsignedType,
- doubleType,
- int32Type,
- optionRangeType,
- };
-
// For storing for an option value:
- struct Entry {
- union {
- bool boolVal;
- unsigned unsignedVal;
- double doubleVal;
- int32 int32Val;
- OptionRange optionRangeVal;
- } u;
+ union Entry {
+ bool boolVal;
+ unsigned unsignedVal;
+ double doubleVal;
+ int32 int32Val;
+ OptionRange optionRangeVal;
+ const char* optionStringVal;
+ GCLogging::Level gcLogLevelVal;
};
// For storing constant meta data about each option:
struct EntryInfo {
const char* name;
- EntryType type;
+ const char* description;
+ Type type;
};
Options();
- // Declare the options:
-#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
- type_ m_##name_;
- JSC_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
+ enum DumpDefaultsOption {
+ DontDumpDefaults,
+ DumpDefaults
+ };
+ static void dumpOptionsIfNeeded();
+ static void dumpAllOptions(StringBuilder&, DumpLevel, const char* title,
+ const char* separator, const char* optionHeader, const char* optionFooter, DumpDefaultsOption);
+ static void dumpOption(StringBuilder&, DumpLevel, OptionID,
+ const char* optionHeader, const char* optionFooter, DumpDefaultsOption);
+
+ static bool setOptionWithoutAlias(const char* arg);
+ static bool setAliasedOption(const char* arg);
+ static bool overrideAliasedOptionWithHeuristic(const char* name);
// Declare the singleton instance of the options store:
JS_EXPORTDATA static Entry s_options[numberOfOptions];
+ static Entry s_defaultOptions[numberOfOptions];
static const EntryInfo s_optionsInfo[numberOfOptions];
+
+ friend class Option;
};
+class Option {
+public:
+ Option(Options::OptionID id)
+ : m_id(id)
+ , m_entry(Options::s_options[m_id])
+ {
+ }
+
+ void dump(StringBuilder&) const;
+
+ bool operator==(const Option& other) const;
+ bool operator!=(const Option& other) const { return !(*this == other); }
+
+ const char* name() const;
+ const char* description() const;
+ Options::Type type() const;
+ bool isOverridden() const;
+ const Option defaultOption() const;
+
+ bool& boolVal();
+ unsigned& unsignedVal();
+ double& doubleVal();
+ int32_t& int32Val();
+ OptionRange optionRangeVal();
+ const char* optionStringVal();
+ GCLogging::Level& gcLogLevelVal();
+
+private:
+ // Only used for constructing default Options.
+ Option(Options::OptionID id, Options::Entry& entry)
+ : m_id(id)
+ , m_entry(entry)
+ {
+ }
+
+ Options::OptionID m_id;
+ Options::Entry& m_entry;
+};
+
+inline const char* Option::name() const
+{
+ return Options::s_optionsInfo[m_id].name;
+}
+
+inline const char* Option::description() const
+{
+ return Options::s_optionsInfo[m_id].description;
+}
+
+inline Options::Type Option::type() const
+{
+ return Options::s_optionsInfo[m_id].type;
+}
+
+inline bool Option::isOverridden() const
+{
+ return *this != defaultOption();
+}
+
+inline const Option Option::defaultOption() const
+{
+ return Option(m_id, Options::s_defaultOptions[m_id]);
+}
+
+inline bool& Option::boolVal()
+{
+ return m_entry.boolVal;
+}
+
+inline unsigned& Option::unsignedVal()
+{
+ return m_entry.unsignedVal;
+}
+
+inline double& Option::doubleVal()
+{
+ return m_entry.doubleVal;
+}
+
+inline int32_t& Option::int32Val()
+{
+ return m_entry.int32Val;
+}
+
+inline OptionRange Option::optionRangeVal()
+{
+ return m_entry.optionRangeVal;
+}
+
+inline const char* Option::optionStringVal()
+{
+ return m_entry.optionStringVal;
+}
+
+inline GCLogging::Level& Option::gcLogLevelVal()
+{
+ return m_entry.gcLogLevelVal;
+}
+
} // namespace JSC
#endif // Options_h
diff --git a/Source/JavaScriptCore/runtime/PrivateName.h b/Source/JavaScriptCore/runtime/PrivateName.h
index 5d2774a20..2b6ba017d 100644
--- a/Source/JavaScriptCore/runtime/PrivateName.h
+++ b/Source/JavaScriptCore/runtime/PrivateName.h
@@ -26,26 +26,35 @@
#ifndef PrivateName_h
#define PrivateName_h
-#include <wtf/text/StringImpl.h>
+#include <wtf/text/SymbolImpl.h>
namespace JSC {
class PrivateName {
public:
PrivateName()
- : m_impl(StringImpl::createEmptyUnique())
+ : m_uid(StringImpl::createSymbolEmpty())
{
}
- explicit PrivateName(StringImpl* uid)
- : m_impl(uid)
+
+ explicit PrivateName(SymbolImpl& uid)
+ : m_uid(&uid)
{
- ASSERT(m_impl->isEmptyUnique());
}
- StringImpl* uid() const { return m_impl.get(); }
+ enum DescriptionTag { Description };
+ explicit PrivateName(DescriptionTag, const String& description)
+ : m_uid(StringImpl::createSymbol(description.impl()))
+ {
+ }
+
+ SymbolImpl* uid() const { return m_uid.get(); }
+
+ bool operator==(const PrivateName& other) const { return uid() == other.uid(); }
+ bool operator!=(const PrivateName& other) const { return uid() != other.uid(); }
private:
- RefPtr<StringImpl> m_impl;
+ RefPtr<SymbolImpl> m_uid;
};
}
diff --git a/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp b/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp
index 1dd35605c..8e5681bc4 100644
--- a/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp
+++ b/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp
@@ -30,7 +30,7 @@
#include "GetterSetter.h"
#include "JSObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
unsigned PropertyDescriptor::defaultAttributes = DontDelete | DontEnum | ReadOnly;
@@ -106,8 +106,8 @@ void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes)
m_attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this!
GetterSetter* accessor = asGetterSetter(value);
- m_getter = accessor->getter() ? accessor->getter() : jsUndefined();
- m_setter = accessor->setter() ? accessor->setter() : jsUndefined();
+ m_getter = !accessor->isGetterNull() ? accessor->getter() : jsUndefined();
+ m_setter = !accessor->isSetterNull() ? accessor->setter() : jsUndefined();
m_seenAttributes = EnumerablePresent | ConfigurablePresent;
} else {
m_value = value;
@@ -115,14 +115,24 @@ void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes)
}
}
+void PropertyDescriptor::setCustomDescriptor(unsigned attributes)
+{
+ m_attributes = attributes | Accessor | CustomAccessor;
+ m_attributes &= ~ReadOnly;
+ m_seenAttributes = EnumerablePresent | ConfigurablePresent;
+ setGetter(jsUndefined());
+ setSetter(jsUndefined());
+ m_value = JSValue();
+}
+
void PropertyDescriptor::setAccessorDescriptor(GetterSetter* accessor, unsigned attributes)
{
ASSERT(attributes & Accessor);
attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this!
m_attributes = attributes;
- m_getter = accessor->getter() ? accessor->getter() : jsUndefined();
- m_setter = accessor->setter() ? accessor->setter() : jsUndefined();
+ m_getter = !accessor->isGetterNull() ? accessor->getter() : jsUndefined();
+ m_setter = !accessor->isSetterNull() ? accessor->setter() : jsUndefined();
m_seenAttributes = EnumerablePresent | ConfigurablePresent;
}
@@ -176,8 +186,10 @@ bool sameValue(ExecState* exec, JSValue a, JSValue b)
return false;
double x = a.asNumber();
double y = b.asNumber();
- if (std::isnan(x))
- return std::isnan(y);
+ bool xIsNaN = std::isnan(x);
+ bool yIsNaN = std::isnan(y);
+ if (xIsNaN || yIsNaN)
+ return xIsNaN && yIsNaN;
return bitwise_cast<uint64_t>(x) == bitwise_cast<uint64_t>(y);
}
@@ -220,7 +232,7 @@ unsigned PropertyDescriptor::attributesOverridingCurrent(const PropertyDescripto
overrideMask |= DontDelete;
if (isAccessorDescriptor())
overrideMask |= Accessor;
- return (m_attributes & overrideMask) | (currentAttributes & ~overrideMask);
+ return (m_attributes & overrideMask) | (currentAttributes & ~overrideMask & ~CustomAccessor);
}
}
diff --git a/Source/JavaScriptCore/runtime/PropertyDescriptor.h b/Source/JavaScriptCore/runtime/PropertyDescriptor.h
index 2cc95fb21..0345b4e4a 100644
--- a/Source/JavaScriptCore/runtime/PropertyDescriptor.h
+++ b/Source/JavaScriptCore/runtime/PropertyDescriptor.h
@@ -29,68 +29,72 @@
#include "JSCJSValue.h"
namespace JSC {
- class GetterSetter;
- // See ES5.1 9.12
- bool sameValue(ExecState*, JSValue, JSValue);
+class GetterSetter;
- class PropertyDescriptor {
- public:
- PropertyDescriptor()
- : m_attributes(defaultAttributes)
- , m_seenAttributes(0)
- {
- }
- PropertyDescriptor(JSValue value, unsigned attributes)
- : m_value(value)
- , m_attributes(attributes)
- , m_seenAttributes(EnumerablePresent | ConfigurablePresent | WritablePresent)
- {
- ASSERT(m_value);
- ASSERT(!m_value.isGetterSetter());
- }
- JS_EXPORT_PRIVATE bool writable() const;
- JS_EXPORT_PRIVATE bool enumerable() const;
- JS_EXPORT_PRIVATE bool configurable() const;
- JS_EXPORT_PRIVATE bool isDataDescriptor() const;
- bool isGenericDescriptor() const;
- JS_EXPORT_PRIVATE bool isAccessorDescriptor() const;
- unsigned attributes() const { return m_attributes; }
- JSValue value() const { return m_value; }
- JS_EXPORT_PRIVATE JSValue getter() const;
- JS_EXPORT_PRIVATE JSValue setter() const;
- JSObject* getterObject() const;
- JSObject* setterObject() const;
- JS_EXPORT_PRIVATE void setUndefined();
- JS_EXPORT_PRIVATE void setDescriptor(JSValue value, unsigned attributes);
- JS_EXPORT_PRIVATE void setAccessorDescriptor(GetterSetter* accessor, unsigned attributes);
- JS_EXPORT_PRIVATE void setWritable(bool);
- JS_EXPORT_PRIVATE void setEnumerable(bool);
- JS_EXPORT_PRIVATE void setConfigurable(bool);
- void setValue(JSValue value) { m_value = value; }
- JS_EXPORT_PRIVATE void setSetter(JSValue);
- JS_EXPORT_PRIVATE void setGetter(JSValue);
- bool isEmpty() const { return !(m_value || m_getter || m_setter || m_seenAttributes); }
- bool writablePresent() const { return m_seenAttributes & WritablePresent; }
- bool enumerablePresent() const { return m_seenAttributes & EnumerablePresent; }
- bool configurablePresent() const { return m_seenAttributes & ConfigurablePresent; }
- bool setterPresent() const { return m_setter; }
- bool getterPresent() const { return m_getter; }
- bool equalTo(ExecState* exec, const PropertyDescriptor& other) const;
- bool attributesEqual(const PropertyDescriptor& other) const;
- unsigned attributesOverridingCurrent(const PropertyDescriptor& current) const;
+// See ES5.1 9.12
+bool sameValue(ExecState*, JSValue, JSValue);
+
+class PropertyDescriptor {
+public:
+ PropertyDescriptor()
+ : m_attributes(defaultAttributes)
+ , m_seenAttributes(0)
+ {
+ }
+ PropertyDescriptor(JSValue value, unsigned attributes)
+ : m_value(value)
+ , m_attributes(attributes)
+ , m_seenAttributes(EnumerablePresent | ConfigurablePresent | WritablePresent)
+ {
+ ASSERT(m_value);
+ ASSERT(!m_value.isGetterSetter());
+ ASSERT(!m_value.isCustomGetterSetter());
+ }
+ JS_EXPORT_PRIVATE bool writable() const;
+ JS_EXPORT_PRIVATE bool enumerable() const;
+ JS_EXPORT_PRIVATE bool configurable() const;
+ JS_EXPORT_PRIVATE bool isDataDescriptor() const;
+ bool isGenericDescriptor() const;
+ JS_EXPORT_PRIVATE bool isAccessorDescriptor() const;
+ unsigned attributes() const { return m_attributes; }
+ JSValue value() const { return m_value; }
+ JS_EXPORT_PRIVATE JSValue getter() const;
+ JS_EXPORT_PRIVATE JSValue setter() const;
+ JSObject* getterObject() const;
+ JSObject* setterObject() const;
+ JS_EXPORT_PRIVATE void setUndefined();
+ JS_EXPORT_PRIVATE void setDescriptor(JSValue, unsigned attributes);
+ JS_EXPORT_PRIVATE void setCustomDescriptor(unsigned attributes);
+ JS_EXPORT_PRIVATE void setAccessorDescriptor(GetterSetter* accessor, unsigned attributes);
+ JS_EXPORT_PRIVATE void setWritable(bool);
+ JS_EXPORT_PRIVATE void setEnumerable(bool);
+ JS_EXPORT_PRIVATE void setConfigurable(bool);
+ void setValue(JSValue value) { m_value = value; }
+ JS_EXPORT_PRIVATE void setSetter(JSValue);
+ JS_EXPORT_PRIVATE void setGetter(JSValue);
+ bool isEmpty() const { return !(m_value || m_getter || m_setter || m_seenAttributes); }
+ bool writablePresent() const { return m_seenAttributes & WritablePresent; }
+ bool enumerablePresent() const { return m_seenAttributes & EnumerablePresent; }
+ bool configurablePresent() const { return m_seenAttributes & ConfigurablePresent; }
+ bool setterPresent() const { return !!m_setter; }
+ bool getterPresent() const { return !!m_getter; }
+ bool equalTo(ExecState*, const PropertyDescriptor& other) const;
+ bool attributesEqual(const PropertyDescriptor& other) const;
+ unsigned attributesOverridingCurrent(const PropertyDescriptor& current) const;
+
+private:
+ JS_EXPORTDATA static unsigned defaultAttributes;
+ bool operator==(const PropertyDescriptor&) { return false; }
+ enum { WritablePresent = 1, EnumerablePresent = 2, ConfigurablePresent = 4};
+ // May be a getter/setter
+ JSValue m_value;
+ JSValue m_getter;
+ JSValue m_setter;
+ unsigned m_attributes;
+ unsigned m_seenAttributes;
+};
- private:
- JS_EXPORTDATA static unsigned defaultAttributes;
- bool operator==(const PropertyDescriptor&){ return false; }
- enum { WritablePresent = 1, EnumerablePresent = 2, ConfigurablePresent = 4};
- // May be a getter/setter
- JSValue m_value;
- JSValue m_getter;
- JSValue m_setter;
- unsigned m_attributes;
- unsigned m_seenAttributes;
- };
}
#endif
diff --git a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h
index fad60fba5..b068b991d 100644
--- a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h
+++ b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2014 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,35 +21,40 @@
#ifndef PropertyMapHashTable_h
#define PropertyMapHashTable_h
+#include "JSExportMacros.h"
#include "PropertyOffset.h"
#include "Structure.h"
#include "WriteBarrier.h"
#include <wtf/CryptographicallyRandomNumber.h>
#include <wtf/HashTable.h>
#include <wtf/MathExtras.h>
-#include <wtf/PassOwnPtr.h>
#include <wtf/Vector.h>
-#include <wtf/text/StringImpl.h>
+#include <wtf/text/AtomicStringImpl.h>
-#ifndef NDEBUG
-#define DUMP_PROPERTYMAP_STATS 0
-#else
#define DUMP_PROPERTYMAP_STATS 0
-#endif
+#define DUMP_PROPERTYMAP_COLLISIONS 0
-#if DUMP_PROPERTYMAP_STATS
+#define PROPERTY_MAP_DELETED_ENTRY_KEY ((UniquedStringImpl*)1)
-extern int numProbes;
-extern int numCollisions;
-extern int numRehashes;
-extern int numRemoves;
+namespace JSC {
-#endif
+#if DUMP_PROPERTYMAP_STATS
-#define PROPERTY_MAP_DELETED_ENTRY_KEY ((StringImpl*)1)
+struct PropertyMapHashTableStats {
+ std::atomic<unsigned> numFinds;
+ std::atomic<unsigned> numCollisions;
+ std::atomic<unsigned> numLookups;
+ std::atomic<unsigned> numLookupProbing;
+ std::atomic<unsigned> numAdds;
+ std::atomic<unsigned> numRemoves;
+ std::atomic<unsigned> numRehashes;
+ std::atomic<unsigned> numReinserts;
+};
-namespace JSC {
+JS_EXPORTDATA extern PropertyMapHashTableStats* propertyMapHashTableStats;
+
+#endif
inline bool isPowerOf2(unsigned v)
{
@@ -72,22 +77,7 @@ inline unsigned nextPowerOf2(unsigned v)
return v;
}
-struct PropertyMapEntry {
- StringImpl* key;
- PropertyOffset offset;
- unsigned attributes;
- WriteBarrier<JSCell> specificValue;
-
- PropertyMapEntry(VM& vm, JSCell* owner, StringImpl* key, PropertyOffset offset, unsigned attributes, JSCell* specificValue)
- : key(key)
- , offset(offset)
- , attributes(attributes)
- , specificValue(vm, owner, specificValue, WriteBarrier<JSCell>::MayBeNull)
- {
- }
-};
-
-class PropertyTable : public JSCell {
+class PropertyTable final : public JSCell {
// This is the implementation for 'iterator' and 'const_iterator',
// used for iterating over the table in insertion order.
@@ -130,20 +120,20 @@ class PropertyTable : public JSCell {
};
public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
static const bool needsDestruction = true;
- static const bool hasImmortalStructure = true;
static void destroy(JSCell*);
DECLARE_EXPORT_INFO;
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), info());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
}
- static void visitChildren(JSCell*, SlotVisitor&);
-
- typedef StringImpl* KeyType;
+ typedef UniquedStringImpl* KeyType;
typedef PropertyMapEntry ValueType;
// The in order iterator provides overloaded * and -> to access the Value at the current position.
@@ -157,8 +147,8 @@ public:
// Constructor is passed an initial capacity, a PropertyTable to copy, or both.
static PropertyTable* create(VM&, unsigned initialCapacity);
- static PropertyTable* clone(VM&, JSCell* owner, const PropertyTable&);
- static PropertyTable* clone(VM&, JSCell* owner, unsigned initialCapacity, const PropertyTable&);
+ static PropertyTable* clone(VM&, const PropertyTable&);
+ static PropertyTable* clone(VM&, unsigned initialCapacity, const PropertyTable&);
~PropertyTable();
// Ordered iteration methods.
@@ -169,7 +159,7 @@ public:
// Find a value in the table.
find_iterator find(const KeyType&);
- find_iterator findWithString(const KeyType&);
+ ValueType* get(const KeyType&);
// Add a value to the table
enum EffectOnPropertyOffset { PropertyOffsetMayChange, PropertyOffsetMustNotChange };
std::pair<find_iterator, bool> add(const ValueType& entry, PropertyOffset&, EffectOnPropertyOffset);
@@ -195,7 +185,7 @@ public:
PropertyOffset nextOffset(PropertyOffset inlineCapacity);
// Copy this PropertyTable, ensuring the copy has at least the capacity provided.
- PropertyTable* copy(VM&, JSCell* owner, unsigned newCapacity);
+ PropertyTable* copy(VM&, unsigned newCapacity);
#ifndef NDEBUG
size_t sizeInMemory();
@@ -204,8 +194,8 @@ public:
private:
PropertyTable(VM&, unsigned initialCapacity);
- PropertyTable(VM&, JSCell*, const PropertyTable&);
- PropertyTable(VM&, JSCell*, unsigned initialCapacity, const PropertyTable&);
+ PropertyTable(VM&, const PropertyTable&);
+ PropertyTable(VM&, unsigned initialCapacity, const PropertyTable&);
PropertyTable(const PropertyTable&);
// Used to insert a value known not to be in the table, and where we know capacity to be available.
@@ -251,9 +241,9 @@ private:
unsigned* m_index;
unsigned m_keyCount;
unsigned m_deletedCount;
- OwnPtr< Vector<PropertyOffset>> m_deletedOffsets;
+ std::unique_ptr<Vector<PropertyOffset>> m_deletedOffsets;
- static const unsigned MinimumTableSize = 8;
+ static const unsigned MinimumTableSize = 16;
static const unsigned EmptyEntryIndex = 0;
};
@@ -280,12 +270,12 @@ inline PropertyTable::const_iterator PropertyTable::end() const
inline PropertyTable::find_iterator PropertyTable::find(const KeyType& key)
{
ASSERT(key);
- ASSERT(key->isIdentifier() || key->isEmptyUnique());
- unsigned hash = key->existingHash();
+ ASSERT(key->isAtomic() || key->isSymbol());
+ unsigned hash = IdentifierRepHash::hash(key);
unsigned step = 0;
#if DUMP_PROPERTYMAP_STATS
- ++numProbes;
+ ++propertyMapHashTableStats->numFinds;
#endif
while (true) {
@@ -295,50 +285,51 @@ inline PropertyTable::find_iterator PropertyTable::find(const KeyType& key)
if (key == table()[entryIndex - 1].key)
return std::make_pair(&table()[entryIndex - 1], hash & m_indexMask);
-#if DUMP_PROPERTYMAP_STATS
- ++numCollisions;
-#endif
-
if (!step)
- step = WTF::doubleHash(key->existingHash()) | 1;
- hash += step;
+ step = WTF::doubleHash(IdentifierRepHash::hash(key)) | 1;
#if DUMP_PROPERTYMAP_STATS
- ++numRehashes;
+ ++propertyMapHashTableStats->numCollisions;
#endif
+
+#if DUMP_PROPERTYMAP_COLLISIONS
+ dataLog("PropertyTable collision for ", key, " (", hash, ") with step ", step, "\n");
+ dataLog("Collided with ", table()[entryIndex - 1].key, "(", IdentifierRepHash::hash(table()[entryIndex - 1].key), ")\n");
+#endif
+
+ hash += step;
}
}
-inline PropertyTable::find_iterator PropertyTable::findWithString(const KeyType& key)
+inline PropertyTable::ValueType* PropertyTable::get(const KeyType& key)
{
ASSERT(key);
- ASSERT(!key->isIdentifier() && !key->hasHash());
- unsigned hash = key->hash();
+ ASSERT(key->isAtomic() || key->isSymbol());
+
+ if (!m_keyCount)
+ return nullptr;
+
+ unsigned hash = IdentifierRepHash::hash(key);
unsigned step = 0;
#if DUMP_PROPERTYMAP_STATS
- ++numProbes;
+ ++propertyMapHashTableStats->numLookups;
#endif
while (true) {
unsigned entryIndex = m_index[hash & m_indexMask];
if (entryIndex == EmptyEntryIndex)
- return std::make_pair((ValueType*)0, hash & m_indexMask);
- const KeyType& keyInMap = table()[entryIndex - 1].key;
- if (equal(key, keyInMap) && keyInMap->isIdentifier())
- return std::make_pair(&table()[entryIndex - 1], hash & m_indexMask);
+ return nullptr;
+ if (key == table()[entryIndex - 1].key)
+ return &table()[entryIndex - 1];
#if DUMP_PROPERTYMAP_STATS
- ++numCollisions;
+ ++propertyMapHashTableStats->numLookupProbing;
#endif
if (!step)
- step = WTF::doubleHash(key->existingHash()) | 1;
+ step = WTF::doubleHash(IdentifierRepHash::hash(key)) | 1;
hash += step;
-
-#if DUMP_PROPERTYMAP_STATS
- ++numRehashes;
-#endif
}
}
@@ -351,6 +342,10 @@ inline std::pair<PropertyTable::find_iterator, bool> PropertyTable::add(const Va
return std::make_pair(iter, false);
}
+#if DUMP_PROPERTYMAP_STATS
+ ++propertyMapHashTableStats->numAdds;
+#endif
+
// Ref the key
entry.key->ref();
@@ -384,7 +379,7 @@ inline void PropertyTable::remove(const find_iterator& iter)
return;
#if DUMP_PROPERTYMAP_STATS
- ++numRemoves;
+ ++propertyMapHashTableStats->numRemoves;
#endif
// Replace this one element with the deleted sentinel. Also clear out
@@ -424,7 +419,7 @@ inline unsigned PropertyTable::propertyStorageSize() const
inline void PropertyTable::clearDeletedOffsets()
{
- m_deletedOffsets.clear();
+ m_deletedOffsets = nullptr;
}
inline bool PropertyTable::hasDeletedOffset()
@@ -442,7 +437,7 @@ inline PropertyOffset PropertyTable::getDeletedOffset()
inline void PropertyTable::addDeletedOffset(PropertyOffset offset)
{
if (!m_deletedOffsets)
- m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>);
+ m_deletedOffsets = std::make_unique<Vector<PropertyOffset>>();
m_deletedOffsets->append(offset);
}
@@ -454,15 +449,15 @@ inline PropertyOffset PropertyTable::nextOffset(PropertyOffset inlineCapacity)
return offsetForPropertyNumber(size(), inlineCapacity);
}
-inline PropertyTable* PropertyTable::copy(VM& vm, JSCell* owner, unsigned newCapacity)
+inline PropertyTable* PropertyTable::copy(VM& vm, unsigned newCapacity)
{
ASSERT(newCapacity >= m_keyCount);
// Fast case; if the new table will be the same m_indexSize as this one, we can memcpy it,
// save rehashing all keys.
if (sizeForCapacity(newCapacity) == m_indexSize)
- return PropertyTable::clone(vm, owner, *this);
- return PropertyTable::clone(vm, owner, newCapacity, *this);
+ return PropertyTable::clone(vm, *this);
+ return PropertyTable::clone(vm, newCapacity, *this);
}
#ifndef NDEBUG
@@ -477,6 +472,10 @@ inline size_t PropertyTable::sizeInMemory()
inline void PropertyTable::reinsert(const ValueType& entry)
{
+#if DUMP_PROPERTYMAP_STATS
+ ++propertyMapHashTableStats->numReinserts;
+#endif
+
// Used to insert a value known not to be in the table, and where
// we know capacity to be available.
ASSERT(canInsert());
@@ -492,6 +491,10 @@ inline void PropertyTable::reinsert(const ValueType& entry)
inline void PropertyTable::rehash(unsigned newCapacity)
{
+#if DUMP_PROPERTYMAP_STATS
+ ++propertyMapHashTableStats->numRehashes;
+#endif
+
unsigned* oldEntryIndices = m_index;
iterator iter = this->begin();
iterator end = this->end();
diff --git a/Source/JavaScriptCore/runtime/PropertyName.h b/Source/JavaScriptCore/runtime/PropertyName.h
index e4d5fabd5..9d3cc2b51 100644
--- a/Source/JavaScriptCore/runtime/PropertyName.h
+++ b/Source/JavaScriptCore/runtime/PropertyName.h
@@ -28,90 +28,56 @@
#include "Identifier.h"
#include "PrivateName.h"
+#include <wtf/Optional.h>
namespace JSC {
-template <typename CharType>
-ALWAYS_INLINE uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length)
-{
- // An empty string is not a number.
- if (!length)
- return UINT_MAX;
-
- // Get the first character, turning it into a digit.
- uint32_t value = characters[0] - '0';
- if (value > 9)
- return UINT_MAX;
-
- // Check for leading zeros. If the first characher is 0, then the
- // length of the string must be one - e.g. "042" is not equal to "42".
- if (!value && length > 1)
- return UINT_MAX;
-
- while (--length) {
- // Multiply value by 10, checking for overflow out of 32 bits.
- if (value > 0xFFFFFFFFU / 10)
- return UINT_MAX;
- value *= 10;
-
- // Get the next character, turning it into a digit.
- uint32_t newValue = *(++characters) - '0';
- if (newValue > 9)
- return UINT_MAX;
-
- // Add in the old value, checking for overflow out of 32 bits.
- newValue += value;
- if (newValue < value)
- return UINT_MAX;
- value = newValue;
- }
-
- return value;
-}
-
-ALWAYS_INLINE uint32_t toUInt32FromStringImpl(StringImpl* impl)
-{
- if (impl->is8Bit())
- return toUInt32FromCharacters(impl->characters8(), impl->length());
- return toUInt32FromCharacters(impl->characters16(), impl->length());
-}
-
class PropertyName {
public:
+ PropertyName(UniquedStringImpl* propertyName)
+ : m_impl(propertyName)
+ {
+ }
+
PropertyName(const Identifier& propertyName)
- : m_impl(propertyName.impl())
+ : PropertyName(propertyName.impl())
{
- ASSERT(!m_impl || m_impl->isIdentifier() || m_impl->isEmptyUnique());
}
PropertyName(const PrivateName& propertyName)
: m_impl(propertyName.uid())
{
- ASSERT(m_impl && m_impl->isEmptyUnique());
+ ASSERT(m_impl);
+ ASSERT(m_impl->isSymbol());
}
- StringImpl* uid() const
+ bool isNull() const { return !m_impl; }
+
+ bool isSymbol()
{
- ASSERT(!m_impl || (m_impl->isIdentifier() == !m_impl->isEmptyUnique()));
- return m_impl;
+ return m_impl && m_impl->isSymbol();
}
- StringImpl* publicName() const
+ UniquedStringImpl* uid() const
{
- ASSERT(!m_impl || (m_impl->isIdentifier() == !m_impl->isEmptyUnique()));
- return m_impl->isIdentifier() ? m_impl : 0;
+ return m_impl;
}
- static const uint32_t NotAnIndex = UINT_MAX;
+ AtomicStringImpl* publicName() const
+ {
+ return (!m_impl || m_impl->isSymbol()) ? nullptr : static_cast<AtomicStringImpl*>(m_impl);
+ }
- uint32_t asIndex()
+ void dump(PrintStream& out) const
{
- ASSERT(!m_impl || (m_impl->isIdentifier() == !m_impl->isEmptyUnique()));
- return m_impl ? toUInt32FromStringImpl(m_impl) : NotAnIndex;
+ if (m_impl)
+ out.print(m_impl);
+ else
+ out.print("<null property name>");
}
private:
- StringImpl* m_impl;
+ UniquedStringImpl* m_impl;
};
inline bool operator==(PropertyName a, const Identifier& b)
@@ -129,6 +95,11 @@ inline bool operator==(PropertyName a, PropertyName b)
return a.uid() == b.uid();
}
+inline bool operator==(PropertyName a, const char* b)
+{
+ return equal(a.uid(), b);
+}
+
inline bool operator!=(PropertyName a, const Identifier& b)
{
return a.uid() != b.impl();
@@ -144,6 +115,16 @@ inline bool operator!=(PropertyName a, PropertyName b)
return a.uid() != b.uid();
}
+ALWAYS_INLINE Optional<uint32_t> parseIndex(PropertyName propertyName)
+{
+ auto uid = propertyName.uid();
+ if (!uid)
+ return Nullopt;
+ if (uid->isSymbol())
+ return Nullopt;
+ return parseIndex(*uid);
+}
+
}
#endif
diff --git a/Source/JavaScriptCore/runtime/PropertyNameArray.cpp b/Source/JavaScriptCore/runtime/PropertyNameArray.cpp
deleted file mode 100644
index 08a5296a4..000000000
--- a/Source/JavaScriptCore/runtime/PropertyNameArray.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2006, 2008 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
- * 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 "PropertyNameArray.h"
-
-#include "JSObject.h"
-
-#include "Structure.h"
-#include "StructureChain.h"
-
-namespace JSC {
-
-static const size_t setThreshold = 20;
-
-void PropertyNameArray::add(StringImpl* identifier)
-{
- ASSERT(!identifier || identifier == StringImpl::empty() || identifier->isIdentifier());
-
- size_t size = m_data->propertyNameVector().size();
- if (size < setThreshold) {
- for (size_t i = 0; i < size; ++i) {
- if (identifier == m_data->propertyNameVector()[i].impl())
- return;
- }
- } else {
- if (m_set.isEmpty()) {
- for (size_t i = 0; i < size; ++i)
- m_set.add(m_data->propertyNameVector()[i].impl());
- }
- if (!m_set.add(identifier).isNewEntry)
- return;
- }
-
- addKnownUnique(identifier);
-}
-
-} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/PropertyNameArray.h b/Source/JavaScriptCore/runtime/PropertyNameArray.h
index bfbddaa60..14f6f785c 100644
--- a/Source/JavaScriptCore/runtime/PropertyNameArray.h
+++ b/Source/JavaScriptCore/runtime/PropertyNameArray.h
@@ -27,88 +27,129 @@
#include <wtf/Vector.h>
namespace JSC {
-
- class Structure;
- class StructureChain;
- // FIXME: Rename to PropertyNameArray.
- class PropertyNameArrayData : public RefCounted<PropertyNameArrayData> {
- public:
- typedef Vector<Identifier, 20> PropertyNameVector;
-
- static PassRefPtr<PropertyNameArrayData> create() { return adoptRef(new PropertyNameArrayData); }
-
- PropertyNameVector& propertyNameVector() { return m_propertyNameVector; }
-
- private:
- PropertyNameArrayData()
- {
- }
-
- PropertyNameVector m_propertyNameVector;
- };
-
- // FIXME: Rename to PropertyNameArrayBuilder.
- class PropertyNameArray {
- public:
- PropertyNameArray(VM* vm)
- : m_data(PropertyNameArrayData::create())
- , m_vm(vm)
- , m_numCacheableSlots(0)
- , m_baseObject(0)
- {
+// FIXME: Rename to PropertyNameArray.
+class PropertyNameArrayData : public RefCounted<PropertyNameArrayData> {
+public:
+ typedef Vector<Identifier, 20> PropertyNameVector;
+
+ static Ref<PropertyNameArrayData> create() { return adoptRef(*new PropertyNameArrayData); }
+
+ PropertyNameVector& propertyNameVector() { return m_propertyNameVector; }
+
+private:
+ PropertyNameArrayData()
+ {
+ }
+
+ PropertyNameVector m_propertyNameVector;
+};
+
+// FIXME: Rename to PropertyNameArrayBuilder.
+class PropertyNameArray {
+public:
+ PropertyNameArray(VM* vm, PropertyNameMode mode)
+ : m_data(PropertyNameArrayData::create())
+ , m_vm(vm)
+ , m_mode(mode)
+ {
+ }
+
+ PropertyNameArray(ExecState* exec, PropertyNameMode mode)
+ : PropertyNameArray(&exec->vm(), mode)
+ {
+ }
+
+ VM* vm() { return m_vm; }
+
+ void add(uint32_t index)
+ {
+ add(Identifier::from(m_vm, index));
+ }
+
+ void add(const Identifier&);
+ void add(UniquedStringImpl*);
+ void addKnownUnique(UniquedStringImpl*);
+
+ Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; }
+ const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; }
+
+ void setData(PassRefPtr<PropertyNameArrayData> data) { m_data = data; }
+ PropertyNameArrayData* data() { return m_data.get(); }
+ PassRefPtr<PropertyNameArrayData> releaseData() { return m_data.release(); }
+
+ // FIXME: Remove these functions.
+ bool canAddKnownUniqueForStructure() const { return m_data->propertyNameVector().isEmpty(); }
+ typedef PropertyNameArrayData::PropertyNameVector::const_iterator const_iterator;
+ size_t size() const { return m_data->propertyNameVector().size(); }
+ const_iterator begin() const { return m_data->propertyNameVector().begin(); }
+ const_iterator end() const { return m_data->propertyNameVector().end(); }
+
+ PropertyNameMode mode() const { return m_mode; }
+ bool includeSymbolProperties() const;
+ bool includeStringProperties() const;
+
+private:
+ bool isUidMatchedToTypeMode(UniquedStringImpl* identifier);
+
+ RefPtr<PropertyNameArrayData> m_data;
+ HashSet<UniquedStringImpl*> m_set;
+ VM* m_vm;
+ PropertyNameMode m_mode;
+};
+
+ALWAYS_INLINE void PropertyNameArray::add(const Identifier& identifier)
+{
+ add(identifier.impl());
+}
+
+ALWAYS_INLINE void PropertyNameArray::addKnownUnique(UniquedStringImpl* identifier)
+{
+ if (!isUidMatchedToTypeMode(identifier))
+ return;
+ m_data->propertyNameVector().append(Identifier::fromUid(m_vm, identifier));
+}
+
+ALWAYS_INLINE void PropertyNameArray::add(UniquedStringImpl* identifier)
+{
+ static const unsigned setThreshold = 20;
+
+ ASSERT(identifier);
+
+ if (!isUidMatchedToTypeMode(identifier))
+ return;
+
+ if (size() < setThreshold) {
+ if (m_data->propertyNameVector().contains(identifier))
+ return;
+ } else {
+ if (m_set.isEmpty()) {
+ for (Identifier& name : m_data->propertyNameVector())
+ m_set.add(name.impl());
}
-
- PropertyNameArray(ExecState* exec)
- : m_data(PropertyNameArrayData::create())
- , m_vm(&exec->vm())
- , m_numCacheableSlots(0)
- , m_baseObject(0)
- {
- }
-
- VM* vm() { return m_vm; }
-
- void add(const Identifier& identifier) { add(identifier.impl()); }
- JS_EXPORT_PRIVATE void add(StringImpl*);
- void addKnownUnique(StringImpl* identifier) { m_data->propertyNameVector().append(Identifier(m_vm, identifier)); }
-
- Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; }
- const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; }
-
- void setData(PassRefPtr<PropertyNameArrayData> data) { m_data = data; }
- PropertyNameArrayData* data() { return m_data.get(); }
- PassRefPtr<PropertyNameArrayData> releaseData() { return m_data.release(); }
-
- // FIXME: Remove these functions.
- typedef PropertyNameArrayData::PropertyNameVector::const_iterator const_iterator;
- size_t size() const { return m_data->propertyNameVector().size(); }
- const_iterator begin() const { return m_data->propertyNameVector().begin(); }
- const_iterator end() const { return m_data->propertyNameVector().end(); }
-
- size_t numCacheableSlots() const { return m_numCacheableSlots; }
- void setNumCacheableSlotsForObject(JSObject* object, size_t numCacheableSlots)
- {
- if (object != m_baseObject)
- return;
- m_numCacheableSlots = numCacheableSlots;
- }
- void setBaseObject(JSObject* object)
- {
- if (m_baseObject)
- return;
- m_baseObject = object;
- }
-
- private:
- typedef HashSet<StringImpl*, PtrHash<StringImpl*>> IdentifierSet;
-
- RefPtr<PropertyNameArrayData> m_data;
- IdentifierSet m_set;
- VM* m_vm;
- size_t m_numCacheableSlots;
- JSObject* m_baseObject;
- };
+ if (!m_set.add(identifier).isNewEntry)
+ return;
+ }
+
+ addKnownUnique(identifier);
+}
+
+ALWAYS_INLINE bool PropertyNameArray::isUidMatchedToTypeMode(UniquedStringImpl* identifier)
+{
+ if (identifier->isSymbol())
+ return includeSymbolProperties();
+ return includeStringProperties();
+}
+
+ALWAYS_INLINE bool PropertyNameArray::includeSymbolProperties() const
+{
+ return static_cast<std::underlying_type<PropertyNameMode>::type>(m_mode) & static_cast<std::underlying_type<PropertyNameMode>::type>(PropertyNameMode::Symbols);
+}
+
+ALWAYS_INLINE bool PropertyNameArray::includeStringProperties() const
+{
+ return static_cast<std::underlying_type<PropertyNameMode>::type>(m_mode) & static_cast<std::underlying_type<PropertyNameMode>::type>(PropertyNameMode::Strings);
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/PropertyOffset.h b/Source/JavaScriptCore/runtime/PropertyOffset.h
index dc0297bf7..aeedb70bd 100644
--- a/Source/JavaScriptCore/runtime/PropertyOffset.h
+++ b/Source/JavaScriptCore/runtime/PropertyOffset.h
@@ -26,7 +26,6 @@
#ifndef PropertyOffset_h
#define PropertyOffset_h
-#include <wtf/Platform.h>
#include <wtf/StdLibExtras.h>
namespace JSC {
diff --git a/Source/JavaScriptCore/runtime/PropertySlot.cpp b/Source/JavaScriptCore/runtime/PropertySlot.cpp
index c949f4bd2..ad555c7cf 100644
--- a/Source/JavaScriptCore/runtime/PropertySlot.cpp
+++ b/Source/JavaScriptCore/runtime/PropertySlot.cpp
@@ -23,6 +23,7 @@
#include "GetterSetter.h"
#include "JSCJSValueInlines.h"
+#include "JSObject.h"
namespace JSC {
@@ -32,4 +33,10 @@ JSValue PropertySlot::functionGetter(ExecState* exec) const
return callGetter(exec, m_thisValue, m_data.getter.getterSetter);
}
+JSValue PropertySlot::customGetter(ExecState* exec, PropertyName propertyName) const
+{
+ JSValue thisValue = m_attributes & CustomAccessor ? m_thisValue : JSValue(slotBase());
+ return JSValue::decode(m_data.custom.getValue(exec, JSValue::encode(thisValue), propertyName));
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/PropertySlot.h b/Source/JavaScriptCore/runtime/PropertySlot.h
index ae93455a4..7e7ee058b 100644
--- a/Source/JavaScriptCore/runtime/PropertySlot.h
+++ b/Source/JavaScriptCore/runtime/PropertySlot.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2007, 2008, 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 Library General Public
@@ -31,42 +31,72 @@ namespace JSC {
class ExecState;
class GetterSetter;
+class JSObject;
// ECMA 262-3 8.6.1
// Property attributes
enum Attribute {
- None = 0,
- ReadOnly = 1 << 1, // property can be only read, not written
- DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
- DontDelete = 1 << 3, // property can't be deleted
- Function = 1 << 4, // property is a function - only used by static hashtables
- Accessor = 1 << 5, // property is a getter/setter
+ None = 0,
+ ReadOnly = 1 << 1, // property can be only read, not written
+ DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
+ DontDelete = 1 << 3, // property can't be deleted
+ Accessor = 1 << 4, // property is a getter/setter
+ CustomAccessor = 1 << 5,
+
+ // Things that are used by static hashtables are not in the attributes byte in PropertyMapEntry.
+ Function = 1 << 8, // property is a function - only used by static hashtables
+ Builtin = 1 << 9, // property is a builtin function - only used by static hashtables
+ ConstantInteger = 1 << 10, // property is a constant integer - only used by static hashtables
+ BuiltinOrFunction = Builtin | Function, // helper only used by static hashtables
+ BuiltinOrFunctionOrAccessor = Builtin | Function | Accessor, // helper only used by static hashtables
+ BuiltinOrFunctionOrAccessorOrConstant = Builtin | Function | Accessor | ConstantInteger, // helper only used by static hashtables
};
+inline unsigned attributesForStructure(unsigned attributes)
+{
+ // The attributes that are used just for the static hashtable are at bit 8 and higher.
+ return static_cast<uint8_t>(attributes);
+}
+
class PropertySlot {
- enum PropertyType {
+ enum PropertyType : uint8_t {
TypeUnset,
TypeValue,
TypeGetter,
- TypeCustom,
- TypeCustomIndex
+ TypeCustom
+ };
+
+ enum CacheabilityType : uint8_t {
+ CachingDisallowed,
+ CachingAllowed
};
public:
- explicit PropertySlot(const JSValue thisValue)
- : m_propertyType(TypeUnset)
- , m_offset(invalidOffset)
+ enum class InternalMethodType : uint8_t {
+ Get, // [[Get]] internal method in the spec.
+ HasProperty, // [[HasProperty]] internal method in the spec.
+ GetOwnProperty, // [[GetOwnProperty]] internal method in the spec.
+ VMInquiry, // Our VM is just poking around. When this is the InternalMethodType, getOwnPropertySlot is not allowed to do user observable actions.
+ };
+
+ explicit PropertySlot(const JSValue thisValue, InternalMethodType internalMethodType)
+ : m_offset(invalidOffset)
, m_thisValue(thisValue)
+ , m_slotBase(nullptr)
+ , m_watchpointSet(nullptr)
+ , m_cacheability(CachingAllowed)
+ , m_propertyType(TypeUnset)
+ , m_internalMethodType(internalMethodType)
{
}
- typedef EncodedJSValue (*GetValueFunc)(ExecState*, EncodedJSValue slotBase, EncodedJSValue thisValue, PropertyName);
- typedef EncodedJSValue (*GetIndexValueFunc)(ExecState*, EncodedJSValue slotBase, EncodedJSValue thisValue, unsigned);
+ typedef EncodedJSValue (*GetValueFunc)(ExecState*, EncodedJSValue thisValue, PropertyName);
JSValue getValue(ExecState*, PropertyName) const;
JSValue getValue(ExecState*, unsigned propertyName) const;
- bool isCacheable() const { return m_offset != invalidOffset; }
+ bool isCacheable() const { return m_cacheability == CachingAllowed && m_offset != invalidOffset; }
+ bool isUnset() const { return m_propertyType == TypeUnset; }
bool isValue() const { return m_propertyType == TypeValue; }
bool isAccessor() const { return m_propertyType == TypeGetter; }
bool isCustom() const { return m_propertyType == TypeCustom; }
@@ -74,6 +104,13 @@ public:
bool isCacheableGetter() const { return isCacheable() && isAccessor(); }
bool isCacheableCustom() const { return isCacheable() && isCustom(); }
+ InternalMethodType internalMethodType() const { return m_internalMethodType; }
+
+ void disableCaching()
+ {
+ m_cacheability = CachingDisallowed;
+ }
+
unsigned attributes() const { return m_attributes; }
PropertyOffset cachedOffset() const
@@ -96,13 +133,18 @@ public:
JSObject* slotBase() const
{
- ASSERT(m_propertyType != TypeUnset);
return m_slotBase;
}
+ WatchpointSet* watchpointSet() const
+ {
+ return m_watchpointSet;
+ }
+
void setValue(JSObject* slotBase, unsigned attributes, JSValue value)
{
- ASSERT(value);
+ ASSERT(attributes == attributesForStructure(attributes));
+
m_data.value = JSValue::encode(value);
m_attributes = attributes;
@@ -114,6 +156,8 @@ public:
void setValue(JSObject* slotBase, unsigned attributes, JSValue value, PropertyOffset offset)
{
+ ASSERT(attributes == attributesForStructure(attributes));
+
ASSERT(value);
m_data.value = JSValue::encode(value);
m_attributes = attributes;
@@ -126,6 +170,8 @@ public:
void setValue(JSString*, unsigned attributes, JSValue value)
{
+ ASSERT(attributes == attributesForStructure(attributes));
+
ASSERT(value);
m_data.value = JSValue::encode(value);
m_attributes = attributes;
@@ -137,6 +183,8 @@ public:
void setCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
{
+ ASSERT(attributes == attributesForStructure(attributes));
+
ASSERT(getValue);
m_data.custom.getValue = getValue;
m_attributes = attributes;
@@ -149,6 +197,8 @@ public:
void setCacheableCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
{
+ ASSERT(attributes == attributesForStructure(attributes));
+
ASSERT(getValue);
m_data.custom.getValue = getValue;
m_attributes = attributes;
@@ -159,21 +209,10 @@ public:
m_offset = !invalidOffset;
}
- void setCustomIndex(JSObject* slotBase, unsigned attributes, unsigned index, GetIndexValueFunc getIndexValue)
- {
- ASSERT(getIndexValue);
- m_data.customIndex.getIndexValue = getIndexValue;
- m_data.customIndex.index = index;
- m_attributes = attributes;
-
- ASSERT(slotBase);
- m_slotBase = slotBase;
- m_propertyType = TypeCustomIndex;
- m_offset = invalidOffset;
- }
-
void setGetterSlot(JSObject* slotBase, unsigned attributes, GetterSetter* getterSetter)
{
+ ASSERT(attributes == attributesForStructure(attributes));
+
ASSERT(getterSetter);
m_data.getter.getterSetter = getterSetter;
m_attributes = attributes;
@@ -186,6 +225,8 @@ public:
void setCacheableGetterSlot(JSObject* slotBase, unsigned attributes, GetterSetter* getterSetter, PropertyOffset offset)
{
+ ASSERT(attributes == attributesForStructure(attributes));
+
ASSERT(getterSetter);
m_data.getter.getterSetter = getterSetter;
m_attributes = attributes;
@@ -196,6 +237,11 @@ public:
m_offset = offset;
}
+ void setThisValue(JSValue thisValue)
+ {
+ m_thisValue = thisValue;
+ }
+
void setUndefined()
{
m_data.value = JSValue::encode(jsUndefined());
@@ -206,8 +252,14 @@ public:
m_offset = invalidOffset;
}
+ void setWatchpointSet(WatchpointSet& set)
+ {
+ m_watchpointSet = &set;
+ }
+
private:
JS_EXPORT_PRIVATE JSValue functionGetter(ExecState*) const;
+ JS_EXPORT_PRIVATE JSValue customGetter(ExecState*, PropertyName) const;
unsigned m_attributes;
union {
@@ -218,18 +270,35 @@ private:
struct {
GetValueFunc getValue;
} custom;
- struct {
- GetIndexValueFunc getIndexValue;
- unsigned index;
- } customIndex;
} m_data;
- PropertyType m_propertyType;
PropertyOffset m_offset;
- const JSValue m_thisValue;
+ JSValue m_thisValue;
JSObject* m_slotBase;
+ WatchpointSet* m_watchpointSet;
+ CacheabilityType m_cacheability;
+ PropertyType m_propertyType;
+ InternalMethodType m_internalMethodType;
};
+ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, PropertyName propertyName) const
+{
+ if (m_propertyType == TypeValue)
+ return JSValue::decode(m_data.value);
+ if (m_propertyType == TypeGetter)
+ return functionGetter(exec);
+ return customGetter(exec, propertyName);
+}
+
+ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, unsigned propertyName) const
+{
+ if (m_propertyType == TypeValue)
+ return JSValue::decode(m_data.value);
+ if (m_propertyType == TypeGetter)
+ return functionGetter(exec);
+ return customGetter(exec, Identifier::from(exec, propertyName));
+}
+
} // namespace JSC
#endif // PropertySlot_h
diff --git a/Source/JavaScriptCore/runtime/PropertyTable.cpp b/Source/JavaScriptCore/runtime/PropertyTable.cpp
index 82210da95..74474c6d9 100644
--- a/Source/JavaScriptCore/runtime/PropertyTable.cpp
+++ b/Source/JavaScriptCore/runtime/PropertyTable.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * 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
@@ -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
@@ -35,7 +35,7 @@
namespace JSC {
-const ClassInfo PropertyTable::s_info = { "PropertyTable", 0, 0, 0, CREATE_METHOD_TABLE(PropertyTable) };
+const ClassInfo PropertyTable::s_info = { "PropertyTable", 0, 0, CREATE_METHOD_TABLE(PropertyTable) };
PropertyTable* PropertyTable::create(VM& vm, unsigned initialCapacity)
{
@@ -44,16 +44,16 @@ PropertyTable* PropertyTable::create(VM& vm, unsigned initialCapacity)
return table;
}
-PropertyTable* PropertyTable::clone(VM& vm, JSCell* owner, const PropertyTable& other)
+PropertyTable* PropertyTable::clone(VM& vm, const PropertyTable& other)
{
- PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, owner, other);
+ PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, other);
table->finishCreation(vm);
return table;
}
-PropertyTable* PropertyTable::clone(VM& vm, JSCell* owner, unsigned initialCapacity, const PropertyTable& other)
+PropertyTable* PropertyTable::clone(VM& vm, unsigned initialCapacity, const PropertyTable& other)
{
- PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, owner, initialCapacity, other);
+ PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, initialCapacity, other);
table->finishCreation(vm);
return table;
}
@@ -69,7 +69,7 @@ PropertyTable::PropertyTable(VM& vm, unsigned initialCapacity)
ASSERT(isPowerOf2(m_indexSize));
}
-PropertyTable::PropertyTable(VM& vm, JSCell* owner, const PropertyTable& other)
+PropertyTable::PropertyTable(VM& vm, const PropertyTable& other)
: JSCell(vm, vm.propertyTableStructure.get())
, m_indexSize(other.m_indexSize)
, m_indexMask(other.m_indexMask)
@@ -82,18 +82,16 @@ PropertyTable::PropertyTable(VM& vm, JSCell* owner, const PropertyTable& other)
memcpy(m_index, other.m_index, dataSize());
iterator end = this->end();
- for (iterator iter = begin(); iter != end; ++iter) {
+ for (iterator iter = begin(); iter != end; ++iter)
iter->key->ref();
- Heap::writeBarrier(owner, iter->specificValue.get());
- }
// Copy the m_deletedOffsets vector.
Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get();
if (otherDeletedOffsets)
- m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets));
+ m_deletedOffsets = std::make_unique<Vector<PropertyOffset>>(*otherDeletedOffsets);
}
-PropertyTable::PropertyTable(VM& vm, JSCell* owner, unsigned initialCapacity, const PropertyTable& other)
+PropertyTable::PropertyTable(VM& vm, unsigned initialCapacity, const PropertyTable& other)
: JSCell(vm, vm.propertyTableStructure.get())
, m_indexSize(sizeForCapacity(initialCapacity))
, m_indexMask(m_indexSize - 1)
@@ -109,13 +107,12 @@ PropertyTable::PropertyTable(VM& vm, JSCell* owner, unsigned initialCapacity, co
ASSERT(canInsert());
reinsert(*iter);
iter->key->ref();
- Heap::writeBarrier(owner, iter->specificValue.get());
}
// Copy the m_deletedOffsets vector.
Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get();
if (otherDeletedOffsets)
- m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets));
+ m_deletedOffsets = std::make_unique<Vector<PropertyOffset>>(*otherDeletedOffsets);
}
void PropertyTable::destroy(JSCell* cell)
@@ -132,17 +129,5 @@ PropertyTable::~PropertyTable()
fastFree(m_index);
}
-void PropertyTable::visitChildren(JSCell* cell, SlotVisitor& visitor)
-{
- PropertyTable* thisObject = jsCast<PropertyTable*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
- JSCell::visitChildren(thisObject, visitor);
+} // namespace JSC
- PropertyTable::iterator end = thisObject->end();
- for (PropertyTable::iterator ptr = thisObject->begin(); ptr != end; ++ptr)
- visitor.append(&ptr->specificValue);
-}
-
-}
diff --git a/Source/JavaScriptCore/runtime/Protect.h b/Source/JavaScriptCore/runtime/Protect.h
index 78dd319a3..e72cafb82 100644
--- a/Source/JavaScriptCore/runtime/Protect.h
+++ b/Source/JavaScriptCore/runtime/Protect.h
@@ -27,39 +27,39 @@
namespace JSC {
- inline void gcProtect(JSCell* val)
- {
- Heap::heap(val)->protect(val);
- }
+inline void gcProtect(JSCell* val)
+{
+ Heap::heap(val)->protect(val);
+}
- inline void gcUnprotect(JSCell* val)
- {
- Heap::heap(val)->unprotect(val);
- }
+inline void gcUnprotect(JSCell* val)
+{
+ Heap::heap(val)->unprotect(val);
+}
- inline void gcProtectNullTolerant(JSCell* val)
- {
- if (val)
- gcProtect(val);
- }
+inline void gcProtectNullTolerant(JSCell* val)
+{
+ if (val)
+ gcProtect(val);
+}
- inline void gcUnprotectNullTolerant(JSCell* val)
- {
- if (val)
- gcUnprotect(val);
- }
-
- inline void gcProtect(JSValue value)
- {
- if (value && value.isCell())
- gcProtect(value.asCell());
- }
+inline void gcUnprotectNullTolerant(JSCell* val)
+{
+ if (val)
+ gcUnprotect(val);
+}
- inline void gcUnprotect(JSValue value)
- {
- if (value && value.isCell())
- gcUnprotect(value.asCell());
- }
+inline void gcProtect(JSValue value)
+{
+ if (value && value.isCell())
+ gcProtect(value.asCell());
+}
+
+inline void gcUnprotect(JSValue value)
+{
+ if (value && value.isCell())
+ gcUnprotect(value.asCell());
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/PrototypeMap.cpp b/Source/JavaScriptCore/runtime/PrototypeMap.cpp
index 78d6a7171..d9a150db0 100644
--- a/Source/JavaScriptCore/runtime/PrototypeMap.cpp
+++ b/Source/JavaScriptCore/runtime/PrototypeMap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -26,14 +26,15 @@
#include "config.h"
#include "PrototypeMap.h"
+#include "IndexingType.h"
#include "JSGlobalObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
void PrototypeMap::addPrototype(JSObject* object)
{
- m_prototypes.add(object, object);
+ m_prototypes.set(object, object);
// Note that this method makes the somewhat odd decision to not check if this
// object currently has indexed accessors. We could do that check here, and if
@@ -52,24 +53,39 @@ void PrototypeMap::addPrototype(JSObject* object)
// used as a prototype.
}
-Structure* PrototypeMap::emptyObjectStructureForPrototype(JSObject* prototype, unsigned inlineCapacity)
+inline Structure* PrototypeMap::createEmptyStructure(JSObject* prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity)
{
- StructureMap::AddResult addResult = m_structures.add(std::make_pair(prototype, inlineCapacity), nullptr);
- if (!addResult.isNewEntry) {
+ auto key = std::make_pair(prototype, std::make_pair(inlineCapacity, classInfo));
+ if (Structure* structure = m_structures.get(key)) {
ASSERT(isPrototype(prototype));
- return addResult.iterator->value.get();
+ return structure;
}
addPrototype(prototype);
- Structure* structure = JSFinalObject::createStructure(
- prototype->globalObject()->vm(), prototype->globalObject(), prototype, inlineCapacity);
- addResult.iterator->value = Weak<Structure>(structure);
+ Structure* structure = Structure::create(
+ prototype->globalObject()->vm(), prototype->globalObject(), prototype, typeInfo, classInfo, indexingType, inlineCapacity);
+ m_structures.set(key, Weak<Structure>(structure));
return structure;
}
+Structure* PrototypeMap::emptyStructureForPrototypeFromBaseStructure(JSObject* prototype, Structure* baseStructure)
+{
+ // We currently do not have inline capacity static analysis for subclasses and all internal function constructors have a default inline capacity of 0.
+ IndexingType indexingType = baseStructure->indexingType();
+ if (prototype->structure()->anyObjectInChainMayInterceptIndexedAccesses() && hasIndexedProperties(indexingType))
+ indexingType = (indexingType & ~IndexingShapeMask) | SlowPutArrayStorageShape;
+
+ return createEmptyStructure(prototype, baseStructure->typeInfo(), baseStructure->classInfo(), indexingType, 0);
+}
+
+Structure* PrototypeMap::emptyObjectStructureForPrototype(JSObject* prototype, unsigned inlineCapacity)
+{
+ return createEmptyStructure(prototype, JSFinalObject::typeInfo(), JSFinalObject::info(), JSFinalObject::defaultIndexingType, inlineCapacity);
+}
+
void PrototypeMap::clearEmptyObjectStructureForPrototype(JSObject* object, unsigned inlineCapacity)
{
- m_structures.remove(std::make_pair(object, inlineCapacity));
+ m_structures.remove(std::make_pair(object, std::make_pair(inlineCapacity, JSFinalObject::info())));
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/PrototypeMap.h b/Source/JavaScriptCore/runtime/PrototypeMap.h
index 9752ca7ea..4d2122dc8 100644
--- a/Source/JavaScriptCore/runtime/PrototypeMap.h
+++ b/Source/JavaScriptCore/runtime/PrototypeMap.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -33,18 +33,28 @@ namespace JSC {
class JSObject;
class Structure;
+class VM;
// Tracks the canonical structure an object should be allocated with when inheriting from a given prototype.
class PrototypeMap {
public:
+ explicit PrototypeMap(VM& vm)
+ : m_prototypes(vm)
+ , m_structures(vm)
+ {
+ }
+
JS_EXPORT_PRIVATE Structure* emptyObjectStructureForPrototype(JSObject*, unsigned inlineCapacity);
+ JS_EXPORT_PRIVATE Structure* emptyStructureForPrototypeFromBaseStructure(JSObject*, Structure*);
void clearEmptyObjectStructureForPrototype(JSObject*, unsigned inlineCapacity);
- void addPrototype(JSObject*);
+ JS_EXPORT_PRIVATE void addPrototype(JSObject*);
TriState isPrototype(JSObject*) const; // Returns a conservative estimate.
private:
+ Structure* createEmptyStructure(JSObject* prototype, const TypeInfo&, const ClassInfo*, IndexingType, unsigned inlineCapacity);
+
WeakGCMap<JSObject*, JSObject> m_prototypes;
- typedef WeakGCMap<std::pair<JSObject*, unsigned>, Structure> StructureMap;
+ typedef WeakGCMap<std::pair<JSObject*, std::pair<unsigned, const ClassInfo*>>, Structure> StructureMap;
StructureMap m_structures;
};
diff --git a/Source/JavaScriptCore/runtime/ProxyConstructor.cpp b/Source/JavaScriptCore/runtime/ProxyConstructor.cpp
new file mode 100644
index 000000000..a3bf232fb
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ProxyConstructor.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 "ProxyConstructor.h"
+
+#include "Error.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "ObjectPrototype.h"
+#include "ProxyObject.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ProxyConstructor);
+
+const ClassInfo ProxyConstructor::s_info = { "Proxy", &Base::s_info, 0, CREATE_METHOD_TABLE(ProxyConstructor) };
+
+ProxyConstructor* ProxyConstructor::create(VM& vm, Structure* structure)
+{
+ ProxyConstructor* constructor = new (NotNull, allocateCell<ProxyConstructor>(vm.heap)) ProxyConstructor(vm, structure);
+ constructor->finishCreation(vm, "Proxy");
+ return constructor;
+}
+
+ProxyConstructor::ProxyConstructor(VM& vm, Structure* structure)
+ : Base(vm, structure)
+{
+}
+
+void ProxyConstructor::finishCreation(VM& vm, const char* name)
+{
+ Base::finishCreation(vm, name);
+
+ putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(2), ReadOnly | DontDelete | DontEnum);
+}
+
+static EncodedJSValue JSC_HOST_CALL constructProxyObject(ExecState* exec)
+{
+ if (exec->newTarget().isUndefined())
+ return throwVMTypeError(exec, ASCIILiteral("new.target of Proxy construct should not be undefined."));
+
+ ArgList args(exec);
+ JSValue target = args.at(0);
+ JSValue handler = args.at(1);
+ return JSValue::encode(ProxyObject::create(exec, exec->lexicalGlobalObject()->proxyObjectStructure(), target, handler));
+}
+
+ConstructType ProxyConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructProxyObject;
+ return ConstructTypeHost;
+}
+
+static EncodedJSValue JSC_HOST_CALL callProxy(ExecState* exec)
+{
+ return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(exec, "Proxy"));
+}
+
+CallType ProxyConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callProxy;
+ return CallTypeHost;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ProxyConstructor.h b/Source/JavaScriptCore/runtime/ProxyConstructor.h
new file mode 100644
index 000000000..4f142a496
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ProxyConstructor.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.
+ */
+
+#ifndef ProxyConstructor_h
+#define ProxyConstructor_h
+
+#include "InternalFunction.h"
+
+namespace JSC {
+
+class ProxyConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+ static const unsigned StructureFlags = Base::StructureFlags;
+
+ static ProxyConstructor* create(VM&, Structure*);
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ void finishCreation(VM&, const char* name);
+
+private:
+ ProxyConstructor(VM&, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+
+ static EncodedJSValue getGetter(ExecState*, EncodedJSValue thisValue, PropertyName);
+};
+
+} // namespace JSC
+
+#endif // ProxyConstructor_h
diff --git a/Source/JavaScriptCore/runtime/ProxyObject.cpp b/Source/JavaScriptCore/runtime/ProxyObject.cpp
new file mode 100644
index 000000000..6ea856d73
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ProxyObject.cpp
@@ -0,0 +1,311 @@
+/*
+ * 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 "ProxyObject.h"
+
+#include "Error.h"
+#include "IdentifierInlines.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "ObjectConstructor.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ProxyObject);
+
+const ClassInfo ProxyObject::s_info = { "ProxyObject", &Base::s_info, 0, CREATE_METHOD_TABLE(ProxyObject) };
+
+ProxyObject::ProxyObject(VM& vm, Structure* structure)
+ : Base(vm, structure)
+{
+}
+
+void ProxyObject::finishCreation(VM& vm, ExecState* exec, JSValue target, JSValue handler)
+{
+ Base::finishCreation(vm);
+ if (!target.isObject()) {
+ throwTypeError(exec, ASCIILiteral("A Proxy's 'target' should be an Object"));
+ return;
+ }
+ if (ProxyObject* targetAsProxy = jsDynamicCast<ProxyObject*>(target)) {
+ // FIXME: Add tests for this once we implement Proxy.revoke(.).
+ // https://bugs.webkit.org/show_bug.cgi?id=154321
+ if (targetAsProxy->handler().isNull()) {
+ throwTypeError(exec, ASCIILiteral("If a Proxy's handler is another Proxy object, the other Proxy object must have a non-null handler."));
+ return;
+ }
+ }
+ if (!handler.isObject()) {
+ throwTypeError(exec, ASCIILiteral("A Proxy's 'handler' should be an Object"));
+ return;
+ }
+
+ m_target.set(vm, this, jsCast<JSObject*>(target));
+ m_handler.set(vm, this, handler);
+}
+
+static EncodedJSValue performProxyGet(ExecState* exec, EncodedJSValue thisValue, PropertyName propertyName)
+{
+ VM& vm = exec->vm();
+ JSObject* thisObject = jsCast<JSObject*>(JSValue::decode(thisValue)); // This might be a value where somewhere in __proto__ chain lives a ProxyObject.
+ JSObject* proxyObjectAsObject = thisObject;
+ // FIXME: make it so that custom getters take both the |this| value and the slotBase (property holder).
+ // https://bugs.webkit.org/show_bug.cgi?id=154320
+ while (true) {
+ if (LIKELY(proxyObjectAsObject->inherits(ProxyObject::info())))
+ break;
+
+ Structure& structure = *vm.heap.structureIDTable().get(proxyObjectAsObject->structureID());
+ JSValue prototype = structure.storedPrototype();
+ RELEASE_ASSERT(prototype.isObject());
+ proxyObjectAsObject = asObject(prototype);
+ }
+
+ ProxyObject* proxyObject = jsCast<ProxyObject*>(proxyObjectAsObject);
+ JSValue handlerValue = proxyObject->handler();
+ if (handlerValue.isNull())
+ return throwVMTypeError(exec, ASCIILiteral("Proxy 'handler' is null. It should be an Object."));
+
+ JSObject* handler = jsCast<JSObject*>(handlerValue);
+ CallData callData;
+ CallType callType;
+ JSValue getHandler = handler->getMethod(exec, callData, callType, vm.propertyNames->get, ASCIILiteral("'get' property of a Proxy's handler object should be callable."));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSObject* target = proxyObject->target();
+ if (getHandler.isUndefined())
+ return JSValue::encode(target->get(exec, propertyName));
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(target);
+ arguments.append(identifierToSafePublicJSValue(vm, Identifier::fromUid(&vm, propertyName.uid())));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ arguments.append(thisObject);
+ JSValue trapResult = call(exec, getHandler, callType, callData, handler, arguments);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ PropertyDescriptor descriptor;
+ if (target->getOwnPropertyDescriptor(exec, propertyName, descriptor)) {
+ if (descriptor.isDataDescriptor() && !descriptor.configurable() && !descriptor.writable()) {
+ if (!sameValue(exec, descriptor.value(), trapResult))
+ return throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'get' result of a non-configurable and non-writable property should be the same value as the target's property."));
+ } else if (descriptor.isAccessorDescriptor() && !descriptor.configurable() && descriptor.getter().isUndefined()) {
+ if (!trapResult.isUndefined())
+ return throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'get' result of a non-configurable accessor property without a getter should be undefined."));
+ }
+ }
+
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ return JSValue::encode(trapResult);
+}
+
+bool ProxyObject::performInternalMethodGetOwnProperty(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ VM& vm = exec->vm();
+ slot.setValue(this, None, jsUndefined()); // We do this to protect against any bad actors. Nobody should depend on this value.
+ JSValue handlerValue = this->handler();
+ if (handlerValue.isNull()) {
+ throwVMTypeError(exec, ASCIILiteral("Proxy 'handler' is null. It should be an Object."));
+ return false;
+ }
+
+ JSObject* handler = jsCast<JSObject*>(handlerValue);
+ CallData callData;
+ CallType callType;
+ JSValue getOwnPropertyDescriptorMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "getOwnPropertyDescriptor"), ASCIILiteral("'getOwnPropertyDescriptor' property of a Proxy's handler should be callable."));
+ if (exec->hadException())
+ return false;
+ JSObject* target = this->target();
+ if (getOwnPropertyDescriptorMethod.isUndefined())
+ return target->methodTable(vm)->getOwnPropertySlot(target, exec, propertyName, slot);
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(target);
+ arguments.append(identifierToSafePublicJSValue(vm, Identifier::fromUid(&vm, propertyName.uid())));
+ if (exec->hadException())
+ return false;
+ JSValue trapResult = call(exec, getOwnPropertyDescriptorMethod, callType, callData, handler, arguments);
+ if (exec->hadException())
+ return false;
+
+ if (!trapResult.isUndefined() && !trapResult.isObject()) {
+ throwVMTypeError(exec, ASCIILiteral("result of 'getOwnPropertyDescriptor' call should either be an Object or undefined."));
+ return false;
+ }
+
+ PropertyDescriptor targetPropertyDescriptor;
+ bool isTargetPropertyDescriptorDefined = target->getOwnPropertyDescriptor(exec, propertyName, targetPropertyDescriptor);
+ if (exec->hadException())
+ return false;
+
+ if (trapResult.isUndefined()) {
+ if (!isTargetPropertyDescriptorDefined)
+ return false;
+ if (!targetPropertyDescriptor.configurable()) {
+ throwVMTypeError(exec, ASCIILiteral("When the result of 'getOwnPropertyDescriptor' is undefined the target must be configurable."));
+ return false;
+ }
+ // FIXME: this doesn't work if 'target' is another Proxy. We don't have isExtensible implemented in a way that fits w/ Proxys.
+ // https://bugs.webkit.org/show_bug.cgi?id=154375
+ if (!target->isExtensible()) {
+ // FIXME: Come up with a test for this error. I'm not sure how to because
+ // Object.seal(o) will make all fields [[Configurable]] false.
+ // https://bugs.webkit.org/show_bug.cgi?id=154376
+ throwVMTypeError(exec, ASCIILiteral("When 'getOwnPropertyDescriptor' returns undefined, the 'target' of a Proxy should be extensible."));
+ return false;
+ }
+
+ return false;
+ }
+
+ PropertyDescriptor trapResultAsDescriptor;
+ toPropertyDescriptor(exec, trapResult, trapResultAsDescriptor);
+ if (exec->hadException())
+ return false;
+ bool throwException = false;
+ bool valid = validateAndApplyPropertyDescriptor(exec, nullptr, propertyName, target->isExtensible(),
+ trapResultAsDescriptor, isTargetPropertyDescriptorDefined, targetPropertyDescriptor, throwException);
+ if (!valid) {
+ throwVMTypeError(exec, ASCIILiteral("Result from 'getOwnPropertyDescriptor' fails the IsCompatiblePropertyDescriptor test."));
+ return false;
+ }
+
+ if (!trapResultAsDescriptor.configurable()) {
+ if (!isTargetPropertyDescriptorDefined || targetPropertyDescriptor.configurable()) {
+ throwVMTypeError(exec, ASCIILiteral("Result from 'getOwnPropertyDescriptor' can't be non-configurable when the 'target' doesn't have it as an own property or if it is a configurable own property on 'target'."));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ProxyObject::performHasProperty(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ VM& vm = exec->vm();
+ slot.setValue(this, None, jsUndefined()); // Nobody should rely on our value, but be safe and protect against any bad actors reading our value.
+
+ JSValue handlerValue = this->handler();
+ if (handlerValue.isNull()) {
+ throwVMTypeError(exec, ASCIILiteral("Proxy 'handler' is null. It should be an Object."));
+ return false;
+ }
+
+ JSObject* handler = jsCast<JSObject*>(handlerValue);
+ CallData callData;
+ CallType callType;
+ JSValue hasMethod = handler->getMethod(exec, callData, callType, vm.propertyNames->has, ASCIILiteral("'has' property of a Proxy's handler should be callable."));
+ if (exec->hadException())
+ return false;
+ JSObject* target = this->target();
+ if (hasMethod.isUndefined())
+ return target->methodTable(vm)->getOwnPropertySlot(target, exec, propertyName, slot);
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(target);
+ arguments.append(identifierToSafePublicJSValue(vm, Identifier::fromUid(&vm, propertyName.uid())));
+ if (exec->hadException())
+ return false;
+ JSValue trapResult = call(exec, hasMethod, callType, callData, handler, arguments);
+ if (exec->hadException())
+ return false;
+
+ bool trapResultAsBool = trapResult.toBoolean(exec);
+ if (exec->hadException())
+ return false;
+
+ if (!trapResultAsBool) {
+ PropertyDescriptor descriptor;
+ bool isPropertyDescriptorDefined = target->getOwnPropertyDescriptor(exec, propertyName, descriptor);
+ if (exec->hadException())
+ return false;
+ if (isPropertyDescriptorDefined) {
+ if (!descriptor.configurable()) {
+ throwVMTypeError(exec, ASCIILiteral("Proxy 'has' must return 'true' for non-configurable properties."));
+ return false;
+ }
+ if (!target->isExtensible()) {
+ throwVMTypeError(exec, ASCIILiteral("Proxy 'has' must return 'true' for a non-extensible 'target' object with a configurable property."));
+ return false;
+ }
+ }
+ }
+
+ return trapResultAsBool;
+}
+
+bool ProxyObject::getOwnPropertySlotCommon(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ slot.disableCaching();
+ switch (slot.internalMethodType()) {
+ case PropertySlot::InternalMethodType::Get:
+ slot.setCustom(this, CustomAccessor, performProxyGet);
+ return true;
+ case PropertySlot::InternalMethodType::GetOwnProperty:
+ return performInternalMethodGetOwnProperty(exec, propertyName, slot);
+ case PropertySlot::InternalMethodType::HasProperty:
+ return performHasProperty(exec, propertyName, slot);
+ default:
+ return false;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+ return false;
+}
+
+bool ProxyObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ ProxyObject* thisObject = jsCast<ProxyObject*>(object);
+ return thisObject->getOwnPropertySlotCommon(exec, propertyName, slot);
+}
+
+bool ProxyObject::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned propertyName, PropertySlot& slot)
+{
+ ProxyObject* thisObject = jsCast<ProxyObject*>(object);
+ Identifier ident = Identifier::from(exec, propertyName);
+ if (exec->hadException())
+ return false;
+ return thisObject->getOwnPropertySlotCommon(exec, ident.impl(), slot);
+}
+
+void ProxyObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_target);
+ visitor.append(&thisObject->m_handler);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ProxyObject.h b/Source/JavaScriptCore/runtime/ProxyObject.h
new file mode 100644
index 000000000..b9ae0abba
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ProxyObject.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef ProxyObject_h
+#define ProxyObject_h
+
+#include "JSGlobalObject.h"
+#include "JSObject.h"
+
+namespace JSC {
+
+class ProxyObject : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+
+ const static unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static ProxyObject* create(ExecState* exec, Structure* structure, JSValue target, JSValue handler)
+ {
+ VM& vm = exec->vm();
+ ProxyObject* proxy = new (NotNull, allocateCell<ProxyObject>(vm.heap)) ProxyObject(vm, structure);
+ proxy->finishCreation(vm, exec, target, handler);
+ return proxy;
+ }
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ DECLARE_EXPORT_INFO;
+
+ JSObject* target() { return m_target.get(); }
+ JSValue handler() { return m_handler.get(); }
+
+private:
+ ProxyObject(VM&, Structure*);
+ void finishCreation(VM&, ExecState*, JSValue target, JSValue handler);
+
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ bool getOwnPropertySlotCommon(ExecState*, PropertyName, PropertySlot&);
+ bool performInternalMethodGetOwnProperty(ExecState*, PropertyName, PropertySlot&);
+ bool performHasProperty(ExecState*, PropertyName, PropertySlot&);
+
+ WriteBarrier<JSObject> m_target;
+ WriteBarrier<Unknown> m_handler;
+};
+
+} // namespace JSC
+
+#endif // JSPromise_h
diff --git a/Source/JavaScriptCore/runtime/PureNaN.h b/Source/JavaScriptCore/runtime/PureNaN.h
new file mode 100644
index 000000000..a236d09e1
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/PureNaN.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef PureNaN_h
+#define PureNaN_h
+
+#include <wtf/Assertions.h>
+#include <wtf/StdLibExtras.h>
+
+namespace JSC {
+
+// NaN (not-a-number) double values are central to how JavaScriptCore encodes JavaScript
+// values (JSValues). All values, including integers and non-numeric values, are always
+// encoded using the IEEE 854 binary double format. Non-double values are encoded using
+// a NaN with the sign bit set. The 51-bit payload is then used for encoding the actual
+// value - be it an integer or a pointer to an object, or something else. But we only
+// make use of the low 49 bits and the top 15 bits being all set to 1 is the indicator
+// that a value is not a double. Top 15 bits being set to 1 also indicate a signed
+// signaling NaN with some additional NaN payload bits.
+//
+// Our use of NaN encoding means that we have to be careful with how we use NaNs for
+// ordinary doubles. For example, it would be wrong to ever use a NaN that has the top
+// 15 bits set, as that would look like a non-double value to JSC.
+//
+// We can trust that on all of the hardware/OS combinations that we care about,
+// NaN-producing math operations never produce a NaN that looks like a tagged value. But
+// if we're ever in a situation where we worry about it, we can use purifyNaN() to get a
+// NaN that doesn't look like a tagged non-double value. The JavaScript language doesn't
+// distinguish between different flavors of NaN and there is no way to detect what kind
+// of NaN you have - hence so long as all double NaNs are purified then our tagging
+// scheme remains sound.
+//
+// It's worth noting that there are cases, like sin(), that will almost produce a NaN
+// that breaks us. sin(-inf) returns 0xfff8000000000000. This doesn't break us because
+// not all of the top 15 bits are set. But it's very close. Hence our assumptions about
+// NaN are just about the most aggressive assumptions we could possibly make without
+// having to call purifyNaN() in surprising places.
+//
+// For naming purposes, we say that a NaN is "pure" if it is safe to tag, in the sense
+// that doing so would result in a tagged value that would pass the "are you a double"
+// test. We say that a NaN is "impure" if attempting to tag it would result in a value
+// that would look like something other than a double.
+
+// Returns some kind of pure NaN.
+inline double pureNaN()
+{
+ // Be sure that we return exactly the kind of NaN that is safe. We engineer the bits
+ // ourselves to ensure that it's !isImpureNaN(). FWIW, this is what
+ // numeric_limits<double>::quiet_NaN() returns on Mac/X86_64. But AFAICT there is
+ // no guarantee that quiet_NaN would return a pureNaN on all platforms. For example,
+ // the docs appear to imply that quiet_NaN could even return a double with the
+ // signaling bit set on hardware that doesn't do signaling. That would probably
+ // never happen, but it's healthy to be paranoid.
+ return bitwise_cast<double>(0x7ff8000000000000ll);
+}
+
+#define PNaN (pureNaN())
+
+inline bool isImpureNaN(double value)
+{
+ // Tests if the double value would break JSVALUE64 encoding, which is the most
+ // aggressive kind of encoding that we currently use.
+ return bitwise_cast<uint64_t>(value) >= 0xfffe000000000000llu;
+}
+
+// If the given value is NaN then return a NaN that is known to be pure.
+inline double purifyNaN(double value)
+{
+ if (value != value)
+ return PNaN;
+ return value;
+}
+
+} // namespace JSC
+
+#endif // PureNaN_h
diff --git a/Source/JavaScriptCore/runtime/PutPropertySlot.h b/Source/JavaScriptCore/runtime/PutPropertySlot.h
index 2004b451a..5d10b8290 100644
--- a/Source/JavaScriptCore/runtime/PutPropertySlot.h
+++ b/Source/JavaScriptCore/runtime/PutPropertySlot.h
@@ -1,6 +1,5 @@
-// -*- mode: c++; c-basic-offset: 4 -*-
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-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
@@ -11,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
@@ -28,75 +27,107 @@
#define PutPropertySlot_h
#include "JSCJSValue.h"
+#include "PropertyOffset.h"
#include <wtf/Assertions.h>
namespace JSC {
- class JSObject;
- class JSFunction;
+class JSObject;
+class JSFunction;
- class PutPropertySlot {
- public:
- enum Type { Uncachable, ExistingProperty, NewProperty, CustomProperty };
- enum Context { UnknownContext, PutById, PutByIdEval };
- typedef void (*PutValueFunc)(ExecState*, JSObject* base, EncodedJSValue thisObject, EncodedJSValue value);
-
- PutPropertySlot(JSValue thisValue, bool isStrictMode = false, Context context = UnknownContext)
- : m_type(Uncachable)
- , m_base(0)
- , m_thisValue(thisValue)
- , m_isStrictMode(isStrictMode)
- , m_context(context)
- , m_putFunction(nullptr)
- {
- }
-
- void setExistingProperty(JSObject* base, PropertyOffset offset)
- {
- m_type = ExistingProperty;
- m_base = base;
- m_offset = offset;
- }
-
- void setNewProperty(JSObject* base, PropertyOffset offset)
- {
- m_type = NewProperty;
- m_base = base;
- m_offset = offset;
- }
-
- void setCustomProperty(JSObject* base, PutValueFunc function)
- {
- m_type = CustomProperty;
- m_base = base;
- m_putFunction = function;
- }
-
- Context context() const { return static_cast<Context>(m_context); }
-
- Type type() const { return m_type; }
- JSObject* base() const { return m_base; }
- JSValue thisValue() const { return m_thisValue; }
-
- bool isStrictMode() const { return m_isStrictMode; }
- bool isCacheable() const { return m_type != Uncachable && m_type != CustomProperty; }
- PropertyOffset cachedOffset() const
- {
- ASSERT(isCacheable());
- return m_offset;
- }
-
- private:
- Type m_type;
- JSObject* m_base;
- JSValue m_thisValue;
- PropertyOffset m_offset;
- bool m_isStrictMode;
- uint8_t m_context;
- PutValueFunc m_putFunction;
-
- };
+class PutPropertySlot {
+public:
+ enum Type { Uncachable, ExistingProperty, NewProperty, SetterProperty, CustomValue, CustomAccessor };
+ enum Context { UnknownContext, PutById, PutByIdEval };
+ typedef void (*PutValueFunc)(ExecState*, EncodedJSValue thisObject, EncodedJSValue value);
+
+ PutPropertySlot(JSValue thisValue, bool isStrictMode = false, Context context = UnknownContext, bool isInitialization = false)
+ : m_type(Uncachable)
+ , m_base(0)
+ , m_thisValue(thisValue)
+ , m_offset(invalidOffset)
+ , m_isStrictMode(isStrictMode)
+ , m_isInitialization(isInitialization)
+ , m_context(context)
+ , m_putFunction(nullptr)
+ {
+ }
+
+ void setExistingProperty(JSObject* base, PropertyOffset offset)
+ {
+ m_type = ExistingProperty;
+ m_base = base;
+ m_offset = offset;
+ }
+
+ void setNewProperty(JSObject* base, PropertyOffset offset)
+ {
+ m_type = NewProperty;
+ m_base = base;
+ m_offset = offset;
+ }
+
+ void setCustomValue(JSObject* base, PutValueFunc function)
+ {
+ m_type = CustomValue;
+ m_base = base;
+ m_putFunction = function;
+ }
+
+ void setCustomAccessor(JSObject* base, PutValueFunc function)
+ {
+ m_type = CustomAccessor;
+ m_base = base;
+ m_putFunction = function;
+ }
+
+ void setCacheableSetter(JSObject* base, PropertyOffset offset)
+ {
+ m_type = SetterProperty;
+ m_base = base;
+ m_offset = offset;
+ }
+
+ void setThisValue(JSValue thisValue)
+ {
+ m_thisValue = thisValue;
+ }
+
+ PutValueFunc customSetter() const
+ {
+ ASSERT(isCacheableCustom());
+ return m_putFunction;
+ }
+
+ Context context() const { return static_cast<Context>(m_context); }
+
+ Type type() const { return m_type; }
+ JSObject* base() const { return m_base; }
+ JSValue thisValue() const { return m_thisValue; }
+
+ bool isStrictMode() const { return m_isStrictMode; }
+ bool isCacheablePut() const { return m_type == NewProperty || m_type == ExistingProperty; }
+ bool isCacheableSetter() const { return m_type == SetterProperty; }
+ bool isCacheableCustom() const { return m_type == CustomValue || m_type == CustomAccessor; }
+ bool isCustomAccessor() const { return m_type == CustomAccessor; }
+ bool isInitialization() const { return m_isInitialization; }
+
+ PropertyOffset cachedOffset() const
+ {
+ return m_offset;
+ }
+
+private:
+ Type m_type;
+ JSObject* m_base;
+ JSValue m_thisValue;
+ PropertyOffset m_offset;
+ bool m_isStrictMode;
+ bool m_isInitialization;
+ uint8_t m_context;
+ PutValueFunc m_putFunction;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ReflectObject.cpp b/Source/JavaScriptCore/runtime/ReflectObject.cpp
new file mode 100644
index 000000000..df7206bc9
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ReflectObject.cpp
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "ReflectObject.h"
+
+#include "JSCInlines.h"
+#include "JSGlobalObjectFunctions.h"
+#include "JSPropertyNameIterator.h"
+#include "Lookup.h"
+#include "ObjectConstructor.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL reflectObjectDefineProperty(ExecState*);
+static EncodedJSValue JSC_HOST_CALL reflectObjectEnumerate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL reflectObjectGet(ExecState*);
+static EncodedJSValue JSC_HOST_CALL reflectObjectGetOwnPropertyDescriptor(ExecState*);
+static EncodedJSValue JSC_HOST_CALL reflectObjectGetPrototypeOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL reflectObjectIsExtensible(ExecState*);
+static EncodedJSValue JSC_HOST_CALL reflectObjectOwnKeys(ExecState*);
+static EncodedJSValue JSC_HOST_CALL reflectObjectPreventExtensions(ExecState*);
+static EncodedJSValue JSC_HOST_CALL reflectObjectSetPrototypeOf(ExecState*);
+
+}
+
+#include "ReflectObject.lut.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ReflectObject);
+
+const ClassInfo ReflectObject::s_info = { "Reflect", &Base::s_info, &reflectObjectTable, CREATE_METHOD_TABLE(ReflectObject) };
+
+/* Source for ReflectObject.lut.h
+@begin reflectObjectTable
+ apply JSBuiltin DontEnum|Function 3
+ defineProperty reflectObjectDefineProperty DontEnum|Function 3
+ deleteProperty JSBuiltin DontEnum|Function 2
+ enumerate reflectObjectEnumerate DontEnum|Function 1
+ get reflectObjectGet DontEnum|Function 2
+ getOwnPropertyDescriptor reflectObjectGetOwnPropertyDescriptor DontEnum|Function 2
+ getPrototypeOf reflectObjectGetPrototypeOf DontEnum|Function 1
+ has JSBuiltin DontEnum|Function 2
+ isExtensible reflectObjectIsExtensible DontEnum|Function 1
+ ownKeys reflectObjectOwnKeys DontEnum|Function 1
+ preventExtensions reflectObjectPreventExtensions DontEnum|Function 1
+ setPrototypeOf reflectObjectSetPrototypeOf DontEnum|Function 2
+@end
+*/
+
+ReflectObject::ReflectObject(VM& vm, Structure* structure)
+ : JSNonFinalObject(vm, structure)
+{
+}
+
+void ReflectObject::finishCreation(VM& vm, JSGlobalObject*)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+}
+
+bool ReflectObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<Base>(exec, reflectObjectTable, jsCast<ReflectObject*>(object), propertyName, slot);
+}
+
+// ------------------------------ Functions --------------------------------
+
+// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.defineproperty
+EncodedJSValue JSC_HOST_CALL reflectObjectDefineProperty(ExecState* exec)
+{
+ JSValue target = exec->argument(0);
+ if (!target.isObject())
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.defineProperty requires the first argument be an object")));
+ auto propertyName = exec->argument(1).toPropertyKey(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ PropertyDescriptor descriptor;
+ if (!toPropertyDescriptor(exec, exec->argument(2), descriptor))
+ return JSValue::encode(jsUndefined());
+ ASSERT((descriptor.attributes() & Accessor) || (!descriptor.isAccessorDescriptor()));
+ ASSERT(!exec->hadException());
+
+ // Reflect.defineProperty should not throw an error when the defineOwnProperty operation fails.
+ bool shouldThrow = false;
+ JSObject* targetObject = asObject(target);
+ return JSValue::encode(jsBoolean(targetObject->methodTable(exec->vm())->defineOwnProperty(targetObject, exec, propertyName, descriptor, shouldThrow)));
+}
+
+// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.enumerate
+EncodedJSValue JSC_HOST_CALL reflectObjectEnumerate(ExecState* exec)
+{
+ JSValue target = exec->argument(0);
+ if (!target.isObject())
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.enumerate requires the first argument be an object")));
+ return JSValue::encode(JSPropertyNameIterator::create(exec, exec->lexicalGlobalObject()->propertyNameIteratorStructure(), asObject(target)));
+}
+
+// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.get
+EncodedJSValue JSC_HOST_CALL reflectObjectGet(ExecState* exec)
+{
+ JSValue target = exec->argument(0);
+ if (!target.isObject())
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.get requires the first argument be an object")));
+
+ const Identifier propertyName = exec->argument(1).toPropertyKey(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+
+ JSValue receiver = target;
+ if (exec->argumentCount() >= 3)
+ receiver = exec->argument(2);
+
+ PropertySlot slot(receiver, PropertySlot::InternalMethodType::Get);
+ return JSValue::encode(target.get(exec, propertyName, slot));
+}
+
+// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.getownpropertydescriptor
+EncodedJSValue JSC_HOST_CALL reflectObjectGetOwnPropertyDescriptor(ExecState* exec)
+{
+ JSValue target = exec->argument(0);
+ if (!target.isObject())
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.getOwnPropertyDescriptor requires the first argument be an object")));
+
+ auto key = exec->argument(1).toPropertyKey(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ return JSValue::encode(objectConstructorGetOwnPropertyDescriptor(exec, asObject(target), key));
+}
+
+// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.getprototypeof
+EncodedJSValue JSC_HOST_CALL reflectObjectGetPrototypeOf(ExecState* exec)
+{
+ JSValue target = exec->argument(0);
+ if (!target.isObject())
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.getPrototypeOf requires the first argument be an object")));
+ return JSValue::encode(objectConstructorGetPrototypeOf(exec, asObject(target)));
+}
+
+// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.isextensible
+EncodedJSValue JSC_HOST_CALL reflectObjectIsExtensible(ExecState* exec)
+{
+ JSValue target = exec->argument(0);
+ if (!target.isObject())
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.isExtensible requires the first argument be an object")));
+ return JSValue::encode(jsBoolean(asObject(target)->isExtensible()));
+}
+
+// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.ownkeys
+EncodedJSValue JSC_HOST_CALL reflectObjectOwnKeys(ExecState* exec)
+{
+ JSValue target = exec->argument(0);
+ if (!target.isObject())
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.ownKeys requires the first argument be an object")));
+ return JSValue::encode(ownPropertyKeys(exec, jsCast<JSObject*>(target), PropertyNameMode::StringsAndSymbols, DontEnumPropertiesMode::Include));
+}
+
+// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.preventextensions
+EncodedJSValue JSC_HOST_CALL reflectObjectPreventExtensions(ExecState* exec)
+{
+ JSValue target = exec->argument(0);
+ if (!target.isObject())
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.preventExtensions requires the first argument be an object")));
+ asObject(target)->preventExtensions(exec->vm());
+ return JSValue::encode(jsBoolean(true));
+}
+
+// http://www.ecma-international.org/ecma-262/6.0/#sec-reflect.setprototypeof
+EncodedJSValue JSC_HOST_CALL reflectObjectSetPrototypeOf(ExecState* exec)
+{
+ JSValue target = exec->argument(0);
+ if (!target.isObject())
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.setPrototypeOf requires the first argument be an object")));
+ JSValue proto = exec->argument(1);
+ if (!proto.isObject() && !proto.isNull())
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.setPrototypeOf requires the second argument be either an object or null")));
+
+ JSObject* object = asObject(target);
+
+ if (!checkProtoSetterAccessAllowed(exec, object))
+ return JSValue::encode(jsBoolean(false));
+
+ if (object->prototype() == proto)
+ return JSValue::encode(jsBoolean(true));
+
+ if (!object->isExtensible())
+ return JSValue::encode(jsBoolean(false));
+
+ return JSValue::encode(jsBoolean(object->setPrototypeWithCycleCheck(exec, proto)));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ReflectObject.h b/Source/JavaScriptCore/runtime/ReflectObject.h
new file mode 100644
index 000000000..6a7350229
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ReflectObject.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#ifndef ReflectObject_h
+#define ReflectObject_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class ReflectObject : public JSNonFinalObject {
+private:
+ ReflectObject(VM&, Structure*);
+
+public:
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static ReflectObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+ {
+ ReflectObject* object = new (NotNull, allocateCell<ReflectObject>(vm.heap)) ReflectObject(vm, structure);
+ object->finishCreation(vm, globalObject);
+ return object;
+ }
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+
+protected:
+ void finishCreation(VM&, JSGlobalObject*);
+};
+
+} // namespace JSC
+
+#endif // ReflectObject_h
diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp
index 30c105d29..26750b3c7 100644
--- a/Source/JavaScriptCore/runtime/RegExp.cpp
+++ b/Source/JavaScriptCore/runtime/RegExp.cpp
@@ -24,7 +24,7 @@
#include "RegExp.h"
#include "Lexer.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "RegExpCache.h"
#include "Yarr.h"
#include "YarrJIT.h"
@@ -40,7 +40,7 @@
namespace JSC {
-const ClassInfo RegExp::s_info = { "RegExp", 0, 0, 0, CREATE_METHOD_TABLE(RegExp) };
+const ClassInfo RegExp::s_info = { "RegExp", 0, 0, CREATE_METHOD_TABLE(RegExp) };
RegExpFlags regExpFlags(const String& string)
{
@@ -113,7 +113,7 @@ RegExpFunctionalTestCollector* RegExpFunctionalTestCollector::get()
return s_instance;
}
-void RegExpFunctionalTestCollector::outputOneTest(RegExp* regExp, String s, int startOffset, int* ovector, int result)
+void RegExpFunctionalTestCollector::outputOneTest(RegExp* regExp, const String& s, int startOffset, int* ovector, int result)
{
if ((!m_lastRegExp) || (m_lastRegExp != regExp)) {
m_lastRegExp = regExp;
@@ -227,6 +227,10 @@ RegExp::RegExp(VM& vm, const String& patternString, RegExpFlags flags)
, m_constructionError(0)
, m_numSubpatterns(0)
#if ENABLE(REGEXP_TRACING)
+ , m_rtMatchOnlyTotalSubjectStringLen(0.0)
+ , m_rtMatchTotalSubjectStringLen(0.0)
+ , m_rtMatchOnlyCallCount(0)
+ , m_rtMatchOnlyFoundCount(0)
, m_rtMatchCallCount(0)
, m_rtMatchFoundCount(0)
#endif
@@ -252,6 +256,16 @@ void RegExp::destroy(JSCell* cell)
thisObject->RegExp::~RegExp();
}
+size_t RegExp::estimatedSize(JSCell* cell)
+{
+ RegExp* thisObject = static_cast<RegExp*>(cell);
+ size_t regexDataSize = thisObject->m_regExpBytecode ? thisObject->m_regExpBytecode->estimatedSizeInBytes() : 0;
+#if ENABLE(YARR_JIT)
+ regexDataSize += thisObject->m_regExpJITCode.size();
+#endif
+ return Base::estimatedSize(cell) + regexDataSize;
+}
+
RegExp* RegExp::createWithoutCaching(VM& vm, const String& patternString, RegExpFlags flags)
{
RegExp* regExp = new (NotNull, allocateCell<RegExp>(vm.heap)) RegExp(vm, patternString, flags);
@@ -269,8 +283,10 @@ void RegExp::compile(VM* vm, Yarr::YarrCharSize charSize)
Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
if (m_constructionError) {
RELEASE_ASSERT_NOT_REACHED();
+#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
m_state = ParseError;
return;
+#endif
}
ASSERT(m_numSubpatterns == pattern.m_numSubpatterns);
@@ -281,24 +297,18 @@ void RegExp::compile(VM* vm, Yarr::YarrCharSize charSize)
}
#if ENABLE(YARR_JIT)
- if (!pattern.m_containsBackreferences && vm->canUseRegExpJIT()) {
+ if (!pattern.m_containsBackreferences && !pattern.containsUnsignedLengthPattern() && vm->canUseRegExpJIT()) {
Yarr::jitCompile(pattern, charSize, vm, m_regExpJITCode);
-#if ENABLE(YARR_JIT_DEBUG)
- if (!m_regExpJITCode.isFallBack())
- m_state = JITCode;
- else
- m_state = ByteCode;
-#else
if (!m_regExpJITCode.isFallBack()) {
m_state = JITCode;
return;
}
-#endif
}
#else
UNUSED_PARAM(charSize);
#endif
+ m_state = ByteCode;
m_regExpBytecode = Yarr::byteCompile(pattern, &vm->m_regExpAllocator);
}
@@ -324,6 +334,7 @@ int RegExp::match(VM& vm, const String& s, unsigned startOffset, Vector<int, 32>
{
#if ENABLE(REGEXP_TRACING)
m_rtMatchCallCount++;
+ m_rtMatchTotalSubjectStringLen += (double)(s.length() - startOffset);
#endif
ASSERT(m_state != ParseError);
@@ -391,8 +402,10 @@ void RegExp::compileMatchOnly(VM* vm, Yarr::YarrCharSize charSize)
Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
if (m_constructionError) {
RELEASE_ASSERT_NOT_REACHED();
+#if COMPILER_QUIRK(CONSIDERS_UNREACHABLE_CODE)
m_state = ParseError;
return;
+#endif
}
ASSERT(m_numSubpatterns == pattern.m_numSubpatterns);
@@ -403,24 +416,18 @@ void RegExp::compileMatchOnly(VM* vm, Yarr::YarrCharSize charSize)
}
#if ENABLE(YARR_JIT)
- if (!pattern.m_containsBackreferences && vm->canUseRegExpJIT()) {
+ if (!pattern.m_containsBackreferences && !pattern.containsUnsignedLengthPattern() && vm->canUseRegExpJIT()) {
Yarr::jitCompile(pattern, charSize, vm, m_regExpJITCode, Yarr::MatchOnly);
-#if ENABLE(YARR_JIT_DEBUG)
- if (!m_regExpJITCode.isFallBack())
- m_state = JITCode;
- else
- m_state = ByteCode;
-#else
if (!m_regExpJITCode.isFallBack()) {
m_state = JITCode;
return;
}
-#endif
}
#else
UNUSED_PARAM(charSize);
#endif
+ m_state = ByteCode;
m_regExpBytecode = Yarr::byteCompile(pattern, &vm->m_regExpAllocator);
}
@@ -445,7 +452,8 @@ void RegExp::compileIfNecessaryMatchOnly(VM& vm, Yarr::YarrCharSize charSize)
MatchResult RegExp::match(VM& vm, const String& s, unsigned startOffset)
{
#if ENABLE(REGEXP_TRACING)
- m_rtMatchCallCount++;
+ m_rtMatchOnlyCallCount++;
+ m_rtMatchOnlyTotalSubjectStringLen += (double)(s.length() - startOffset);
#endif
ASSERT(m_state != ParseError);
@@ -458,7 +466,7 @@ MatchResult RegExp::match(VM& vm, const String& s, unsigned startOffset)
m_regExpJITCode.execute(s.characters16(), startOffset, s.length());
#if ENABLE(REGEXP_TRACING)
if (!result)
- m_rtMatchFoundCount++;
+ m_rtMatchOnlyFoundCount++;
#endif
return result;
}
@@ -476,7 +484,7 @@ MatchResult RegExp::match(VM& vm, const String& s, unsigned startOffset)
if (r >= 0) {
#if ENABLE(REGEXP_TRACING)
- m_rtMatchFoundCount++;
+ m_rtMatchOnlyFoundCount++;
#endif
return MatchResult(r, reinterpret_cast<unsigned*>(offsetVector)[1]);
}
@@ -484,7 +492,7 @@ MatchResult RegExp::match(VM& vm, const String& s, unsigned startOffset)
return MatchResult::failed();
}
-void RegExp::invalidateCode()
+void RegExp::deleteCode()
{
if (!hasCode())
return;
@@ -492,7 +500,7 @@ void RegExp::invalidateCode()
#if ENABLE(YARR_JIT)
m_regExpJITCode.clear();
#endif
- m_regExpBytecode.clear();
+ m_regExpBytecode = nullptr;
}
#if ENABLE(YARR_JIT_DEBUG)
@@ -563,16 +571,32 @@ void RegExp::matchCompareWithInterpreter(const String& s, int startOffset, int*
Yarr::YarrCodeBlock& codeBlock = m_regExpJITCode;
const size_t jitAddrSize = 20;
- char jitAddr[jitAddrSize];
- if (m_state == JITCode)
- snprintf(jitAddr, jitAddrSize, "fallback");
- else
- snprintf(jitAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.getAddr()));
+ char jit8BitMatchOnlyAddr[jitAddrSize];
+ char jit16BitMatchOnlyAddr[jitAddrSize];
+ char jit8BitMatchAddr[jitAddrSize];
+ char jit16BitMatchAddr[jitAddrSize];
+ if (m_state == ByteCode) {
+ snprintf(jit8BitMatchOnlyAddr, jitAddrSize, "fallback ");
+ snprintf(jit16BitMatchOnlyAddr, jitAddrSize, "---- ");
+ snprintf(jit8BitMatchAddr, jitAddrSize, "fallback ");
+ snprintf(jit16BitMatchAddr, jitAddrSize, "---- ");
+ } else {
+ snprintf(jit8BitMatchOnlyAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.get8BitMatchOnlyAddr()));
+ snprintf(jit16BitMatchOnlyAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.get16BitMatchOnlyAddr()));
+ snprintf(jit8BitMatchAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.get8BitMatchAddr()));
+ snprintf(jit16BitMatchAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.get16BitMatchAddr()));
+ }
#else
- const char* jitAddr = "JIT Off";
+ const char* jit8BitMatchOnlyAddr = "JIT Off";
+ const char* jit16BitMatchOnlyAddr = "";
+ const char* jit8BitMatchAddr = "JIT Off";
+ const char* jit16BitMatchAddr = "";
#endif
+ unsigned averageMatchOnlyStringLen = (unsigned)(m_rtMatchOnlyTotalSubjectStringLen / m_rtMatchOnlyCallCount);
+ unsigned averageMatchStringLen = (unsigned)(m_rtMatchTotalSubjectStringLen / m_rtMatchCallCount);
- printf("%-40.40s %16.16s %10d %10d\n", formattedPattern, jitAddr, m_rtMatchCallCount, m_rtMatchFoundCount);
+ printf("%-40.40s %16.16s %16.16s %10d %10d %10u\n", formattedPattern, jit8BitMatchOnlyAddr, jit16BitMatchOnlyAddr, m_rtMatchOnlyCallCount, m_rtMatchOnlyFoundCount, averageMatchOnlyStringLen);
+ printf(" %16.16s %16.16s %10d %10d %10u\n", jit8BitMatchAddr, jit16BitMatchAddr, m_rtMatchCallCount, m_rtMatchFoundCount, averageMatchStringLen);
}
#endif
diff --git a/Source/JavaScriptCore/runtime/RegExp.h b/Source/JavaScriptCore/runtime/RegExp.h
index d982ce4c3..3777fd5c1 100644
--- a/Source/JavaScriptCore/runtime/RegExp.h
+++ b/Source/JavaScriptCore/runtime/RegExp.h
@@ -37,93 +37,100 @@
namespace JSC {
- struct RegExpRepresentation;
- class VM;
+struct RegExpRepresentation;
+class VM;
- JS_EXPORT_PRIVATE RegExpFlags regExpFlags(const String&);
+JS_EXPORT_PRIVATE RegExpFlags regExpFlags(const String&);
- class RegExp : public JSCell {
- public:
- typedef JSCell Base;
+class RegExp final : public JSCell {
+public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
- JS_EXPORT_PRIVATE static RegExp* create(VM&, const String& pattern, RegExpFlags);
- static const bool needsDestruction = true;
- static const bool hasImmortalStructure = true;
- static void destroy(JSCell*);
+ JS_EXPORT_PRIVATE static RegExp* create(VM&, const String& pattern, RegExpFlags);
+ static const bool needsDestruction = true;
+ static void destroy(JSCell*);
+ static size_t estimatedSize(JSCell*);
- bool global() const { return m_flags & FlagGlobal; }
- bool ignoreCase() const { return m_flags & FlagIgnoreCase; }
- bool multiline() const { return m_flags & FlagMultiline; }
+ bool global() const { return m_flags & FlagGlobal; }
+ bool ignoreCase() const { return m_flags & FlagIgnoreCase; }
+ bool multiline() const { return m_flags & FlagMultiline; }
- const String& pattern() const { return m_patternString; }
+ const String& pattern() const { return m_patternString; }
- bool isValid() const { return !m_constructionError && m_flags != InvalidFlags; }
- const char* errorMessage() const { return m_constructionError; }
+ bool isValid() const { return !m_constructionError && m_flags != InvalidFlags; }
+ const char* errorMessage() const { return m_constructionError; }
- JS_EXPORT_PRIVATE int match(VM&, const String&, unsigned startOffset, Vector<int, 32>& ovector);
- MatchResult match(VM&, const String&, unsigned startOffset);
- unsigned numSubpatterns() const { return m_numSubpatterns; }
+ JS_EXPORT_PRIVATE int match(VM&, const String&, unsigned startOffset, Vector<int, 32>& ovector);
+ JS_EXPORT_PRIVATE MatchResult match(VM&, const String&, unsigned startOffset);
+ unsigned numSubpatterns() const { return m_numSubpatterns; }
- bool hasCode()
- {
- return m_state != NotCompiled;
- }
+ bool hasCode()
+ {
+ return m_state != NotCompiled;
+ }
+
+ void deleteCode();
- void invalidateCode();
-
#if ENABLE(REGEXP_TRACING)
- void printTraceData();
+ void printTraceData();
#endif
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(LeafType, 0), info());
- }
-
- DECLARE_INFO;
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+ }
+
+ DECLARE_INFO;
- RegExpKey key() { return RegExpKey(m_flags, m_patternString); }
+ RegExpKey key() { return RegExpKey(m_flags, m_patternString); }
- protected:
- void finishCreation(VM&);
+protected:
+ void finishCreation(VM&);
- private:
- friend class RegExpCache;
- RegExp(VM&, const String&, RegExpFlags);
+private:
+ friend class RegExpCache;
+ RegExp(VM&, const String&, RegExpFlags);
- static RegExp* createWithoutCaching(VM&, const String&, RegExpFlags);
+ static RegExp* createWithoutCaching(VM&, const String&, RegExpFlags);
- enum RegExpState {
- ParseError,
- JITCode,
- ByteCode,
- NotCompiled
- } m_state;
+ enum RegExpState {
+ ParseError,
+ JITCode,
+ ByteCode,
+ NotCompiled
+ };
- void compile(VM*, Yarr::YarrCharSize);
- void compileIfNecessary(VM&, Yarr::YarrCharSize);
+ RegExpState m_state;
- void compileMatchOnly(VM*, Yarr::YarrCharSize);
- void compileIfNecessaryMatchOnly(VM&, Yarr::YarrCharSize);
+ void compile(VM*, Yarr::YarrCharSize);
+ void compileIfNecessary(VM&, Yarr::YarrCharSize);
+
+ void compileMatchOnly(VM*, Yarr::YarrCharSize);
+ void compileIfNecessaryMatchOnly(VM&, Yarr::YarrCharSize);
#if ENABLE(YARR_JIT_DEBUG)
- void matchCompareWithInterpreter(const String&, int startOffset, int* offsetVector, int jitResult);
+ void matchCompareWithInterpreter(const String&, int startOffset, int* offsetVector, int jitResult);
#endif
- String m_patternString;
- RegExpFlags m_flags;
- const char* m_constructionError;
- unsigned m_numSubpatterns;
+ String m_patternString;
+ RegExpFlags m_flags;
+ const char* m_constructionError;
+ unsigned m_numSubpatterns;
#if ENABLE(REGEXP_TRACING)
- unsigned m_rtMatchCallCount;
- unsigned m_rtMatchFoundCount;
+ double m_rtMatchOnlyTotalSubjectStringLen;
+ double m_rtMatchTotalSubjectStringLen;
+ unsigned m_rtMatchOnlyCallCount;
+ unsigned m_rtMatchOnlyFoundCount;
+ unsigned m_rtMatchCallCount;
+ unsigned m_rtMatchFoundCount;
#endif
#if ENABLE(YARR_JIT)
- Yarr::YarrCodeBlock m_regExpJITCode;
+ Yarr::YarrCodeBlock m_regExpJITCode;
#endif
- OwnPtr<Yarr::BytecodePattern> m_regExpBytecode;
- };
+ std::unique_ptr<Yarr::BytecodePattern> m_regExpBytecode;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpCache.cpp b/Source/JavaScriptCore/runtime/RegExpCache.cpp
index 126004701..8f4660a78 100644
--- a/Source/JavaScriptCore/runtime/RegExpCache.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpCache.cpp
@@ -29,7 +29,7 @@
#include "config.h"
#include "RegExpCache.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "RegExpObject.h"
#include "StrongInlines.h"
@@ -60,7 +60,6 @@ void RegExpCache::finalize(Handle<Unknown> handle, void*)
{
RegExp* regExp = static_cast<RegExp*>(handle.get().asCell());
weakRemove(m_weakCache, regExp->key(), regExp);
- regExp->invalidateCode();
}
void RegExpCache::addToStrongCache(RegExp* regExp)
@@ -74,7 +73,7 @@ void RegExpCache::addToStrongCache(RegExp* regExp)
m_nextEntryInStrongCache = 0;
}
-void RegExpCache::invalidateCode()
+void RegExpCache::deleteAllCode()
{
for (int i = 0; i < maxStrongCacheableEntries; i++)
m_strongCache[i].clear();
@@ -85,7 +84,7 @@ void RegExpCache::invalidateCode()
RegExp* regExp = it->value.get();
if (!regExp) // Skip zombies.
continue;
- regExp->invalidateCode();
+ regExp->deleteCode();
}
}
diff --git a/Source/JavaScriptCore/runtime/RegExpCache.h b/Source/JavaScriptCore/runtime/RegExpCache.h
index d2bfdfef3..942f3dcb9 100644
--- a/Source/JavaScriptCore/runtime/RegExpCache.h
+++ b/Source/JavaScriptCore/runtime/RegExpCache.h
@@ -39,12 +39,14 @@
namespace JSC {
class RegExpCache : private WeakHandleOwner {
-friend class RegExp;
-typedef HashMap<RegExpKey, Weak<RegExp>> RegExpCacheMap;
+ WTF_MAKE_FAST_ALLOCATED;
+
+ friend class RegExp;
+ typedef HashMap<RegExpKey, Weak<RegExp>> RegExpCacheMap;
public:
RegExpCache(VM* vm);
- void invalidateCode();
+ void deleteAllCode();
private:
diff --git a/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp b/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp
index c54b4783d..e93061886 100644
--- a/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp
@@ -26,7 +26,7 @@
#include "config.h"
#include "RegExpCachedResult.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "RegExpMatchesArray.h"
namespace JSC {
@@ -37,23 +37,45 @@ void RegExpCachedResult::visitChildren(SlotVisitor& visitor)
visitor.append(&m_lastRegExp);
visitor.append(&m_reifiedInput);
visitor.append(&m_reifiedResult);
+ visitor.append(&m_reifiedLeftContext);
+ visitor.append(&m_reifiedRightContext);
}
-RegExpMatchesArray* RegExpCachedResult::lastResult(ExecState* exec, JSObject* owner)
+JSArray* RegExpCachedResult::lastResult(ExecState* exec, JSObject* owner)
{
- if (m_result) {
+ if (!m_reified) {
m_reifiedInput.set(exec->vm(), owner, m_lastInput.get());
- m_reifiedResult.set(exec->vm(), owner, RegExpMatchesArray::create(exec, m_lastInput.get(), m_lastRegExp.get(), m_result));
- m_result = MatchResult::failed();
+ m_reifiedResult.set(exec->vm(), owner, createRegExpMatchesArray(exec, m_lastInput.get(), m_lastRegExp.get(), m_result));
+ m_reified = true;
}
return m_reifiedResult.get();
}
+JSString* RegExpCachedResult::leftContext(ExecState* exec, JSObject* owner)
+{
+ // Make sure we're reified.
+ lastResult(exec, owner);
+ if (!m_reifiedLeftContext)
+ m_reifiedLeftContext.set(exec->vm(), owner, m_result.start ? jsSubstring(exec, m_reifiedInput.get(), 0, m_result.start) : jsEmptyString(exec));
+ return m_reifiedLeftContext.get();
+}
+
+JSString* RegExpCachedResult::rightContext(ExecState* exec, JSObject* owner)
+{
+ // Make sure we're reified.
+ lastResult(exec, owner);
+ if (!m_reifiedRightContext) {
+ unsigned length = m_reifiedInput->length();
+ m_reifiedRightContext.set(exec->vm(), owner, m_result.end != length ? jsSubstring(exec, m_reifiedInput.get(), m_result.end, length - m_result.end) : jsEmptyString(exec));
+ }
+ return m_reifiedRightContext.get();
+}
+
void RegExpCachedResult::setInput(ExecState* exec, JSObject* owner, JSString* input)
{
// Make sure we're reified, otherwise m_reifiedInput will be ignored.
lastResult(exec, owner);
- ASSERT(!m_result);
+ ASSERT(m_reified);
m_reifiedInput.set(exec->vm(), owner, input);
}
diff --git a/Source/JavaScriptCore/runtime/RegExpCachedResult.h b/Source/JavaScriptCore/runtime/RegExpCachedResult.h
index d2763bc77..bf6c0b864 100644
--- a/Source/JavaScriptCore/runtime/RegExpCachedResult.h
+++ b/Source/JavaScriptCore/runtime/RegExpCachedResult.h
@@ -30,54 +30,61 @@
namespace JSC {
- class JSString;
- class RegExpMatchesArray;
+class JSArray;
+class JSString;
- // RegExpCachedResult is used to track the cached results of the last
- // match, stores on the RegExp constructor (e.g. $&, $_, $1, $2 ...).
- // These values will be lazily generated on demand, so the cached result
- // may be in a lazy or reified state. A lazy state is indicated by a
- // value of m_result indicating a successful match, and a reified state
- // is indicated by setting m_result to MatchResult::failed().
- // Following a successful match, m_result, m_lastInput and m_lastRegExp
- // can be used to reify the results from the match, following reification
- // m_reifiedResult and m_reifiedInput hold the cached results.
- class RegExpCachedResult {
- public:
- RegExpCachedResult(VM& vm, JSObject* owner, RegExp* emptyRegExp)
- : m_result(0, 0)
- {
- m_lastInput.set(vm, owner, jsEmptyString(&vm));
- m_lastRegExp.set(vm, owner, emptyRegExp);
- }
+// RegExpCachedResult is used to track the cached results of the last
+// match, stores on the RegExp constructor (e.g. $&, $_, $1, $2 ...).
+// These values will be lazily generated on demand, so the cached result
+// may be in a lazy or reified state. A lazy state is indicated by a
+// value of m_result indicating a successful match, and a reified state
+// is indicated by setting m_result to MatchResult::failed().
+// Following a successful match, m_result, m_lastInput and m_lastRegExp
+// can be used to reify the results from the match, following reification
+// m_reifiedResult and m_reifiedInput hold the cached results.
+class RegExpCachedResult {
+public:
+ RegExpCachedResult(VM& vm, JSObject* owner, RegExp* emptyRegExp)
+ : m_result(0, 0)
+ , m_reified(false)
+ {
+ m_lastInput.set(vm, owner, jsEmptyString(&vm));
+ m_lastRegExp.set(vm, owner, emptyRegExp);
+ }
- ALWAYS_INLINE void record(VM& vm, JSObject* owner, RegExp* regExp, JSString* input, MatchResult result)
- {
- m_lastRegExp.set(vm, owner, regExp);
- m_lastInput.set(vm, owner, input);
- m_result = result;
- }
+ ALWAYS_INLINE void record(VM& vm, JSObject* owner, RegExp* regExp, JSString* input, MatchResult result)
+ {
+ m_lastRegExp.set(vm, owner, regExp);
+ m_lastInput.set(vm, owner, input);
+ m_reifiedLeftContext.clear();
+ m_reifiedRightContext.clear();
+ m_result = result;
+ m_reified = false;
+ }
- RegExpMatchesArray* lastResult(ExecState*, JSObject* owner);
- void setInput(ExecState*, JSObject* owner, JSString*);
+ JSArray* lastResult(ExecState*, JSObject* owner);
+ void setInput(ExecState*, JSObject* owner, JSString*);
- JSString* input()
- {
- // If m_result showas a match then we're in a lazy state, so m_lastInput
- // is the most recent value of the input property. If not then we have
- // reified, in which case m_reifiedInput will contain the correct value.
- return m_result ? m_lastInput.get() : m_reifiedInput.get();
- }
+ JSString* leftContext(ExecState*, JSObject* owner);
+ JSString* rightContext(ExecState*, JSObject* owner);
- void visitChildren(SlotVisitor&);
+ JSString* input()
+ {
+ return m_reified ? m_reifiedInput.get() : m_lastInput.get();
+ }
- private:
- MatchResult m_result;
- WriteBarrier<JSString> m_lastInput;
- WriteBarrier<RegExp> m_lastRegExp;
- WriteBarrier<RegExpMatchesArray> m_reifiedResult;
- WriteBarrier<JSString> m_reifiedInput;
- };
+ void visitChildren(SlotVisitor&);
+
+private:
+ MatchResult m_result;
+ bool m_reified;
+ WriteBarrier<JSString> m_lastInput;
+ WriteBarrier<RegExp> m_lastRegExp;
+ WriteBarrier<JSArray> m_reifiedResult;
+ WriteBarrier<JSString> m_reifiedInput;
+ WriteBarrier<JSString> m_reifiedLeftContext;
+ WriteBarrier<JSString> m_reifiedRightContext;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
index bc516b06d..ca9398a63 100644
--- a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2003, 2007, 2008, 2016 Apple Inc. All Rights Reserved.
* Copyright (C) 2009 Torch Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -23,30 +23,32 @@
#include "RegExpConstructor.h"
#include "Error.h"
-#include "Operations.h"
+#include "GetterSetter.h"
+#include "JSCInlines.h"
#include "RegExpMatchesArray.h"
#include "RegExpPrototype.h"
+#include "StructureInlines.h"
namespace JSC {
-static EncodedJSValue regExpConstructorInput(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorMultiline(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorLastMatch(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorLastParen(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorLeftContext(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorRightContext(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar1(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar2(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar3(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar4(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar5(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar6(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar7(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar8(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpConstructorDollar9(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-
-static void setRegExpConstructorInput(ExecState*, JSObject*, EncodedJSValue, EncodedJSValue);
-static void setRegExpConstructorMultiline(ExecState*, JSObject*, EncodedJSValue, EncodedJSValue);
+static EncodedJSValue regExpConstructorInput(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorMultiline(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorLastMatch(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorLastParen(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorLeftContext(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorRightContext(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorDollar1(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorDollar2(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorDollar3(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorDollar4(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorDollar5(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorDollar6(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorDollar7(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorDollar8(ExecState*, EncodedJSValue, PropertyName);
+static EncodedJSValue regExpConstructorDollar9(ExecState*, EncodedJSValue, PropertyName);
+
+static void setRegExpConstructorInput(ExecState*, EncodedJSValue, EncodedJSValue);
+static void setRegExpConstructorMultiline(ExecState*, EncodedJSValue, EncodedJSValue);
} // namespace JSC
@@ -54,7 +56,7 @@ static void setRegExpConstructorMultiline(ExecState*, JSObject*, EncodedJSValue,
namespace JSC {
-const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::regExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) };
+const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, &regExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) };
/* Source for RegExpConstructor.lut.h
@begin regExpConstructorTable
@@ -89,9 +91,9 @@ RegExpConstructor::RegExpConstructor(VM& vm, Structure* structure, RegExpPrototy
{
}
-void RegExpConstructor::finishCreation(VM& vm, RegExpPrototype* regExpPrototype)
+void RegExpConstructor::finishCreation(VM& vm, RegExpPrototype* regExpPrototype, GetterSetter* speciesSymbol)
{
- Base::finishCreation(vm, Identifier(&vm, "RegExp").string());
+ Base::finishCreation(vm, regExpPrototype->classInfo()->className);
ASSERT(inherits(info()));
// ECMA 15.10.5.1 RegExp.prototype
@@ -99,6 +101,8 @@ void RegExpConstructor::finishCreation(VM& vm, RegExpPrototype* regExpPrototype)
// no. of arguments for constructor
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(2), ReadOnly | DontDelete | DontEnum);
+
+ putDirectNonIndexAccessor(vm, vm.propertyNames->speciesSymbol, speciesSymbol, Accessor | ReadOnly | DontEnum);
}
void RegExpConstructor::destroy(JSCell* cell)
@@ -110,16 +114,13 @@ void RegExpConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
RegExpConstructor* thisObject = jsCast<RegExpConstructor*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
Base::visitChildren(thisObject, visitor);
thisObject->m_cachedResult.visitChildren(visitor);
}
JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i)
{
- RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this);
+ JSArray* array = m_cachedResult.lastResult(exec, this);
if (i < array->length()) {
JSValue result = JSValue(array).get(exec, i);
@@ -132,7 +133,7 @@ JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i)
JSValue RegExpConstructor::getLastParen(ExecState* exec)
{
- RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this);
+ JSArray* array = m_cachedResult.lastResult(exec, this);
unsigned length = array->length();
if (length > 1) {
JSValue result = JSValue(array).get(exec, length - 1);
@@ -145,113 +146,117 @@ JSValue RegExpConstructor::getLastParen(ExecState* exec)
JSValue RegExpConstructor::getLeftContext(ExecState* exec)
{
- return m_cachedResult.lastResult(exec, this)->leftContext(exec);
+ return m_cachedResult.leftContext(exec, this);
}
JSValue RegExpConstructor::getRightContext(ExecState* exec)
{
- return m_cachedResult.lastResult(exec, this)->rightContext(exec);
+ return m_cachedResult.rightContext(exec, this);
}
bool RegExpConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
- return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec->vm()), jsCast<RegExpConstructor*>(object), propertyName, slot);
-}
-
-static inline RegExpConstructor* asRegExpConstructor(EncodedJSValue value)
-{
- return jsCast<RegExpConstructor*>(JSValue::decode(value));
+ return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, regExpConstructorTable, jsCast<RegExpConstructor*>(object), propertyName, slot);
}
-EncodedJSValue regExpConstructorDollar1(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorDollar1(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 1));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getBackref(exec, 1));
}
-EncodedJSValue regExpConstructorDollar2(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorDollar2(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 2));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getBackref(exec, 2));
}
-EncodedJSValue regExpConstructorDollar3(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorDollar3(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 3));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getBackref(exec, 3));
}
-EncodedJSValue regExpConstructorDollar4(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorDollar4(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 4));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getBackref(exec, 4));
}
-EncodedJSValue regExpConstructorDollar5(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorDollar5(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 5));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getBackref(exec, 5));
}
-EncodedJSValue regExpConstructorDollar6(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorDollar6(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 6));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getBackref(exec, 6));
}
-EncodedJSValue regExpConstructorDollar7(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorDollar7(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 7));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getBackref(exec, 7));
}
-EncodedJSValue regExpConstructorDollar8(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorDollar8(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 8));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getBackref(exec, 8));
}
-EncodedJSValue regExpConstructorDollar9(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorDollar9(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 9));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getBackref(exec, 9));
}
-EncodedJSValue regExpConstructorInput(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorInput(ExecState*, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->input());
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->input());
}
-EncodedJSValue regExpConstructorMultiline(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorMultiline(ExecState*, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(jsBoolean(asRegExpConstructor(slotBase)->multiline()));
+ return JSValue::encode(jsBoolean(asRegExpConstructor(JSValue::decode(thisValue))->multiline()));
}
-EncodedJSValue regExpConstructorLastMatch(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorLastMatch(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getBackref(exec, 0));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getBackref(exec, 0));
}
-EncodedJSValue regExpConstructorLastParen(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorLastParen(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getLastParen(exec));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getLastParen(exec));
}
-EncodedJSValue regExpConstructorLeftContext(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorLeftContext(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getLeftContext(exec));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getLeftContext(exec));
}
-EncodedJSValue regExpConstructorRightContext(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+EncodedJSValue regExpConstructorRightContext(ExecState* exec, EncodedJSValue thisValue, PropertyName)
{
- return JSValue::encode(asRegExpConstructor(slotBase)->getRightContext(exec));
+ return JSValue::encode(asRegExpConstructor(JSValue::decode(thisValue))->getRightContext(exec));
}
-void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, EncodedJSValue, EncodedJSValue value)
+void setRegExpConstructorInput(ExecState* exec, EncodedJSValue thisValue, EncodedJSValue value)
{
- if (auto constructor = jsDynamicCast<RegExpConstructor*>(baseObject))
+ if (auto constructor = jsDynamicCast<RegExpConstructor*>(JSValue::decode(thisValue)))
constructor->setInput(exec, JSValue::decode(value).toString(exec));
}
-void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, EncodedJSValue, EncodedJSValue value)
+void setRegExpConstructorMultiline(ExecState* exec, EncodedJSValue thisValue, EncodedJSValue value)
{
- if (auto constructor = jsDynamicCast<RegExpConstructor*>(baseObject))
+ if (auto constructor = jsDynamicCast<RegExpConstructor*>(JSValue::decode(thisValue)))
constructor->setMultiline(JSValue::decode(value).toBoolean(exec));
}
+inline Structure* getRegExpStructure(ExecState* exec, JSGlobalObject* globalObject, JSValue newTarget)
+{
+ Structure* structure = globalObject->regExpStructure();
+ if (newTarget != jsUndefined()) {
+ structure = InternalFunction::createSubclassStructure(exec, newTarget, structure);
+ }
+ return structure;
+}
+
// ECMA 15.10.4
-JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, bool callAsConstructor)
+JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, JSValue newTarget)
{
JSValue arg0 = args.at(0);
JSValue arg1 = args.at(1);
@@ -260,9 +265,10 @@ JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const A
if (!arg1.isUndefined())
return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Cannot supply flags when constructing one RegExp from another.")));
// If called as a function, this just returns the first argument (see 15.10.3.1).
- if (callAsConstructor) {
+ if (newTarget != jsUndefined()) {
RegExp* regExp = static_cast<RegExpObject*>(asObject(arg0))->regExp();
- return RegExpObject::create(exec->vm(), globalObject->regExpStructure(), regExp);
+
+ return RegExpObject::create(exec->vm(), getRegExpStructure(exec, globalObject, newTarget), regExp);
}
return asObject(arg0);
}
@@ -284,13 +290,14 @@ JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const A
RegExp* regExp = RegExp::create(vm, pattern, flags);
if (!regExp->isValid())
return vm.throwException(exec, createSyntaxError(exec, regExp->errorMessage()));
- return RegExpObject::create(vm, globalObject->regExpStructure(), regExp);
+
+ return RegExpObject::create(vm, getRegExpStructure(exec, globalObject, newTarget), regExp);
}
static EncodedJSValue JSC_HOST_CALL constructWithRegExpConstructor(ExecState* exec)
{
ArgList args(exec);
- return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args, true));
+ return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args, exec->newTarget()));
}
ConstructType RegExpConstructor::getConstructData(JSCell*, ConstructData& constructData)
diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.h b/Source/JavaScriptCore/runtime/RegExpConstructor.h
index 9fa8ed8bf..7f253cafa 100644
--- a/Source/JavaScriptCore/runtime/RegExpConstructor.h
+++ b/Source/JavaScriptCore/runtime/RegExpConstructor.h
@@ -25,105 +25,104 @@
#include "RegExp.h"
#include "RegExpCachedResult.h"
#include "RegExpObject.h"
-#include <wtf/OwnPtr.h>
-
namespace JSC {
- class RegExpPrototype;
+class RegExpPrototype;
+class GetterSetter;
- class RegExpConstructor : public InternalFunction {
- public:
- typedef InternalFunction Base;
+class RegExpConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
- static RegExpConstructor* create(VM& vm, Structure* structure, RegExpPrototype* regExpPrototype)
- {
- RegExpConstructor* constructor = new (NotNull, allocateCell<RegExpConstructor>(vm.heap)) RegExpConstructor(vm, structure, regExpPrototype);
- constructor->finishCreation(vm, regExpPrototype);
- return constructor;
- }
+ static RegExpConstructor* create(VM& vm, Structure* structure, RegExpPrototype* regExpPrototype, GetterSetter* species)
+ {
+ RegExpConstructor* constructor = new (NotNull, allocateCell<RegExpConstructor>(vm.heap)) RegExpConstructor(vm, structure, regExpPrototype);
+ constructor->finishCreation(vm, regExpPrototype, species);
+ return constructor;
+ }
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- DECLARE_INFO;
+ DECLARE_INFO;
- MatchResult performMatch(VM&, RegExp*, JSString*, const String&, int startOffset, int** ovector);
- MatchResult performMatch(VM&, RegExp*, JSString*, const String&, int startOffset);
+ MatchResult performMatch(VM&, RegExp*, JSString*, const String&, int startOffset, int** ovector);
+ MatchResult performMatch(VM&, RegExp*, JSString*, const String&, int startOffset);
- void setMultiline(bool multiline) { m_multiline = multiline; }
- bool multiline() const { return m_multiline; }
+ void setMultiline(bool multiline) { m_multiline = multiline; }
+ bool multiline() const { return m_multiline; }
- JSValue getBackref(ExecState*, unsigned);
- JSValue getLastParen(ExecState*);
- JSValue getLeftContext(ExecState*);
- JSValue getRightContext(ExecState*);
+ JSValue getBackref(ExecState*, unsigned);
+ JSValue getLastParen(ExecState*);
+ JSValue getLeftContext(ExecState*);
+ JSValue getRightContext(ExecState*);
- void setInput(ExecState* exec, JSString* string) { m_cachedResult.setInput(exec, this, string); }
- JSString* input() { return m_cachedResult.input(); }
+ void setInput(ExecState* exec, JSString* string) { m_cachedResult.setInput(exec, this, string); }
+ JSString* input() { return m_cachedResult.input(); }
- static void visitChildren(JSCell*, SlotVisitor&);
+ static void visitChildren(JSCell*, SlotVisitor&);
- protected:
- void finishCreation(VM&, RegExpPrototype*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | Base::StructureFlags;
+protected:
+ void finishCreation(VM&, RegExpPrototype*, GetterSetter* species);
- private:
- RegExpConstructor(VM&, Structure*, RegExpPrototype*);
- static void destroy(JSCell*);
- static ConstructType getConstructData(JSCell*, ConstructData&);
- static CallType getCallData(JSCell*, CallData&);
+private:
+ RegExpConstructor(VM&, Structure*, RegExpPrototype*);
+ static void destroy(JSCell*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
- RegExpCachedResult m_cachedResult;
- bool m_multiline;
- Vector<int, 32> m_ovector;
- };
+ RegExpCachedResult m_cachedResult;
+ bool m_multiline;
+ Vector<int, 32> m_ovector;
+};
- RegExpConstructor* asRegExpConstructor(JSValue);
+RegExpConstructor* asRegExpConstructor(JSValue);
- JSObject* constructRegExp(ExecState*, JSGlobalObject*, const ArgList&, bool callAsConstructor = false);
+JSObject* constructRegExp(ExecState*, JSGlobalObject*, const ArgList&, JSValue newTarget = jsUndefined());
- inline RegExpConstructor* asRegExpConstructor(JSValue value)
- {
- ASSERT(asObject(value)->inherits(RegExpConstructor::info()));
- return static_cast<RegExpConstructor*>(asObject(value));
- }
+inline RegExpConstructor* asRegExpConstructor(JSValue value)
+{
+ ASSERT(asObject(value)->inherits(RegExpConstructor::info()));
+ return static_cast<RegExpConstructor*>(asObject(value));
+}
- /*
- To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular
- expression matching through the performMatch function. We use cached results to calculate,
- e.g., RegExp.lastMatch and RegExp.leftParen.
- */
- ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(VM& vm, RegExp* regExp, JSString* string, const String& input, int startOffset, int** ovector)
- {
- int position = regExp->match(vm, input, startOffset, m_ovector);
+/*
+ To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular
+ expression matching through the performMatch function. We use cached results to calculate,
+ e.g., RegExp.lastMatch and RegExp.leftParen.
+*/
+ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(VM& vm, RegExp* regExp, JSString* string, const String& input, int startOffset, int** ovector)
+{
+ int position = regExp->match(vm, input, startOffset, m_ovector);
- if (ovector)
- *ovector = m_ovector.data();
+ if (ovector)
+ *ovector = m_ovector.data();
- if (position == -1)
- return MatchResult::failed();
+ if (position == -1)
+ return MatchResult::failed();
- ASSERT(!m_ovector.isEmpty());
- ASSERT(m_ovector[0] == position);
- ASSERT(m_ovector[1] >= position);
- size_t end = m_ovector[1];
+ ASSERT(!m_ovector.isEmpty());
+ ASSERT(m_ovector[0] == position);
+ ASSERT(m_ovector[1] >= position);
+ size_t end = m_ovector[1];
- m_cachedResult.record(vm, this, regExp, string, MatchResult(position, end));
+ m_cachedResult.record(vm, this, regExp, string, MatchResult(position, end));
- return MatchResult(position, end);
- }
- ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(VM& vm, RegExp* regExp, JSString* string, const String& input, int startOffset)
- {
- MatchResult result = regExp->match(vm, input, startOffset);
- if (result)
- m_cachedResult.record(vm, this, regExp, string, result);
- return result;
- }
+ return MatchResult(position, end);
+}
+ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(VM& vm, RegExp* regExp, JSString* string, const String& input, int startOffset)
+{
+ MatchResult result = regExp->match(vm, input, startOffset);
+ if (result)
+ m_cachedResult.record(vm, this, regExp, string, result);
+ return result;
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
index 3eb462240..440cc9512 100644
--- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-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
@@ -27,98 +27,71 @@
#include "RegExpMatchesArray.h"
#include "ButterflyInlines.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
-const ClassInfo RegExpMatchesArray::s_info = {"Array", &JSArray::s_info, 0, 0, CREATE_METHOD_TABLE(RegExpMatchesArray)};
+static const PropertyOffset indexPropertyOffset = 100;
+static const PropertyOffset inputPropertyOffset = 101;
-RegExpMatchesArray::RegExpMatchesArray(VM& vm, Butterfly* butterfly, JSGlobalObject* globalObject, JSString* input, RegExp* regExp, MatchResult result)
- : JSArray(vm, globalObject->regExpMatchesArrayStructure(), butterfly)
- , m_result(result)
- , m_state(ReifiedNone)
+static JSArray* tryCreateUninitializedRegExpMatchesArray(VM& vm, Structure* structure, unsigned initialLength)
{
- m_input.set(vm, this, input);
- m_regExp.set(vm, this, regExp);
+ unsigned vectorLength = std::max(BASE_VECTOR_LEN, initialLength);
+ if (vectorLength > MAX_STORAGE_VECTOR_LENGTH)
+ return 0;
+
+ void* temp;
+ if (!vm.heap.tryAllocateStorage(0, Butterfly::totalSize(0, structure->outOfLineCapacity(), true, vectorLength * sizeof(EncodedJSValue)), &temp))
+ return 0;
+ Butterfly* butterfly = Butterfly::fromBase(temp, 0, structure->outOfLineCapacity());
+ butterfly->setVectorLength(vectorLength);
+ butterfly->setPublicLength(initialLength);
+
+ return JSArray::createWithButterfly(vm, structure, butterfly);
}
-RegExpMatchesArray* RegExpMatchesArray::create(ExecState* exec, JSString* input, RegExp* regExp, MatchResult result)
+JSArray* createRegExpMatchesArray(ExecState* exec, JSString* input, RegExp* regExp, MatchResult result)
{
ASSERT(result);
VM& vm = exec->vm();
- Butterfly* butterfly = createArrayButterfly(vm, 0, regExp->numSubpatterns() + 1);
- RegExpMatchesArray* array = new (NotNull, allocateCell<RegExpMatchesArray>(vm.heap)) RegExpMatchesArray(vm, butterfly, exec->lexicalGlobalObject(), input, regExp, result);
- array->finishCreation(vm);
- return array;
-}
-
-void RegExpMatchesArray::finishCreation(VM& vm)
-{
- Base::finishCreation(vm);
-}
+ JSArray* array = tryCreateUninitializedRegExpMatchesArray(vm, exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
+ RELEASE_ASSERT(array);
-void RegExpMatchesArray::visitChildren(JSCell* cell, SlotVisitor& visitor)
-{
- RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
- Base::visitChildren(thisObject, visitor);
- visitor.append(&thisObject->m_input);
- visitor.append(&thisObject->m_regExp);
-}
+ SamplingRegion samplingRegion("Reifying substring properties");
-void RegExpMatchesArray::reifyAllProperties(ExecState* exec)
-{
- ASSERT(m_state != ReifiedAll);
- ASSERT(m_result);
-
- reifyMatchPropertyIfNecessary(exec);
+ array->initializeIndex(vm, 0, jsSubstring(exec, input, result.start, result.end - result.start), ArrayWithContiguous);
- if (unsigned numSubpatterns = m_regExp->numSubpatterns()) {
+ if (unsigned numSubpatterns = regExp->numSubpatterns()) {
Vector<int, 32> subpatternResults;
- int position = m_regExp->match(exec->vm(), m_input->value(exec), m_result.start, subpatternResults);
- ASSERT_UNUSED(position, position >= 0 && static_cast<size_t>(position) == m_result.start);
- ASSERT(m_result.start == static_cast<size_t>(subpatternResults[0]));
- ASSERT(m_result.end == static_cast<size_t>(subpatternResults[1]));
+ int position = regExp->match(vm, input->value(exec), result.start, subpatternResults);
+ ASSERT_UNUSED(position, position >= 0 && static_cast<size_t>(position) == result.start);
+ ASSERT(result.start == static_cast<size_t>(subpatternResults[0]));
+ ASSERT(result.end == static_cast<size_t>(subpatternResults[1]));
for (unsigned i = 1; i <= numSubpatterns; ++i) {
int start = subpatternResults[2 * i];
if (start >= 0)
- putDirectIndex(exec, i, jsSubstring(exec, m_input.get(), start, subpatternResults[2 * i + 1] - start));
+ array->initializeIndex(vm, i, jsSubstring(exec, input, start, subpatternResults[2 * i + 1] - start), ArrayWithContiguous);
else
- putDirectIndex(exec, i, jsUndefined());
+ array->initializeIndex(vm, i, jsUndefined(), ArrayWithContiguous);
}
}
- putDirect(exec->vm(), exec->propertyNames().index, jsNumber(m_result.start));
- putDirect(exec->vm(), exec->propertyNames().input, m_input.get());
+ array->putDirect(vm, indexPropertyOffset, jsNumber(result.start));
+ array->putDirect(vm, inputPropertyOffset, input);
- m_state = ReifiedAll;
-}
-
-void RegExpMatchesArray::reifyMatchProperty(ExecState* exec)
-{
- ASSERT(m_state == ReifiedNone);
- ASSERT(m_result);
- putDirectIndex(exec, 0, jsSubstring(exec, m_input.get(), m_result.start, m_result.end - m_result.start));
- m_state = ReifiedMatch;
-}
-
-JSString* RegExpMatchesArray::leftContext(ExecState* exec)
-{
- if (!m_result.start)
- return jsEmptyString(exec);
- return jsSubstring(exec, m_input.get(), 0, m_result.start);
+ return array;
}
-JSString* RegExpMatchesArray::rightContext(ExecState* exec)
+Structure* createRegExpMatchesArrayStructure(VM& vm, JSGlobalObject& globalObject)
{
- unsigned length = m_input->length();
- if (m_result.end == length)
- return jsEmptyString(exec);
- return jsSubstring(exec, m_input.get(), m_result.end, length - m_result.end);
+ Structure* structure = globalObject.arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous);
+ PropertyOffset offset;
+ structure = structure->addPropertyTransition(vm, structure, vm.propertyNames->index, 0, offset);
+ ASSERT(offset == indexPropertyOffset);
+ structure = structure->addPropertyTransition(vm, structure, vm.propertyNames->input, 0, offset);
+ ASSERT(offset == inputPropertyOffset);
+ return structure;
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.h b/Source/JavaScriptCore/runtime/RegExpMatchesArray.h
index 67fdcb6e1..669dd39ed 100644
--- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.h
+++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.h
@@ -26,114 +26,8 @@
namespace JSC {
- class RegExpMatchesArray : public JSArray {
- private:
- RegExpMatchesArray(VM&, Butterfly*, JSGlobalObject*, JSString*, RegExp*, MatchResult);
-
- enum ReifiedState { ReifiedNone, ReifiedMatch, ReifiedAll };
-
- public:
- typedef JSArray Base;
-
- static RegExpMatchesArray* create(ExecState*, JSString*, RegExp*, MatchResult);
-
- JSString* leftContext(ExecState*);
- JSString* rightContext(ExecState*);
-
- DECLARE_INFO;
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), ArrayWithSlowPutArrayStorage);
- }
-
- static void visitChildren(JSCell*, SlotVisitor&);
-
- protected:
- void finishCreation(VM&);
-
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags;
-
- private:
- ALWAYS_INLINE void reifyAllPropertiesIfNecessary(ExecState* exec)
- {
- if (m_state != ReifiedAll)
- reifyAllProperties(exec);
- }
-
- ALWAYS_INLINE void reifyMatchPropertyIfNecessary(ExecState* exec)
- {
- if (m_state == ReifiedNone)
- reifyMatchProperty(exec);
- }
-
- static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
- {
- RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object);
- thisObject->reifyAllPropertiesIfNecessary(exec);
- return JSArray::getOwnPropertySlot(thisObject, exec, propertyName, slot);
- }
-
- static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned propertyName, PropertySlot& slot)
- {
- RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object);
- if (propertyName)
- thisObject->reifyAllPropertiesIfNecessary(exec);
- else
- thisObject->reifyMatchPropertyIfNecessary(exec);
- return JSArray::getOwnPropertySlotByIndex(thisObject, exec, propertyName, slot);
- }
-
- static void put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue v, PutPropertySlot& slot)
- {
- RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
- thisObject->reifyAllPropertiesIfNecessary(exec);
- JSArray::put(thisObject, exec, propertyName, v, slot);
- }
-
- static void putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue v, bool shouldThrow)
- {
- RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
- thisObject->reifyAllPropertiesIfNecessary(exec);
- JSArray::putByIndex(thisObject, exec, propertyName, v, shouldThrow);
- }
-
- static bool deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
- {
- RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
- thisObject->reifyAllPropertiesIfNecessary(exec);
- return JSArray::deleteProperty(thisObject, exec, propertyName);
- }
-
- static bool deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
- {
- RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
- thisObject->reifyAllPropertiesIfNecessary(exec);
- return JSArray::deletePropertyByIndex(thisObject, exec, propertyName);
- }
-
- static void getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& arr, EnumerationMode mode = ExcludeDontEnumProperties)
- {
- RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object);
- thisObject->reifyAllPropertiesIfNecessary(exec);
- JSArray::getOwnPropertyNames(thisObject, exec, arr, mode);
- }
-
- static bool defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
- {
- RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object);
- thisObject->reifyAllPropertiesIfNecessary(exec);
- return JSArray::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow);
- }
-
- void reifyAllProperties(ExecState*);
- void reifyMatchProperty(ExecState*);
-
- WriteBarrier<JSString> m_input;
- WriteBarrier<RegExp> m_regExp;
- MatchResult m_result;
- ReifiedState m_state;
-};
+JSArray* createRegExpMatchesArray(ExecState*, JSString*, RegExp*, MatchResult);
+Structure* createRegExpMatchesArrayStructure(VM&, JSGlobalObject&);
}
diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp
index f3b376c0d..d61ec74e9 100644
--- a/Source/JavaScriptCore/runtime/RegExpObject.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp
@@ -28,40 +28,18 @@
#include "JSArray.h"
#include "JSGlobalObject.h"
#include "JSString.h"
-#include "Lexer.h"
#include "Lookup.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "RegExpConstructor.h"
#include "RegExpMatchesArray.h"
#include "RegExpPrototype.h"
-#include <wtf/PassOwnPtr.h>
#include <wtf/text/StringBuilder.h>
namespace JSC {
-static EncodedJSValue regExpObjectGlobal(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpObjectIgnoreCase(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpObjectMultiline(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-static EncodedJSValue regExpObjectSource(ExecState*, EncodedJSValue, EncodedJSValue, PropertyName);
-
-} // namespace JSC
-
-#include "RegExpObject.lut.h"
-
-namespace JSC {
-
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(RegExpObject);
-const ClassInfo RegExpObject::s_info = { "RegExp", &Base::s_info, 0, ExecState::regExpTable, CREATE_METHOD_TABLE(RegExpObject) };
-
-/* Source for RegExpObject.lut.h
-@begin regExpTable
- global regExpObjectGlobal DontDelete|ReadOnly|DontEnum
- ignoreCase regExpObjectIgnoreCase DontDelete|ReadOnly|DontEnum
- multiline regExpObjectMultiline DontDelete|ReadOnly|DontEnum
- source regExpObjectSource DontDelete|ReadOnly|DontEnum
-@end
-*/
+const ClassInfo RegExpObject::s_info = { "RegExp", &Base::s_info, nullptr, CREATE_METHOD_TABLE(RegExpObject) };
RegExpObject::RegExpObject(VM& vm, Structure* structure, RegExp* regExp)
: JSNonFinalObject(vm, structure)
@@ -81,9 +59,6 @@ void RegExpObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
RegExpObject* thisObject = jsCast<RegExpObject*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
-
Base::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_regExp);
visitor.append(&thisObject->m_lastIndex);
@@ -97,7 +72,7 @@ bool RegExpObject::getOwnPropertySlot(JSObject* object, ExecState* exec, Propert
slot.setValue(regExp, attributes, regExp->getLastIndex());
return true;
}
- return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec->vm()), jsCast<RegExpObject*>(object), propertyName, slot);
+ return Base::getOwnPropertySlot(object, exec, propertyName, slot);
}
bool RegExpObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
@@ -109,18 +84,25 @@ bool RegExpObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName pr
void RegExpObject::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
- if (mode == IncludeDontEnumProperties)
+ if (mode.includeDontEnumProperties())
propertyNames.add(exec->propertyNames().lastIndex);
Base::getOwnNonIndexPropertyNames(object, exec, propertyNames, mode);
}
void RegExpObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
- if (mode == IncludeDontEnumProperties)
+ if (mode.includeDontEnumProperties())
propertyNames.add(exec->propertyNames().lastIndex);
Base::getPropertyNames(object, exec, propertyNames, mode);
}
+void RegExpObject::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ if (mode.includeDontEnumProperties())
+ propertyNames.add(exec->propertyNames().lastIndex);
+ Base::getGenericPropertyNames(object, exec, propertyNames, mode);
+}
+
static bool reject(ExecState* exec, bool throwException, const char* message)
{
if (throwException)
@@ -145,156 +127,33 @@ bool RegExpObject::defineOwnProperty(JSObject* object, ExecState* exec, Property
return reject(exec, shouldThrow, "Attempting to change value of a readonly property.");
return true;
}
- if (descriptor.writablePresent() && !descriptor.writable())
- regExp->m_lastIndexIsWritable = false;
if (descriptor.value())
regExp->setLastIndex(exec, descriptor.value(), false);
+ if (descriptor.writablePresent() && !descriptor.writable())
+ regExp->m_lastIndexIsWritable = false;
return true;
}
return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow);
}
-static inline RegExpObject* asRegExpObject(EncodedJSValue value)
-{
- return jsCast<RegExpObject*>(JSValue::decode(value));
-}
-
-EncodedJSValue regExpObjectGlobal(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
-{
- return JSValue::encode(jsBoolean(asRegExpObject(slotBase)->regExp()->global()));
-}
-
-EncodedJSValue regExpObjectIgnoreCase(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
-{
- return JSValue::encode(jsBoolean(asRegExpObject(slotBase)->regExp()->ignoreCase()));
-}
-
-EncodedJSValue regExpObjectMultiline(ExecState*, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
-{
- return JSValue::encode(jsBoolean(asRegExpObject(slotBase)->regExp()->multiline()));
-}
-
-template <typename CharacterType>
-static inline void appendLineTerminatorEscape(StringBuilder&, CharacterType);
-
-template <>
-inline void appendLineTerminatorEscape<LChar>(StringBuilder& builder, LChar lineTerminator)
-{
- if (lineTerminator == '\n')
- builder.append('n');
- else
- builder.append('r');
-}
-
-template <>
-inline void appendLineTerminatorEscape<UChar>(StringBuilder& builder, UChar lineTerminator)
+static void regExpObjectSetLastIndexStrict(ExecState* exec, EncodedJSValue thisValue, EncodedJSValue value)
{
- if (lineTerminator == '\n')
- builder.append('n');
- else if (lineTerminator == '\r')
- builder.append('r');
- else if (lineTerminator == 0x2028)
- builder.appendLiteral("u2028");
- else
- builder.appendLiteral("u2029");
-}
-
-template <typename CharacterType>
-static inline JSValue regExpObjectSourceInternal(ExecState* exec, String pattern, const CharacterType* characters, unsigned length)
-{
- bool previousCharacterWasBackslash = false;
- bool inBrackets = false;
- bool shouldEscape = false;
-
- // 15.10.6.4 specifies that RegExp.prototype.toString must return '/' + source + '/',
- // and also states that the result must be a valid RegularExpressionLiteral. '//' is
- // not a valid RegularExpressionLiteral (since it is a single line comment), and hence
- // source cannot ever validly be "". If the source is empty, return a different Pattern
- // that would match the same thing.
- if (!length)
- return jsNontrivialString(exec, ASCIILiteral("(?:)"));
-
- // early return for strings that don't contain a forwards slash and LineTerminator
- for (unsigned i = 0; i < length; ++i) {
- CharacterType ch = characters[i];
- if (!previousCharacterWasBackslash) {
- if (inBrackets) {
- if (ch == ']')
- inBrackets = false;
- } else {
- if (ch == '/') {
- shouldEscape = true;
- break;
- }
- if (ch == '[')
- inBrackets = true;
- }
- }
-
- if (Lexer<CharacterType>::isLineTerminator(ch)) {
- shouldEscape = true;
- break;
- }
-
- if (previousCharacterWasBackslash)
- previousCharacterWasBackslash = false;
- else
- previousCharacterWasBackslash = ch == '\\';
- }
-
- if (!shouldEscape)
- return jsString(exec, pattern);
-
- previousCharacterWasBackslash = false;
- inBrackets = false;
- StringBuilder result;
- for (unsigned i = 0; i < length; ++i) {
- CharacterType ch = characters[i];
- if (!previousCharacterWasBackslash) {
- if (inBrackets) {
- if (ch == ']')
- inBrackets = false;
- } else {
- if (ch == '/')
- result.append('\\');
- else if (ch == '[')
- inBrackets = true;
- }
- }
-
- // escape LineTerminator
- if (Lexer<CharacterType>::isLineTerminator(ch)) {
- if (!previousCharacterWasBackslash)
- result.append('\\');
-
- appendLineTerminatorEscape<CharacterType>(result, ch);
- } else
- result.append(ch);
-
- if (previousCharacterWasBackslash)
- previousCharacterWasBackslash = false;
- else
- previousCharacterWasBackslash = ch == '\\';
- }
-
- return jsString(exec, result.toString());
+ asRegExpObject(JSValue::decode(thisValue))->setLastIndex(exec, JSValue::decode(value), true);
}
-
-
-EncodedJSValue regExpObjectSource(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName)
+static void regExpObjectSetLastIndexNonStrict(ExecState* exec, EncodedJSValue thisValue, EncodedJSValue value)
{
- String pattern = asRegExpObject(slotBase)->regExp()->pattern();
- if (pattern.is8Bit())
- return JSValue::encode(regExpObjectSourceInternal(exec, pattern, pattern.characters8(), pattern.length()));
- return JSValue::encode(regExpObjectSourceInternal(exec, pattern, pattern.characters16(), pattern.length()));
+ asRegExpObject(JSValue::decode(thisValue))->setLastIndex(exec, JSValue::decode(value), false);
}
void RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
{
if (propertyName == exec->propertyNames().lastIndex) {
asRegExpObject(cell)->setLastIndex(exec, value, slot.isStrictMode());
+ slot.setCustomValue(asRegExpObject(cell), slot.isStrictMode()
+ ? regExpObjectSetLastIndexStrict
+ : regExpObjectSetLastIndexNonStrict);
return;
}
Base::put(cell, exec, propertyName, value, slot);
@@ -303,7 +162,7 @@ void RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName,
JSValue RegExpObject::exec(ExecState* exec, JSString* string)
{
if (MatchResult result = match(exec, string))
- return RegExpMatchesArray::create(exec, string, regExp(), result);
+ return createRegExpMatchesArray(exec, string, regExp(), result);
return jsNull();
}
diff --git a/Source/JavaScriptCore/runtime/RegExpObject.h b/Source/JavaScriptCore/runtime/RegExpObject.h
index 2b49ba2a4..1b44301bd 100644
--- a/Source/JavaScriptCore/runtime/RegExpObject.h
+++ b/Source/JavaScriptCore/runtime/RegExpObject.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2007, 2008, 2012 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2003, 2007, 2008, 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
@@ -26,81 +26,86 @@
namespace JSC {
- class RegExpObject : public JSNonFinalObject {
- public:
- typedef JSNonFinalObject Base;
-
- static RegExpObject* create(VM& vm, Structure* structure, RegExp* regExp)
- {
- RegExpObject* object = new (NotNull, allocateCell<RegExpObject>(vm.heap)) RegExpObject(vm, structure, regExp);
- object->finishCreation(vm);
- return object;
- }
+class RegExpObject : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames;
+
+ static RegExpObject* create(VM& vm, Structure* structure, RegExp* regExp)
+ {
+ RegExpObject* object = new (NotNull, allocateCell<RegExpObject>(vm.heap)) RegExpObject(vm, structure, regExp);
+ object->finishCreation(vm);
+ return object;
+ }
- void setRegExp(VM& vm, RegExp* r) { m_regExp.set(vm, this, r); }
- RegExp* regExp() const { return m_regExp.get(); }
+ void setRegExp(VM& vm, RegExp* r) { m_regExp.set(vm, this, r); }
+ RegExp* regExp() const { return m_regExp.get(); }
- void setLastIndex(ExecState* exec, size_t lastIndex)
- {
+ bool setLastIndex(ExecState* exec, size_t lastIndex)
+ {
+ if (LIKELY(m_lastIndexIsWritable)) {
m_lastIndex.setWithoutWriteBarrier(jsNumber(lastIndex));
- if (LIKELY(m_lastIndexIsWritable))
- m_lastIndex.setWithoutWriteBarrier(jsNumber(lastIndex));
- else
- throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
- }
- void setLastIndex(ExecState* exec, JSValue lastIndex, bool shouldThrow)
- {
- if (LIKELY(m_lastIndexIsWritable))
- m_lastIndex.set(exec->vm(), this, lastIndex);
- else if (shouldThrow)
- throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ return true;
}
- JSValue getLastIndex() const
- {
- return m_lastIndex.get();
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ return false;
+ }
+ bool setLastIndex(ExecState* exec, JSValue lastIndex, bool shouldThrow)
+ {
+ if (LIKELY(m_lastIndexIsWritable)) {
+ m_lastIndex.set(exec->vm(), this, lastIndex);
+ return true;
}
- bool test(ExecState* exec, JSString* string) { return match(exec, string); }
- JSValue exec(ExecState*, JSString*);
+ if (shouldThrow)
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ return false;
+ }
+ JSValue getLastIndex() const
+ {
+ return m_lastIndex.get();
+ }
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+ bool test(ExecState* exec, JSString* string) { return match(exec, string); }
+ JSValue exec(ExecState*, JSString*);
- DECLARE_EXPORT_INFO;
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
+ DECLARE_EXPORT_INFO;
- protected:
- JS_EXPORT_PRIVATE RegExpObject(VM&, Structure*, RegExp*);
- JS_EXPORT_PRIVATE void finishCreation(VM&);
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(RegExpObjectType, StructureFlags), info());
+ }
- static const unsigned StructureFlags = OverridesVisitChildren | OverridesGetOwnPropertySlot | Base::StructureFlags;
+protected:
+ JS_EXPORT_PRIVATE RegExpObject(VM&, Structure*, RegExp*);
+ JS_EXPORT_PRIVATE void finishCreation(VM&);
- static void visitChildren(JSCell*, SlotVisitor&);
+ static void visitChildren(JSCell*, SlotVisitor&);
- JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName);
- JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
- JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
- JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
+ JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName);
+ JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
- private:
- MatchResult match(ExecState*, JSString*);
+private:
+ MatchResult match(ExecState*, JSString*);
- WriteBarrier<RegExp> m_regExp;
- WriteBarrier<Unknown> m_lastIndex;
- bool m_lastIndexIsWritable;
- };
+ WriteBarrier<RegExp> m_regExp;
+ WriteBarrier<Unknown> m_lastIndex;
+ bool m_lastIndexIsWritable;
+};
- RegExpObject* asRegExpObject(JSValue);
+RegExpObject* asRegExpObject(JSValue);
- inline RegExpObject* asRegExpObject(JSValue value)
- {
- ASSERT(asObject(value)->inherits(RegExpObject::info()));
- return static_cast<RegExpObject*>(asObject(value));
- }
+inline RegExpObject* asRegExpObject(JSValue value)
+{
+ ASSERT(asObject(value)->inherits(RegExpObject::info()));
+ return static_cast<RegExpObject*>(asObject(value));
+}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
index 89d7ac1b8..83e38af33 100644
--- a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
@@ -29,11 +29,13 @@
#include "JSObject.h"
#include "JSString.h"
#include "JSStringBuilder.h"
+#include "Lexer.h"
#include "ObjectPrototype.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "RegExpObject.h"
#include "RegExp.h"
#include "RegExpCache.h"
+#include "RegExpConstructor.h"
#include "StringRecursionChecker.h"
namespace JSC {
@@ -42,6 +44,12 @@ static EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState*);
static EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState*);
static EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState*);
static EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL regExpProtoFuncSearch(ExecState*);
+static EncodedJSValue JSC_HOST_CALL regExpProtoGetterGlobal(ExecState*);
+static EncodedJSValue JSC_HOST_CALL regExpProtoGetterIgnoreCase(ExecState*);
+static EncodedJSValue JSC_HOST_CALL regExpProtoGetterMultiline(ExecState*);
+static EncodedJSValue JSC_HOST_CALL regExpProtoGetterSource(ExecState*);
+static EncodedJSValue JSC_HOST_CALL regExpProtoGetterFlags(ExecState*);
}
@@ -49,14 +57,19 @@ static EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*);
namespace JSC {
-const ClassInfo RegExpPrototype::s_info = { "RegExp", &RegExpObject::s_info, 0, ExecState::regExpPrototypeTable, CREATE_METHOD_TABLE(RegExpPrototype) };
+const ClassInfo RegExpPrototype::s_info = { "RegExp", &RegExpObject::s_info, &regExpPrototypeTable, CREATE_METHOD_TABLE(RegExpPrototype) };
/* Source for RegExpPrototype.lut.h
@begin regExpPrototypeTable
- compile regExpProtoFuncCompile DontEnum|Function 2
- exec regExpProtoFuncExec DontEnum|Function 1
- test regExpProtoFuncTest DontEnum|Function 1
- toString regExpProtoFuncToString DontEnum|Function 0
+ compile regExpProtoFuncCompile DontEnum|Function 2
+ exec regExpProtoFuncExec DontEnum|Function 1
+ test regExpProtoFuncTest DontEnum|Function 1
+ toString regExpProtoFuncToString DontEnum|Function 0
+ global regExpProtoGetterGlobal DontEnum|Accessor
+ ignoreCase regExpProtoGetterIgnoreCase DontEnum|Accessor
+ multiline regExpProtoGetterMultiline DontEnum|Accessor
+ source regExpProtoGetterSource DontEnum|Accessor
+ flags regExpProtoGetterFlags DontEnum|Accessor
@end
*/
@@ -65,32 +78,45 @@ RegExpPrototype::RegExpPrototype(VM& vm, Structure* structure, RegExp* regExp)
{
}
+void RegExpPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+ JSC_NATIVE_FUNCTION(vm.propertyNames->searchSymbol, regExpProtoFuncSearch, DontEnum, 1);
+}
+
bool RegExpPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
{
- return getStaticFunctionSlot<RegExpObject>(exec, ExecState::regExpPrototypeTable(exec->vm()), jsCast<RegExpPrototype*>(object), propertyName, slot);
+ return getStaticFunctionSlot<Base>(exec, regExpPrototypeTable, jsCast<RegExpPrototype*>(object), propertyName, slot);
}
// ------------------------------ Functions ---------------------------
EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(RegExpObject::info()))
return throwVMTypeError(exec);
- return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->test(exec, exec->argument(0).toString(exec))));
+ JSString* string = exec->argument(0).toStringOrNull(exec);
+ if (!string)
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->test(exec, string)));
}
EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(RegExpObject::info()))
return throwVMTypeError(exec);
- return JSValue::encode(asRegExpObject(thisValue)->exec(exec, exec->argument(0).toString(exec)));
+ JSString* string = exec->argument(0).toStringOrNull(exec);
+ if (!string)
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(asRegExpObject(thisValue)->exec(exec, string));
}
EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!thisValue.inherits(RegExpObject::info()))
return throwVMTypeError(exec);
@@ -126,29 +152,231 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec)
return JSValue::encode(jsUndefined());
}
+typedef std::array<char, 3 + 1> FlagsString; // 3 different flags and a null character terminator.
+
+static inline FlagsString flagsString(ExecState* exec, JSObject* regexp)
+{
+ FlagsString string;
+
+ JSValue globalValue = regexp->get(exec, exec->propertyNames().global);
+ if (exec->hadException())
+ return string;
+ JSValue ignoreCaseValue = regexp->get(exec, exec->propertyNames().ignoreCase);
+ if (exec->hadException())
+ return string;
+ JSValue multilineValue = regexp->get(exec, exec->propertyNames().multiline);
+
+ unsigned index = 0;
+ if (globalValue.toBoolean(exec))
+ string[index++] = 'g';
+ if (ignoreCaseValue.toBoolean(exec))
+ string[index++] = 'i';
+ if (multilineValue.toBoolean(exec))
+ string[index++] = 'm';
+ ASSERT(index < string.size());
+ string[index] = 0;
+ return string;
+}
+
EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
- if (!thisValue.inherits(RegExpObject::info()))
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
return throwVMTypeError(exec);
- RegExpObject* thisObject = asRegExpObject(thisValue);
+ JSObject* thisObject = asObject(thisValue);
StringRecursionChecker checker(exec, thisObject);
if (JSValue earlyReturnValue = checker.earlyReturnValue())
return JSValue::encode(earlyReturnValue);
- char postfix[5] = { '/', 0, 0, 0, 0 };
- int index = 1;
- if (thisObject->get(exec, exec->propertyNames().global).toBoolean(exec))
- postfix[index++] = 'g';
- if (thisObject->get(exec, exec->propertyNames().ignoreCase).toBoolean(exec))
- postfix[index++] = 'i';
- if (thisObject->get(exec, exec->propertyNames().multiline).toBoolean(exec))
- postfix[index] = 'm';
- String source = thisObject->get(exec, exec->propertyNames().source).toString(exec)->value(exec);
- // If source is empty, use "/(?:)/" to avoid colliding with comment syntax
- return JSValue::encode(jsMakeNontrivialString(exec, "/", source, postfix));
+ JSValue sourceValue = thisObject->get(exec, exec->propertyNames().source);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ String source = sourceValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ auto flags = flagsString(exec, thisObject);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ return JSValue::encode(jsMakeNontrivialString(exec, '/', source, '/', flags.data()));
+}
+
+EncodedJSValue JSC_HOST_CALL regExpProtoGetterGlobal(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.inherits(RegExpObject::info()))
+ return throwVMTypeError(exec);
+
+ return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->global()));
+}
+
+EncodedJSValue JSC_HOST_CALL regExpProtoGetterIgnoreCase(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.inherits(RegExpObject::info()))
+ return throwVMTypeError(exec);
+
+ return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->ignoreCase()));
+}
+
+EncodedJSValue JSC_HOST_CALL regExpProtoGetterMultiline(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.inherits(RegExpObject::info()))
+ return throwVMTypeError(exec);
+
+ return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->multiline()));
+}
+
+EncodedJSValue JSC_HOST_CALL regExpProtoGetterFlags(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.isObject())
+ return throwVMTypeError(exec);
+
+ auto flags = flagsString(exec, asObject(thisValue));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ return JSValue::encode(jsString(exec, flags.data()));
+}
+
+template <typename CharacterType>
+static inline void appendLineTerminatorEscape(StringBuilder&, CharacterType);
+
+template <>
+inline void appendLineTerminatorEscape<LChar>(StringBuilder& builder, LChar lineTerminator)
+{
+ if (lineTerminator == '\n')
+ builder.append('n');
+ else
+ builder.append('r');
+}
+
+template <>
+inline void appendLineTerminatorEscape<UChar>(StringBuilder& builder, UChar lineTerminator)
+{
+ if (lineTerminator == '\n')
+ builder.append('n');
+ else if (lineTerminator == '\r')
+ builder.append('r');
+ else if (lineTerminator == 0x2028)
+ builder.appendLiteral("u2028");
+ else
+ builder.appendLiteral("u2029");
+}
+
+template <typename CharacterType>
+static inline JSValue regExpProtoGetterSourceInternal(ExecState* exec, const String& pattern, const CharacterType* characters, unsigned length)
+{
+ bool previousCharacterWasBackslash = false;
+ bool inBrackets = false;
+ bool shouldEscape = false;
+
+ // 15.10.6.4 specifies that RegExp.prototype.toString must return '/' + source + '/',
+ // and also states that the result must be a valid RegularExpressionLiteral. '//' is
+ // not a valid RegularExpressionLiteral (since it is a single line comment), and hence
+ // source cannot ever validly be "". If the source is empty, return a different Pattern
+ // that would match the same thing.
+ if (!length)
+ return jsNontrivialString(exec, ASCIILiteral("(?:)"));
+
+ // early return for strings that don't contain a forwards slash and LineTerminator
+ for (unsigned i = 0; i < length; ++i) {
+ CharacterType ch = characters[i];
+ if (!previousCharacterWasBackslash) {
+ if (inBrackets) {
+ if (ch == ']')
+ inBrackets = false;
+ } else {
+ if (ch == '/') {
+ shouldEscape = true;
+ break;
+ }
+ if (ch == '[')
+ inBrackets = true;
+ }
+ }
+
+ if (Lexer<CharacterType>::isLineTerminator(ch)) {
+ shouldEscape = true;
+ break;
+ }
+
+ if (previousCharacterWasBackslash)
+ previousCharacterWasBackslash = false;
+ else
+ previousCharacterWasBackslash = ch == '\\';
+ }
+
+ if (!shouldEscape)
+ return jsString(exec, pattern);
+
+ previousCharacterWasBackslash = false;
+ inBrackets = false;
+ StringBuilder result;
+ for (unsigned i = 0; i < length; ++i) {
+ CharacterType ch = characters[i];
+ if (!previousCharacterWasBackslash) {
+ if (inBrackets) {
+ if (ch == ']')
+ inBrackets = false;
+ } else {
+ if (ch == '/')
+ result.append('\\');
+ else if (ch == '[')
+ inBrackets = true;
+ }
+ }
+
+ // escape LineTerminator
+ if (Lexer<CharacterType>::isLineTerminator(ch)) {
+ if (!previousCharacterWasBackslash)
+ result.append('\\');
+
+ appendLineTerminatorEscape<CharacterType>(result, ch);
+ } else
+ result.append(ch);
+
+ if (previousCharacterWasBackslash)
+ previousCharacterWasBackslash = false;
+ else
+ previousCharacterWasBackslash = ch == '\\';
+ }
+
+ return jsString(exec, result.toString());
+}
+
+EncodedJSValue JSC_HOST_CALL regExpProtoGetterSource(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.inherits(RegExpObject::info()))
+ return throwVMTypeError(exec);
+
+ String pattern = asRegExpObject(thisValue)->regExp()->pattern();
+ if (pattern.is8Bit())
+ return JSValue::encode(regExpProtoGetterSourceInternal(exec, pattern, pattern.characters8(), pattern.length()));
+ return JSValue::encode(regExpProtoGetterSourceInternal(exec, pattern, pattern.characters16(), pattern.length()));
+}
+
+EncodedJSValue JSC_HOST_CALL regExpProtoFuncSearch(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!thisValue.inherits(RegExpObject::info()))
+ return throwVMTypeError(exec);
+ RegExp* regExp = asRegExpObject(thisValue)->regExp();
+
+ JSString* string = exec->argument(0).toString(exec);
+ String s = string->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
+ MatchResult result = regExpConstructor->performMatch(exec->vm(), regExp, string, s, 0);
+ return JSValue::encode(result ? jsNumber(result.start) : jsNumber(-1));
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.h b/Source/JavaScriptCore/runtime/RegExpPrototype.h
index e9fef179b..8c49cf11c 100644
--- a/Source/JavaScriptCore/runtime/RegExpPrototype.h
+++ b/Source/JavaScriptCore/runtime/RegExpPrototype.h
@@ -26,31 +26,32 @@
namespace JSC {
- class RegExpPrototype : public RegExpObject {
- public:
- typedef RegExpObject Base;
-
- static RegExpPrototype* create(VM& vm, Structure* structure, RegExp* regExp)
- {
- RegExpPrototype* prototype = new (NotNull, allocateCell<RegExpPrototype>(vm.heap)) RegExpPrototype(vm, structure, regExp);
- prototype->finishCreation(vm);
- return prototype;
- }
-
- DECLARE_INFO;
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
-
- protected:
- RegExpPrototype(VM&, Structure*, RegExp*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | RegExpObject::StructureFlags;
-
- private:
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- };
+class RegExpPrototype : public RegExpObject {
+public:
+ typedef RegExpObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static RegExpPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure, RegExp* regExp)
+ {
+ RegExpPrototype* prototype = new (NotNull, allocateCell<RegExpPrototype>(vm.heap)) RegExpPrototype(vm, structure, regExp);
+ 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());
+ }
+
+protected:
+ RegExpPrototype(VM&, Structure*, RegExp*);
+
+private:
+ void finishCreation(VM&, JSGlobalObject*);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RuntimeFlags.h b/Source/JavaScriptCore/runtime/RuntimeFlags.h
new file mode 100644
index 000000000..8cd30c6da
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RuntimeFlags.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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.
+ */
+
+#ifndef RuntimeFlags_h
+#define RuntimeFlags_h
+
+#include <initializer_list>
+
+namespace JSC {
+
+// macro(name, isEnabledFlag)
+#define JSC_RUNTIME_FLAG(macro)
+
+class RuntimeFlags {
+private:
+ enum RuntimeFlagShiftValue : unsigned {
+#define JSC_DECLARE_RUNTIME_FLAG_SHIFT_VALUE(name, isEnabledFlag) shiftValueFor##name,
+ JSC_RUNTIME_FLAG(JSC_DECLARE_RUNTIME_FLAG_SHIFT_VALUE)
+#undef JSC_DECLARE_RUNTIME_FLAG_SHIFT_VALUE
+ };
+
+public:
+ enum RuntimeFlag : unsigned {
+#define JSC_DECLARE_RUNTIME_FLAG(name, isEnabledFlag) name = 1u << (shiftValueFor##name),
+ JSC_RUNTIME_FLAG(JSC_DECLARE_RUNTIME_FLAG)
+#undef JSC_DECLARE_RUNTIME_FLAG
+ };
+
+#define JSC_DECLARE_RUNTIME_FLAG_ACCESSOR(name, isEnabledFlag) \
+ void set##name(bool value)\
+ {\
+ if (value)\
+ m_flags |= name;\
+ else\
+ m_flags &= (~name);\
+ }\
+ bool is##name() const\
+ {\
+ return m_flags & name;\
+ }
+ JSC_RUNTIME_FLAG(JSC_DECLARE_RUNTIME_FLAG_ACCESSOR)
+#undef JSC_DECLARE_RUNTIME_FLAG_ACCESSOR
+
+ RuntimeFlags()
+ : RuntimeFlags(0u)
+ {
+ }
+
+ RuntimeFlags(std::initializer_list<RuntimeFlag> initializerList)
+ : RuntimeFlags()
+ {
+ for (RuntimeFlag flag : initializerList)
+ m_flags |= flag;
+ }
+
+ explicit RuntimeFlags(unsigned flags)
+ : m_flags(flags)
+ {
+ }
+
+ static RuntimeFlags createAllEnabled()
+ {
+ return RuntimeFlags(
+#define JSC_USE_RUNTIME_FLAG(name, isEnabledFlag) ((isEnabledFlag) ? name : 0u) |
+ JSC_RUNTIME_FLAG(JSC_USE_RUNTIME_FLAG)
+#undef JSC_USE_RUNTIME_FLAG
+ 0u
+ );
+ }
+
+private:
+ unsigned m_flags;
+};
+
+} // namespace JSC
+
+#endif // RuntimeFlags_h
diff --git a/Source/JavaScriptCore/runtime/RuntimeType.cpp b/Source/JavaScriptCore/runtime/RuntimeType.cpp
new file mode 100644
index 000000000..ac9fe857d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RuntimeType.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
+ * Copyright (C) Saam Barati <saambarati1@gmail.com>. 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 "RuntimeType.h"
+
+#include "JSCJSValue.h"
+#include "JSCJSValueInlines.h"
+
+namespace JSC {
+
+RuntimeType runtimeTypeForValue(JSValue value)
+{
+ if (UNLIKELY(!value))
+ return TypeNothing;
+
+ if (value.isUndefined())
+ return TypeUndefined;
+ if (value.isNull())
+ return TypeNull;
+ if (value.isMachineInt())
+ return TypeMachineInt;
+ if (value.isNumber())
+ return TypeNumber;
+ if (value.isString())
+ return TypeString;
+ if (value.isBoolean())
+ return TypeBoolean;
+ if (value.isObject())
+ return TypeObject;
+ if (value.isFunction())
+ return TypeFunction;
+ if (value.isSymbol())
+ return TypeSymbol;
+
+ return TypeNothing;
+}
+
+String runtimeTypeAsString(RuntimeType type)
+{
+ if (type == TypeUndefined)
+ return ASCIILiteral("Undefined");
+ if (type == TypeNull)
+ return ASCIILiteral("Null");
+ if (type == TypeMachineInt)
+ return ASCIILiteral("Integer");
+ if (type == TypeNumber)
+ return ASCIILiteral("Number");
+ if (type == TypeString)
+ return ASCIILiteral("String");
+ if (type == TypeObject)
+ return ASCIILiteral("Object");
+ if (type == TypeBoolean)
+ return ASCIILiteral("Boolean");
+ if (type == TypeFunction)
+ return ASCIILiteral("Function");
+ if (type == TypeNothing)
+ return ASCIILiteral("(Nothing)");
+
+ RELEASE_ASSERT_NOT_REACHED();
+ return emptyString();
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RuntimeType.h b/Source/JavaScriptCore/runtime/RuntimeType.h
new file mode 100644
index 000000000..d57b8fbf0
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RuntimeType.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) Saam Barati <saambarati1@gmail.com>. 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 RuntimeType_h
+#define RuntimeType_h
+
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+
+enum RuntimeType : uint16_t {
+ TypeNothing = 0x0,
+ TypeFunction = 0x1,
+ TypeUndefined = 0x2,
+ TypeNull = 0x4,
+ TypeBoolean = 0x8,
+ TypeMachineInt = 0x10,
+ TypeNumber = 0x20,
+ TypeString = 0x40,
+ TypeObject = 0x80,
+ TypeSymbol = 0x100
+};
+
+typedef uint16_t RuntimeTypeMask;
+
+class JSValue;
+RuntimeType runtimeTypeForValue(JSValue);
+String runtimeTypeAsString(RuntimeType);
+
+ALWAYS_INLINE bool runtimeTypeIsPrimitive(RuntimeTypeMask type)
+{
+ return type & ~(TypeFunction | TypeObject);
+}
+
+} // namespace JSC
+
+#endif // RuntimeType_h
diff --git a/Source/JavaScriptCore/runtime/SamplingCounter.cpp b/Source/JavaScriptCore/runtime/SamplingCounter.cpp
index 9826b88e4..b5564b4f9 100644
--- a/Source/JavaScriptCore/runtime/SamplingCounter.cpp
+++ b/Source/JavaScriptCore/runtime/SamplingCounter.cpp
@@ -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.
*
diff --git a/Source/JavaScriptCore/runtime/SamplingCounter.h b/Source/JavaScriptCore/runtime/SamplingCounter.h
index 8413b5458..d1acdcee5 100644
--- a/Source/JavaScriptCore/runtime/SamplingCounter.h
+++ b/Source/JavaScriptCore/runtime/SamplingCounter.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.
*
diff --git a/Source/JavaScriptCore/runtime/SamplingProfiler.cpp b/Source/JavaScriptCore/runtime/SamplingProfiler.cpp
new file mode 100644
index 000000000..9c7ad7445
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/SamplingProfiler.cpp
@@ -0,0 +1,786 @@
+/*
+ * 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 "SamplingProfiler.h"
+
+#if ENABLE(SAMPLING_PROFILER)
+
+#include "CallFrame.h"
+#include "CodeBlock.h"
+#include "Debugger.h"
+#include "Executable.h"
+#include "HeapInlines.h"
+#include "HeapIterationScope.h"
+#include "InlineCallFrame.h"
+#include "Interpreter.h"
+#include "JSCJSValueInlines.h"
+#include "JSFunction.h"
+#include "LLIntPCRanges.h"
+#include "MarkedBlock.h"
+#include "MarkedBlockSet.h"
+#include "PCToCodeOriginMap.h"
+#include "SlotVisitor.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+#include "VM.h"
+#include "VMEntryScope.h"
+
+namespace JSC {
+
+static double sNumTotalStackTraces = 0;
+static double sNumTotalWalks = 0;
+static double sNumFailedWalks = 0;
+static const uint32_t sNumWalkReportingFrequency = 50;
+static const double sWalkErrorPercentage = .05;
+static const bool sReportStatsOnlyWhenTheyreAboveThreshold = false;
+static const bool sReportStats = false;
+
+using FrameType = SamplingProfiler::FrameType;
+using UnprocessedStackFrame = SamplingProfiler::UnprocessedStackFrame;
+
+ALWAYS_INLINE static void reportStats()
+{
+ if (sReportStats && sNumTotalWalks && static_cast<uint64_t>(sNumTotalWalks) % sNumWalkReportingFrequency == 0) {
+ if (!sReportStatsOnlyWhenTheyreAboveThreshold || (sNumFailedWalks / sNumTotalWalks > sWalkErrorPercentage)) {
+ dataLogF("Num total walks: %llu. Failed walks percent: %lf\n",
+ static_cast<unsigned long long>(sNumTotalWalks), sNumFailedWalks / sNumTotalWalks);
+ }
+ }
+}
+
+class FrameWalker {
+public:
+ FrameWalker(ExecState* callFrame, VM& vm, const LockHolder& codeBlockSetLocker, const LockHolder& machineThreadsLocker)
+ : m_vm(vm)
+ , m_callFrame(callFrame)
+ , m_vmEntryFrame(vm.topVMEntryFrame)
+ , m_codeBlockSetLocker(codeBlockSetLocker)
+ , m_machineThreadsLocker(machineThreadsLocker)
+ {
+ }
+
+ SUPPRESS_ASAN
+ size_t walk(Vector<UnprocessedStackFrame>& stackTrace, bool& didRunOutOfSpace)
+ {
+ if (sReportStats)
+ sNumTotalWalks++;
+ resetAtMachineFrame();
+ size_t maxStackTraceSize = stackTrace.size();
+ while (!isAtTop() && !m_bailingOut && m_depth < maxStackTraceSize) {
+ CallSiteIndex callSiteIndex;
+ JSValue unsafeCallee = m_callFrame->unsafeCallee();
+ CodeBlock* codeBlock = m_callFrame->unsafeCodeBlock();
+ if (codeBlock) {
+ ASSERT(isValidCodeBlock(codeBlock));
+ callSiteIndex = m_callFrame->unsafeCallSiteIndex();
+ }
+ stackTrace[m_depth] = UnprocessedStackFrame(codeBlock, JSValue::encode(unsafeCallee), callSiteIndex);
+ m_depth++;
+ advanceToParentFrame();
+ resetAtMachineFrame();
+ }
+ didRunOutOfSpace = m_depth >= maxStackTraceSize && !isAtTop();
+ reportStats();
+ return m_depth;
+ }
+
+ bool wasValidWalk() const
+ {
+ return !m_bailingOut;
+ }
+
+private:
+
+ SUPPRESS_ASAN
+ void advanceToParentFrame()
+ {
+ m_callFrame = m_callFrame->unsafeCallerFrame(m_vmEntryFrame);
+ }
+
+ bool isAtTop() const
+ {
+ return !m_callFrame;
+ }
+
+ SUPPRESS_ASAN
+ void resetAtMachineFrame()
+ {
+ if (isAtTop())
+ return;
+
+ if (!isValidFramePointer(m_callFrame)) {
+ // Guard against pausing the process at weird program points.
+ m_bailingOut = true;
+ if (sReportStats)
+ sNumFailedWalks++;
+ return;
+ }
+
+ CodeBlock* codeBlock = m_callFrame->unsafeCodeBlock();
+ if (!codeBlock)
+ return;
+
+ if (!isValidCodeBlock(codeBlock)) {
+ m_bailingOut = true;
+ if (sReportStats)
+ sNumFailedWalks++;
+ return;
+ }
+ }
+
+ bool isValidFramePointer(ExecState* exec)
+ {
+ uint8_t* fpCast = bitwise_cast<uint8_t*>(exec);
+ for (MachineThreads::Thread* thread = m_vm.heap.machineThreads().threadsListHead(m_machineThreadsLocker); thread; thread = thread->next) {
+ uint8_t* stackBase = static_cast<uint8_t*>(thread->stackBase);
+ uint8_t* stackLimit = static_cast<uint8_t*>(thread->stackEnd);
+ RELEASE_ASSERT(stackBase);
+ RELEASE_ASSERT(stackLimit);
+ if (fpCast <= stackBase && fpCast >= stackLimit)
+ return true;
+ }
+ return false;
+ }
+
+ bool isValidCodeBlock(CodeBlock* codeBlock)
+ {
+ if (!codeBlock)
+ return false;
+ bool result = m_vm.heap.codeBlockSet().contains(m_codeBlockSetLocker, codeBlock);
+ return result;
+ }
+
+ VM& m_vm;
+ ExecState* m_callFrame;
+ VMEntryFrame* m_vmEntryFrame;
+ const LockHolder& m_codeBlockSetLocker;
+ const LockHolder& m_machineThreadsLocker;
+ bool m_bailingOut { false };
+ size_t m_depth { 0 };
+};
+
+SamplingProfiler::SamplingProfiler(VM& vm, RefPtr<Stopwatch>&& stopwatch)
+ : m_vm(vm)
+ , m_stopwatch(WTFMove(stopwatch))
+ , m_timingInterval(std::chrono::microseconds(1000))
+ , m_totalTime(0)
+ , m_timerQueue(WorkQueue::create("jsc.sampling-profiler.queue", WorkQueue::Type::Serial, WorkQueue::QOS::UserInteractive))
+ , m_jscExecutionThread(nullptr)
+ , m_isActive(false)
+ , m_isPaused(false)
+ , m_hasDispatchedFunction(false)
+{
+ if (sReportStats) {
+ sNumTotalWalks = 0;
+ sNumFailedWalks = 0;
+ }
+
+ m_currentFrames.grow(256);
+
+ m_handler = [this] () {
+ LockHolder samplingProfilerLocker(m_lock);
+ if (!m_isActive || !m_jscExecutionThread || m_isPaused) {
+ m_hasDispatchedFunction = false;
+ deref();
+ return;
+ }
+
+ if (m_vm.entryScope) {
+ double nowTime = m_stopwatch->elapsedTime();
+
+ LockHolder machineThreadsLocker(m_vm.heap.machineThreads().getLock());
+ LockHolder codeBlockSetLocker(m_vm.heap.codeBlockSet().getLock());
+ LockHolder executableAllocatorLocker(m_vm.executableAllocator.getLock());
+
+ bool didSuspend = m_jscExecutionThread->suspend();
+ if (didSuspend) {
+ // While the JSC thread is suspended, we can't do things like malloc because the JSC thread
+ // may be holding the malloc lock.
+ ExecState* callFrame;
+ void* machinePC;
+ bool topFrameIsLLInt = false;
+ void* llintPC;
+ {
+ MachineThreads::Thread::Registers registers;
+ m_jscExecutionThread->getRegisters(registers);
+ callFrame = static_cast<ExecState*>(registers.framePointer());
+ machinePC = registers.instructionPointer();
+ llintPC = registers.llintPC();
+ m_jscExecutionThread->freeRegisters(registers);
+ }
+ // FIXME: Lets have a way of detecting when we're parsing code.
+ // https://bugs.webkit.org/show_bug.cgi?id=152761
+ if (m_vm.executableAllocator.isValidExecutableMemory(executableAllocatorLocker, machinePC)) {
+ if (m_vm.isExecutingInRegExpJIT) {
+ // FIXME: We're executing a regexp. Lets gather more intersting data.
+ // https://bugs.webkit.org/show_bug.cgi?id=152729
+ callFrame = m_vm.topCallFrame; // We need to do this or else we'd fail our backtrace validation b/c this isn't a JS frame.
+ }
+ } else if (LLInt::isLLIntPC(machinePC)) {
+ topFrameIsLLInt = true;
+ // We're okay to take a normal stack trace when the PC
+ // is in LLInt code.
+ } else {
+ // We resort to topCallFrame to see if we can get anything
+ // useful. We usually get here when we're executing C code.
+ callFrame = m_vm.topCallFrame;
+ }
+
+ size_t walkSize;
+ bool wasValidWalk;
+ bool didRunOutOfVectorSpace;
+ {
+ FrameWalker walker(callFrame, m_vm, codeBlockSetLocker, machineThreadsLocker);
+ walkSize = walker.walk(m_currentFrames, didRunOutOfVectorSpace);
+ wasValidWalk = walker.wasValidWalk();
+ }
+
+ m_jscExecutionThread->resume();
+
+ // We can now use data structures that malloc, and do other interesting things, again.
+
+ // FIXME: It'd be interesting to take data about the program's state when
+ // we fail to take a stack trace: https://bugs.webkit.org/show_bug.cgi?id=152758
+ if (wasValidWalk && walkSize) {
+ if (sReportStats)
+ sNumTotalStackTraces++;
+ Vector<UnprocessedStackFrame> stackTrace;
+ stackTrace.reserveInitialCapacity(walkSize);
+ for (size_t i = 0; i < walkSize; i++) {
+ UnprocessedStackFrame frame = m_currentFrames[i];
+ stackTrace.uncheckedAppend(frame);
+ }
+
+ m_unprocessedStackTraces.append(UnprocessedStackTrace { nowTime, machinePC, topFrameIsLLInt, llintPC, WTFMove(stackTrace) });
+
+ if (didRunOutOfVectorSpace)
+ m_currentFrames.grow(m_currentFrames.size() * 1.25);
+
+ m_totalTime += nowTime - m_lastTime;
+ }
+ }
+ }
+
+ m_lastTime = m_stopwatch->elapsedTime();
+
+ dispatchFunction(samplingProfilerLocker);
+ };
+}
+
+SamplingProfiler::~SamplingProfiler()
+{
+}
+
+static ALWAYS_INLINE unsigned tryGetBytecodeIndex(unsigned llintPC, CodeBlock* codeBlock, bool& isValid)
+{
+#if ENABLE(DFG_JIT)
+ RELEASE_ASSERT(!codeBlock->hasCodeOrigins());
+#endif
+
+#if USE(JSVALUE64)
+ unsigned bytecodeIndex = llintPC;
+ if (bytecodeIndex < codeBlock->instructionCount()) {
+ isValid = true;
+ return bytecodeIndex;
+ }
+ isValid = false;
+ return 0;
+#else
+ Instruction* instruction = bitwise_cast<Instruction*>(llintPC);
+ if (instruction >= codeBlock->instructions().begin() && instruction < codeBlock->instructions().begin() + codeBlock->instructionCount()) {
+ isValid = true;
+ unsigned bytecodeIndex = instruction - codeBlock->instructions().begin();
+ return bytecodeIndex;
+ }
+ isValid = false;
+ return 0;
+#endif
+}
+
+void SamplingProfiler::processUnverifiedStackTraces()
+{
+ // This function needs to be called from the JSC execution thread.
+ RELEASE_ASSERT(m_lock.isLocked());
+
+ TinyBloomFilter filter = m_vm.heap.objectSpace().blocks().filter();
+ MarkedBlockSet& markedBlockSet = m_vm.heap.objectSpace().blocks();
+
+ for (UnprocessedStackTrace& unprocessedStackTrace : m_unprocessedStackTraces) {
+ m_stackTraces.append(StackTrace());
+ StackTrace& stackTrace = m_stackTraces.last();
+ stackTrace.timestamp = unprocessedStackTrace.timestamp;
+
+ auto appendCodeBlock = [&] (CodeBlock* codeBlock, unsigned bytecodeIndex) {
+ stackTrace.frames.append(StackFrame(codeBlock->ownerExecutable()));
+ m_liveCellPointers.add(codeBlock->ownerExecutable());
+
+ if (bytecodeIndex < codeBlock->instructionCount()) {
+ int divot;
+ int startOffset;
+ int endOffset;
+ codeBlock->expressionRangeForBytecodeOffset(bytecodeIndex, divot, startOffset, endOffset,
+ stackTrace.frames.last().lineNumber, stackTrace.frames.last().columnNumber);
+ }
+ };
+
+ auto appendEmptyFrame = [&] {
+ stackTrace.frames.append(StackFrame());
+ };
+
+ auto storeCalleeIntoTopFrame = [&] (EncodedJSValue encodedCallee) {
+ // Set the callee if it's a valid GC object.
+ JSValue callee = JSValue::decode(encodedCallee);
+ StackFrame& stackFrame = stackTrace.frames.last();
+ bool alreadyHasExecutable = !!stackFrame.executable;
+ if (!Heap::isValueGCObject(filter, markedBlockSet, callee)) {
+ if (!alreadyHasExecutable)
+ stackFrame.frameType = FrameType::Unknown;
+ return;
+ }
+
+ JSCell* calleeCell = callee.asCell();
+ auto setFallbackFrameType = [&] {
+ ASSERT(!alreadyHasExecutable);
+ FrameType result = FrameType::Unknown;
+ CallData callData;
+ CallType callType;
+ callType = getCallData(calleeCell, callData);
+ if (callType == CallTypeHost)
+ result = FrameType::Host;
+
+ stackFrame.frameType = result;
+ };
+
+ auto addCallee = [&] (JSObject* callee) {
+ stackFrame.callee = callee;
+ m_liveCellPointers.add(callee);
+ };
+
+ if (calleeCell->type() != JSFunctionType) {
+ if (JSObject* object = jsDynamicCast<JSObject*>(calleeCell))
+ addCallee(object);
+
+ if (!alreadyHasExecutable)
+ setFallbackFrameType();
+
+ return;
+ }
+
+ addCallee(jsCast<JSFunction*>(calleeCell));
+
+ if (alreadyHasExecutable)
+ return;
+
+ ExecutableBase* executable = jsCast<JSFunction*>(calleeCell)->executable();
+ if (!executable) {
+ setFallbackFrameType();
+ return;
+ }
+
+ RELEASE_ASSERT(Heap::isPointerGCObject(filter, markedBlockSet, executable));
+ stackFrame.frameType = FrameType::Executable;
+ stackFrame.executable = executable;
+ m_liveCellPointers.add(executable);
+ };
+
+
+ // Prepend the top-most inlined frame if needed and gather
+ // location information about where the top frame is executing.
+ size_t startIndex = 0;
+ if (unprocessedStackTrace.frames.size() && !!unprocessedStackTrace.frames[0].verifiedCodeBlock) {
+ CodeBlock* topCodeBlock = unprocessedStackTrace.frames[0].verifiedCodeBlock;
+ if (unprocessedStackTrace.topFrameIsLLInt) {
+ // We reuse LLInt CodeBlocks for the baseline JIT, so we need to check for both jit types.
+ // This might also be false for various reasons (known and unknown), even though
+ // it's super unlikely. One reason that this can be false is when we throw from a DFG frame,
+ // and we end up having to unwind past a VMEntryFrame, we will end up executing
+ // inside the LLInt's handleUncaughtException. So we just protect against this
+ // by ignoring it.
+ unsigned bytecodeIndex = 0;
+ if (topCodeBlock->jitType() == JITCode::InterpreterThunk || topCodeBlock->jitType() == JITCode::BaselineJIT) {
+ bool isValidPC;
+ unsigned bits;
+#if USE(JSVALUE64)
+ bits = static_cast<unsigned>(bitwise_cast<uintptr_t>(unprocessedStackTrace.llintPC));
+#else
+ bits = bitwise_cast<unsigned>(unprocessedStackTrace.llintPC);
+#endif
+ bytecodeIndex = tryGetBytecodeIndex(bits, topCodeBlock, isValidPC);
+
+ UNUSED_PARAM(isValidPC); // FIXME: do something with this info for the web inspector: https://bugs.webkit.org/show_bug.cgi?id=153455
+
+ appendCodeBlock(topCodeBlock, bytecodeIndex);
+ storeCalleeIntoTopFrame(unprocessedStackTrace.frames[0].unverifiedCallee);
+ startIndex = 1;
+ }
+ } else if (Optional<CodeOrigin> codeOrigin = topCodeBlock->findPC(unprocessedStackTrace.topPC)) {
+ codeOrigin->walkUpInlineStack([&] (const CodeOrigin& codeOrigin) {
+ appendCodeBlock(codeOrigin.inlineCallFrame ? codeOrigin.inlineCallFrame->baselineCodeBlock.get() : topCodeBlock, codeOrigin.bytecodeIndex);
+ });
+ storeCalleeIntoTopFrame(unprocessedStackTrace.frames[0].unverifiedCallee);
+ startIndex = 1;
+ }
+ }
+
+ for (size_t i = startIndex; i < unprocessedStackTrace.frames.size(); i++) {
+ UnprocessedStackFrame& unprocessedStackFrame = unprocessedStackTrace.frames[i];
+ if (CodeBlock* codeBlock = unprocessedStackFrame.verifiedCodeBlock) {
+ CallSiteIndex callSiteIndex = unprocessedStackFrame.callSiteIndex;
+
+ auto appendCodeBlockNoInlining = [&] {
+ bool isValidPC;
+ appendCodeBlock(codeBlock, tryGetBytecodeIndex(callSiteIndex.bits(), codeBlock, isValidPC));
+ };
+
+#if ENABLE(DFG_JIT)
+ if (codeBlock->hasCodeOrigins()) {
+ if (codeBlock->canGetCodeOrigin(callSiteIndex)) {
+ codeBlock->codeOrigin(callSiteIndex).walkUpInlineStack([&] (const CodeOrigin& codeOrigin) {
+ appendCodeBlock(codeOrigin.inlineCallFrame ? codeOrigin.inlineCallFrame->baselineCodeBlock.get() : codeBlock, codeOrigin.bytecodeIndex);
+ });
+ } else
+ appendCodeBlock(codeBlock, std::numeric_limits<unsigned>::max());
+ } else
+ appendCodeBlockNoInlining();
+#else
+ appendCodeBlockNoInlining();
+#endif
+ } else
+ appendEmptyFrame();
+
+ // Note that this is okay to do if we walked the inline stack because
+ // the machine frame will be at the top of the processed stack trace.
+ storeCalleeIntoTopFrame(unprocessedStackFrame.unverifiedCallee);
+ }
+ }
+
+ m_unprocessedStackTraces.clear();
+}
+
+void SamplingProfiler::visit(SlotVisitor& slotVisitor)
+{
+ RELEASE_ASSERT(m_lock.isLocked());
+ for (JSCell* cell : m_liveCellPointers)
+ slotVisitor.appendUnbarrieredReadOnlyPointer(cell);
+}
+
+void SamplingProfiler::shutdown()
+{
+ stop();
+}
+
+void SamplingProfiler::start()
+{
+ LockHolder locker(m_lock);
+ start(locker);
+}
+
+void SamplingProfiler::start(const LockHolder& locker)
+{
+ ASSERT(m_lock.isLocked());
+ m_isActive = true;
+ dispatchIfNecessary(locker);
+}
+
+void SamplingProfiler::stop()
+{
+ LockHolder locker(m_lock);
+ stop(locker);
+}
+
+void SamplingProfiler::stop(const LockHolder&)
+{
+ ASSERT(m_lock.isLocked());
+ m_isActive = false;
+ reportStats();
+}
+
+void SamplingProfiler::pause()
+{
+ LockHolder locker(m_lock);
+ m_isPaused = true;
+ reportStats();
+}
+
+void SamplingProfiler::noticeCurrentThreadAsJSCExecutionThread(const LockHolder&)
+{
+ ASSERT(m_lock.isLocked());
+ m_jscExecutionThread = m_vm.heap.machineThreads().machineThreadForCurrentThread();
+}
+
+void SamplingProfiler::noticeCurrentThreadAsJSCExecutionThread()
+{
+ LockHolder locker(m_lock);
+ noticeCurrentThreadAsJSCExecutionThread(locker);
+}
+
+void SamplingProfiler::dispatchIfNecessary(const LockHolder& locker)
+{
+ if (m_isActive && !m_hasDispatchedFunction && m_jscExecutionThread && m_vm.entryScope) {
+ ref(); // Matching deref() is inside m_handler when m_handler stops recursing.
+ dispatchFunction(locker);
+ }
+}
+
+void SamplingProfiler::dispatchFunction(const LockHolder&)
+{
+ m_hasDispatchedFunction = true;
+ m_isPaused = false;
+ m_lastTime = m_stopwatch->elapsedTime();
+ m_timerQueue->dispatchAfter(m_timingInterval, m_handler);
+}
+
+void SamplingProfiler::noticeJSLockAcquisition()
+{
+ LockHolder locker(m_lock);
+ noticeCurrentThreadAsJSCExecutionThread(locker);
+}
+
+void SamplingProfiler::noticeVMEntry()
+{
+ LockHolder locker(m_lock);
+ ASSERT(m_vm.entryScope);
+ noticeCurrentThreadAsJSCExecutionThread(locker);
+ m_lastTime = m_stopwatch->elapsedTime();
+ dispatchIfNecessary(locker);
+}
+
+void SamplingProfiler::clearData(const LockHolder&)
+{
+ ASSERT(m_lock.isLocked());
+ m_stackTraces.clear();
+ m_liveCellPointers.clear();
+ m_unprocessedStackTraces.clear();
+}
+
+String SamplingProfiler::StackFrame::nameFromCallee(VM& vm)
+{
+ if (!callee)
+ return String();
+
+ ExecState* exec = callee->globalObject()->globalExec();
+ auto getPropertyIfPureOperation = [&] (const Identifier& ident) -> String {
+ PropertySlot slot(callee, PropertySlot::InternalMethodType::VMInquiry);
+ PropertyName propertyName(ident);
+ if (callee->getPropertySlot(exec, propertyName, slot)) {
+ if (slot.isValue()) {
+ JSValue nameValue = slot.getValue(exec, propertyName);
+ if (isJSString(nameValue))
+ return asString(nameValue)->tryGetValue();
+ }
+ }
+ return String();
+ };
+
+ String name = getPropertyIfPureOperation(vm.propertyNames->displayName);
+ if (!name.isEmpty())
+ return name;
+
+ return getPropertyIfPureOperation(vm.propertyNames->name);
+}
+
+String SamplingProfiler::StackFrame::displayName(VM& vm)
+{
+ {
+ String name = nameFromCallee(vm);
+ if (!name.isEmpty())
+ return name;
+ }
+
+ if (frameType == FrameType::Unknown)
+ return ASCIILiteral("(unknown)");
+ if (frameType == FrameType::Host)
+ return ASCIILiteral("(host)");
+
+ if (executable->isHostFunction())
+ return static_cast<NativeExecutable*>(executable)->name();
+
+ if (executable->isFunctionExecutable())
+ return static_cast<FunctionExecutable*>(executable)->inferredName().string();
+ if (executable->isProgramExecutable() || executable->isEvalExecutable())
+ return ASCIILiteral("(program)");
+ if (executable->isModuleProgramExecutable())
+ return ASCIILiteral("(module)");
+
+ RELEASE_ASSERT_NOT_REACHED();
+ return String();
+}
+
+String SamplingProfiler::StackFrame::displayNameForJSONTests(VM& vm)
+{
+ {
+ String name = nameFromCallee(vm);
+ if (!name.isEmpty())
+ return name;
+ }
+
+ if (frameType == FrameType::Unknown)
+ return ASCIILiteral("(unknown)");
+ if (frameType == FrameType::Host)
+ return ASCIILiteral("(host)");
+
+ if (executable->isHostFunction())
+ return static_cast<NativeExecutable*>(executable)->name();
+
+ if (executable->isFunctionExecutable()) {
+ String result = static_cast<FunctionExecutable*>(executable)->inferredName().string();
+ if (result.isEmpty())
+ return ASCIILiteral("(anonymous function)");
+ return result;
+ }
+ if (executable->isEvalExecutable())
+ return ASCIILiteral("(eval)");
+ if (executable->isProgramExecutable())
+ return ASCIILiteral("(program)");
+ if (executable->isModuleProgramExecutable())
+ return ASCIILiteral("(module)");
+
+ RELEASE_ASSERT_NOT_REACHED();
+ return String();
+}
+
+int SamplingProfiler::StackFrame::functionStartLine()
+{
+ if (frameType == FrameType::Unknown || frameType == FrameType::Host)
+ return -1;
+
+ if (executable->isHostFunction())
+ return -1;
+ return static_cast<ScriptExecutable*>(executable)->firstLine();
+}
+
+unsigned SamplingProfiler::StackFrame::functionStartColumn()
+{
+ if (frameType == FrameType::Unknown || frameType == FrameType::Host)
+ return -1;
+
+ if (executable->isHostFunction())
+ return -1;
+
+ return static_cast<ScriptExecutable*>(executable)->startColumn();
+}
+
+intptr_t SamplingProfiler::StackFrame::sourceID()
+{
+ if (frameType == FrameType::Unknown || frameType == FrameType::Host)
+ return -1;
+
+ if (executable->isHostFunction())
+ return -1;
+
+ return static_cast<ScriptExecutable*>(executable)->sourceID();
+}
+
+String SamplingProfiler::StackFrame::url()
+{
+ if (frameType == FrameType::Unknown || frameType == FrameType::Host)
+ return emptyString();
+
+ if (executable->isHostFunction())
+ return emptyString();
+
+ String url = static_cast<ScriptExecutable*>(executable)->sourceURL();
+ if (url.isEmpty())
+ return static_cast<ScriptExecutable*>(executable)->source().provider()->sourceURL(); // Fall back to sourceURL directive.
+ return url;
+}
+
+Vector<SamplingProfiler::StackTrace> SamplingProfiler::releaseStackTraces(const LockHolder& locker)
+{
+ ASSERT(m_lock.isLocked());
+ {
+ HeapIterationScope heapIterationScope(m_vm.heap);
+ processUnverifiedStackTraces();
+ }
+
+ Vector<StackTrace> result(WTFMove(m_stackTraces));
+ clearData(locker);
+ return result;
+}
+
+String SamplingProfiler::stackTracesAsJSON()
+{
+ LockHolder locker(m_lock);
+
+ {
+ HeapIterationScope heapIterationScope(m_vm.heap);
+ processUnverifiedStackTraces();
+ }
+
+ StringBuilder json;
+ json.append('[');
+
+ bool loopedOnce = false;
+ auto comma = [&] {
+ if (loopedOnce)
+ json.append(',');
+ };
+ for (StackTrace& stackTrace : m_stackTraces) {
+ comma();
+ json.append('[');
+ loopedOnce = false;
+ for (StackFrame& stackFrame : stackTrace.frames) {
+ comma();
+ json.append('"');
+ json.append(stackFrame.displayNameForJSONTests(m_vm));
+ json.append('"');
+ loopedOnce = true;
+ }
+ json.append(']');
+ loopedOnce = true;
+ }
+
+ json.append(']');
+
+ clearData(locker);
+
+ return json.toString();
+}
+
+} // namespace JSC
+
+namespace WTF {
+
+using namespace JSC;
+
+void printInternal(PrintStream& out, SamplingProfiler::FrameType frameType)
+{
+ switch (frameType) {
+ case SamplingProfiler::FrameType::Executable:
+ out.print("Executable");
+ break;
+ case SamplingProfiler::FrameType::Host:
+ out.print("Host");
+ break;
+ case SamplingProfiler::FrameType::Unknown:
+ out.print("Unknown");
+ break;
+ }
+}
+
+} // namespace WTF
+
+#endif // ENABLE(SAMPLING_PROFILER)
diff --git a/Source/JavaScriptCore/runtime/SamplingProfiler.h b/Source/JavaScriptCore/runtime/SamplingProfiler.h
new file mode 100644
index 000000000..bd9d9425c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/SamplingProfiler.h
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+#ifndef SamplingProfiler_h
+#define SamplingProfiler_h
+
+#if ENABLE(SAMPLING_PROFILER)
+
+#include "CallFrame.h"
+#include "MachineStackMarker.h"
+#include <wtf/HashSet.h>
+#include <wtf/Lock.h>
+#include <wtf/Stopwatch.h>
+#include <wtf/Vector.h>
+#include <wtf/WorkQueue.h>
+
+namespace JSC {
+
+class VM;
+class ExecutableBase;
+
+class SamplingProfiler : public ThreadSafeRefCounted<SamplingProfiler> {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+
+ struct UnprocessedStackFrame {
+ UnprocessedStackFrame(CodeBlock* codeBlock, EncodedJSValue callee, CallSiteIndex callSiteIndex)
+ : unverifiedCallee(callee)
+ , verifiedCodeBlock(codeBlock)
+ , callSiteIndex(callSiteIndex)
+ { }
+ UnprocessedStackFrame()
+ {
+ unverifiedCallee = JSValue::encode(JSValue());
+ verifiedCodeBlock = nullptr;
+ }
+
+ EncodedJSValue unverifiedCallee;
+ CodeBlock* verifiedCodeBlock;
+ CallSiteIndex callSiteIndex;
+ };
+
+ enum class FrameType {
+ Executable,
+ Host,
+ Unknown
+ };
+
+ struct StackFrame {
+ StackFrame(ExecutableBase* executable)
+ : frameType(FrameType::Executable)
+ , executable(executable)
+ { }
+
+ StackFrame()
+ { }
+
+ FrameType frameType { FrameType::Unknown };
+ ExecutableBase* executable { nullptr };
+ JSObject* callee { nullptr };
+ // These attempt to be expression-level line and column number.
+ unsigned lineNumber { std::numeric_limits<unsigned>::max() };
+ unsigned columnNumber { std::numeric_limits<unsigned>::max() };
+
+ bool hasExpressionInfo() const
+ {
+ return lineNumber != std::numeric_limits<unsigned>::max()
+ && columnNumber != std::numeric_limits<unsigned>::max();
+ }
+
+ // These are function-level data.
+ String nameFromCallee(VM&);
+ String displayName(VM&);
+ String displayNameForJSONTests(VM&); // Used for JSC stress tests because they want the "(anonymous function)" string for anonymous functions and they want "(eval)" for eval'd code.
+ int functionStartLine();
+ unsigned functionStartColumn();
+ intptr_t sourceID();
+ String url();
+ };
+
+ struct UnprocessedStackTrace {
+ double timestamp;
+ void* topPC;
+ bool topFrameIsLLInt;
+ void* llintPC;
+ Vector<UnprocessedStackFrame> frames;
+ };
+
+ struct StackTrace {
+ double timestamp;
+ Vector<StackFrame> frames;
+ StackTrace()
+ { }
+ StackTrace(StackTrace&& other)
+ : timestamp(other.timestamp)
+ , frames(WTFMove(other.frames))
+ { }
+ };
+
+ SamplingProfiler(VM&, RefPtr<Stopwatch>&&);
+ ~SamplingProfiler();
+ void noticeJSLockAcquisition();
+ void noticeVMEntry();
+ void shutdown();
+ void visit(SlotVisitor&);
+ Lock& getLock() { return m_lock; }
+ void setTimingInterval(std::chrono::microseconds interval) { m_timingInterval = interval; }
+ JS_EXPORT_PRIVATE void start();
+ void start(const LockHolder&);
+ void stop();
+ void stop(const LockHolder&);
+ Vector<StackTrace> releaseStackTraces(const LockHolder&);
+ JS_EXPORT_PRIVATE String stackTracesAsJSON();
+ JS_EXPORT_PRIVATE void noticeCurrentThreadAsJSCExecutionThread();
+ void noticeCurrentThreadAsJSCExecutionThread(const LockHolder&);
+ void processUnverifiedStackTraces(); // You should call this only after acquiring the lock.
+ double totalTime(const LockHolder&) { return m_totalTime; }
+ void setStopWatch(const LockHolder&, Ref<Stopwatch>&& stopwatch) { m_stopwatch = WTFMove(stopwatch); }
+
+private:
+ void dispatchIfNecessary(const LockHolder&);
+ void dispatchFunction(const LockHolder&);
+ void pause();
+ void clearData(const LockHolder&);
+
+ VM& m_vm;
+ RefPtr<Stopwatch> m_stopwatch;
+ Vector<StackTrace> m_stackTraces;
+ Vector<UnprocessedStackTrace> m_unprocessedStackTraces;
+ std::chrono::microseconds m_timingInterval;
+ double m_lastTime;
+ double m_totalTime;
+ Ref<WorkQueue> m_timerQueue;
+ std::function<void ()> m_handler;
+ Lock m_lock;
+ MachineThreads::Thread* m_jscExecutionThread;
+ bool m_isActive;
+ bool m_isPaused;
+ bool m_hasDispatchedFunction;
+ HashSet<JSCell*> m_liveCellPointers;
+ Vector<UnprocessedStackFrame> m_currentFrames;
+};
+
+} // namespace JSC
+
+namespace WTF {
+
+void printInternal(PrintStream&, JSC::SamplingProfiler::FrameType);
+
+} // namespace WTF
+
+#endif // ENABLE(SAMPLING_PROFILER)
+
+#endif // SamplingProfiler_h
diff --git a/Source/JavaScriptCore/runtime/ScopeOffset.cpp b/Source/JavaScriptCore/runtime/ScopeOffset.cpp
new file mode 100644
index 000000000..1753165e5
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ScopeOffset.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "ScopeOffset.h"
+
+namespace JSC {
+
+void ScopeOffset::dump(PrintStream& out) const
+{
+ if (!*this) {
+ out.print("scopeInvalid");
+ return;
+ }
+
+ out.print("scope", offset());
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/runtime/ScopeOffset.h b/Source/JavaScriptCore/runtime/ScopeOffset.h
new file mode 100644
index 000000000..4dbd18605
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ScopeOffset.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#ifndef ScopeOffset_h
+#define ScopeOffset_h
+
+#include "GenericOffset.h"
+#include <wtf/PrintStream.h>
+
+namespace JSC {
+
+// This is an offset into a scope of some kind. It could be an activation scope or it could be a
+// global object.
+class ScopeOffset : public GenericOffset<ScopeOffset> {
+public:
+ ScopeOffset() { }
+
+ explicit ScopeOffset(unsigned offset)
+ : GenericOffset(offset)
+ {
+ }
+
+ void dump(PrintStream&) const;
+};
+
+} // namespace JSC
+
+#endif // ScopeOffset_h
+
diff --git a/Source/JavaScriptCore/runtime/ScopedArguments.cpp b/Source/JavaScriptCore/runtime/ScopedArguments.cpp
new file mode 100644
index 000000000..a5a2fc75b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ScopedArguments.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "ScopedArguments.h"
+
+#include "GenericArgumentsInlines.h"
+#include "JSCInlines.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ScopedArguments);
+
+const ClassInfo ScopedArguments::s_info = { "Arguments", &Base::s_info, 0, CREATE_METHOD_TABLE(ScopedArguments) };
+
+ScopedArguments::ScopedArguments(VM& vm, Structure* structure, unsigned totalLength)
+ : GenericArguments(vm, structure)
+ , m_overrodeThings(false)
+ , m_totalLength(totalLength)
+{
+}
+
+void ScopedArguments::finishCreation(VM& vm, JSFunction* callee, ScopedArgumentsTable* table, JSLexicalEnvironment* scope)
+{
+ Base::finishCreation(vm);
+ m_callee.set(vm, this, callee);
+ m_table.set(vm, this, table);
+ m_scope.set(vm, this, scope);
+}
+
+ScopedArguments* ScopedArguments::createUninitialized(VM& vm, Structure* structure, JSFunction* callee, ScopedArgumentsTable* table, JSLexicalEnvironment* scope, unsigned totalLength)
+{
+ unsigned overflowLength;
+ if (totalLength > table->length())
+ overflowLength = totalLength - table->length();
+ else
+ overflowLength = 0;
+ ScopedArguments* result = new (
+ NotNull,
+ allocateCell<ScopedArguments>(vm.heap, allocationSize(overflowLength)))
+ ScopedArguments(vm, structure, totalLength);
+ result->finishCreation(vm, callee, table, scope);
+ return result;
+}
+
+ScopedArguments* ScopedArguments::create(VM& vm, Structure* structure, JSFunction* callee, ScopedArgumentsTable* table, JSLexicalEnvironment* scope, unsigned totalLength)
+{
+ ScopedArguments* result =
+ createUninitialized(vm, structure, callee, table, scope, totalLength);
+
+ unsigned namedLength = table->length();
+ for (unsigned i = namedLength; i < totalLength; ++i)
+ result->overflowStorage()[i - namedLength].clear();
+
+ return result;
+}
+
+ScopedArguments* ScopedArguments::createByCopying(ExecState* exec, ScopedArgumentsTable* table, JSLexicalEnvironment* scope)
+{
+ return createByCopyingFrom(
+ exec->vm(), exec->lexicalGlobalObject()->scopedArgumentsStructure(),
+ exec->registers() + CallFrame::argumentOffset(0), exec->argumentCount(),
+ jsCast<JSFunction*>(exec->callee()), table, scope);
+}
+
+ScopedArguments* ScopedArguments::createByCopyingFrom(VM& vm, Structure* structure, Register* argumentsStart, unsigned totalLength, JSFunction* callee, ScopedArgumentsTable* table, JSLexicalEnvironment* scope)
+{
+ ScopedArguments* result =
+ createUninitialized(vm, structure, callee, table, scope, totalLength);
+
+ unsigned namedLength = table->length();
+ for (unsigned i = namedLength; i < totalLength; ++i)
+ result->overflowStorage()[i - namedLength].set(vm, result, argumentsStart[i].jsValue());
+
+ return result;
+}
+
+void ScopedArguments::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ ScopedArguments* thisObject = static_cast<ScopedArguments*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_callee);
+ visitor.append(&thisObject->m_table);
+ visitor.append(&thisObject->m_scope);
+
+ if (thisObject->m_totalLength > thisObject->m_table->length()) {
+ visitor.appendValues(
+ thisObject->overflowStorage(), thisObject->m_totalLength - thisObject->m_table->length());
+ }
+}
+
+Structure* ScopedArguments::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ScopedArgumentsType, StructureFlags), info());
+}
+
+void ScopedArguments::overrideThings(VM& vm)
+{
+ RELEASE_ASSERT(!m_overrodeThings);
+
+ putDirect(vm, vm.propertyNames->length, jsNumber(m_table->length()), DontEnum);
+ putDirect(vm, vm.propertyNames->callee, m_callee.get(), DontEnum);
+ putDirect(vm, vm.propertyNames->iteratorSymbol, globalObject()->arrayProtoValuesFunction(), DontEnum);
+
+ m_overrodeThings = true;
+}
+
+void ScopedArguments::overrideThingsIfNecessary(VM& vm)
+{
+ if (!m_overrodeThings)
+ overrideThings(vm);
+}
+
+void ScopedArguments::overrideArgument(VM& vm, uint32_t i)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(i < m_totalLength);
+ unsigned namedLength = m_table->length();
+ if (i < namedLength)
+ m_table.set(vm, this, m_table->set(vm, i, ScopeOffset()));
+ else
+ overflowStorage()[i - namedLength].clear();
+}
+
+void ScopedArguments::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length)
+{
+ GenericArguments::copyToArguments(exec, firstElementDest, offset, length);
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/runtime/ScopedArguments.h b/Source/JavaScriptCore/runtime/ScopedArguments.h
new file mode 100644
index 000000000..8d36a1bab
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ScopedArguments.h
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+#ifndef ScopedArguments_h
+#define ScopedArguments_h
+
+#include "GenericArguments.h"
+#include "JSLexicalEnvironment.h"
+
+namespace JSC {
+
+// This is an Arguments-class object that we create when you say "arguments" inside a function,
+// and one or more of the arguments may be captured in the function's activation. The function
+// will copy its formally declared arguments into the activation and then create this object. This
+// object will store the overflow arguments, if there are any. This object will use the symbol
+// table's ScopedArgumentsTable and the activation, or its overflow storage, to handle all indexed
+// lookups.
+class ScopedArguments : public GenericArguments<ScopedArguments> {
+private:
+ ScopedArguments(VM&, Structure*, unsigned totalLength);
+ void finishCreation(VM&, JSFunction* callee, ScopedArgumentsTable*, JSLexicalEnvironment*);
+
+public:
+ // Creates an arguments object but leaves it uninitialized. This is dangerous if we GC right
+ // after allocation.
+ static ScopedArguments* createUninitialized(VM&, Structure*, JSFunction* callee, ScopedArgumentsTable*, JSLexicalEnvironment*, unsigned totalLength);
+
+ // Creates an arguments object and initializes everything to the empty value. Use this if you
+ // cannot guarantee that you'll immediately initialize all of the elements.
+ static ScopedArguments* create(VM&, Structure*, JSFunction* callee, ScopedArgumentsTable*, JSLexicalEnvironment*, unsigned totalLength);
+
+ // Creates an arguments object by copying the arguments from the stack.
+ static ScopedArguments* createByCopying(ExecState*, ScopedArgumentsTable*, JSLexicalEnvironment*);
+
+ // Creates an arguments object by copying the arguments from a well-defined stack location.
+ static ScopedArguments* createByCopyingFrom(VM&, Structure*, Register* argumentsStart, unsigned totalLength, JSFunction* callee, ScopedArgumentsTable*, JSLexicalEnvironment*);
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ uint32_t internalLength() const
+ {
+ return m_totalLength;
+ }
+
+ uint32_t length(ExecState* exec) const
+ {
+ if (UNLIKELY(m_overrodeThings))
+ return get(exec, exec->propertyNames().length).toUInt32(exec);
+ return internalLength();
+ }
+
+ bool canAccessIndexQuickly(uint32_t i) const
+ {
+ if (i >= m_totalLength)
+ return false;
+ unsigned namedLength = m_table->length();
+ if (i < namedLength)
+ return !!m_table->get(i);
+ return !!overflowStorage()[i - namedLength].get();
+ }
+
+ bool canAccessArgumentIndexQuicklyInDFG(uint32_t i) const
+ {
+ return canAccessIndexQuickly(i);
+ }
+
+ JSValue getIndexQuickly(uint32_t i) const
+ {
+ ASSERT_WITH_SECURITY_IMPLICATION(canAccessIndexQuickly(i));
+ unsigned namedLength = m_table->length();
+ if (i < namedLength)
+ return m_scope->variableAt(m_table->get(i)).get();
+ return overflowStorage()[i - namedLength].get();
+ }
+
+ void setIndexQuickly(VM& vm, uint32_t i, JSValue value)
+ {
+ ASSERT_WITH_SECURITY_IMPLICATION(canAccessIndexQuickly(i));
+ unsigned namedLength = m_table->length();
+ if (i < namedLength)
+ m_scope->variableAt(m_table->get(i)).set(vm, this, value);
+ else
+ overflowStorage()[i - namedLength].set(vm, this, value);
+ }
+
+ WriteBarrier<JSFunction>& callee()
+ {
+ return m_callee;
+ }
+
+ bool overrodeThings() const { return m_overrodeThings; }
+ void overrideThings(VM&);
+ void overrideThingsIfNecessary(VM&);
+ void overrideArgument(VM&, uint32_t index);
+
+ void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length);
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+
+ static ptrdiff_t offsetOfOverrodeThings() { return OBJECT_OFFSETOF(ScopedArguments, m_overrodeThings); }
+ static ptrdiff_t offsetOfTotalLength() { return OBJECT_OFFSETOF(ScopedArguments, m_totalLength); }
+ static ptrdiff_t offsetOfTable() { return OBJECT_OFFSETOF(ScopedArguments, m_table); }
+ static ptrdiff_t offsetOfScope() { return OBJECT_OFFSETOF(ScopedArguments, m_scope); }
+
+ static size_t overflowStorageOffset()
+ {
+ return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<Unknown>)>(sizeof(ScopedArguments));
+ }
+
+ static size_t allocationSize(unsigned overflowArgumentsLength)
+ {
+ return overflowStorageOffset() + sizeof(WriteBarrier<Unknown>) * overflowArgumentsLength;
+ }
+
+private:
+ WriteBarrier<Unknown>* overflowStorage() const
+ {
+ return bitwise_cast<WriteBarrier<Unknown>*>(
+ bitwise_cast<char*>(this) + overflowStorageOffset());
+ }
+
+
+ bool m_overrodeThings; // True if length, callee, and caller are fully materialized in the object.
+ unsigned m_totalLength; // The length of declared plus overflow arguments.
+ WriteBarrier<JSFunction> m_callee;
+ WriteBarrier<ScopedArgumentsTable> m_table;
+ WriteBarrier<JSLexicalEnvironment> m_scope;
+};
+
+} // namespace JSC
+
+#endif // ScopedArguments_h
+
diff --git a/Source/JavaScriptCore/runtime/ScopedArgumentsTable.cpp b/Source/JavaScriptCore/runtime/ScopedArgumentsTable.cpp
new file mode 100644
index 000000000..23f536d49
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ScopedArgumentsTable.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "ScopedArgumentsTable.h"
+
+#include "JSCInlines.h"
+
+namespace JSC {
+
+const ClassInfo ScopedArgumentsTable::s_info = { "ScopedArgumentsTable", 0, 0, CREATE_METHOD_TABLE(ScopedArgumentsTable) };
+
+ScopedArgumentsTable::ScopedArgumentsTable(VM& vm)
+ : Base(vm, vm.scopedArgumentsTableStructure.get())
+ , m_length(0)
+ , m_locked(false)
+{
+}
+
+ScopedArgumentsTable::~ScopedArgumentsTable()
+{
+}
+
+void ScopedArgumentsTable::destroy(JSCell* cell)
+{
+ static_cast<ScopedArgumentsTable*>(cell)->ScopedArgumentsTable::~ScopedArgumentsTable();
+}
+
+ScopedArgumentsTable* ScopedArgumentsTable::create(VM& vm)
+{
+ ScopedArgumentsTable* result =
+ new (NotNull, allocateCell<ScopedArgumentsTable>(vm.heap)) ScopedArgumentsTable(vm);
+ result->finishCreation(vm);
+ return result;
+}
+
+ScopedArgumentsTable* ScopedArgumentsTable::create(VM& vm, uint32_t length)
+{
+ ScopedArgumentsTable* result = create(vm);
+ result->m_length = length;
+ result->m_arguments = std::make_unique<ScopeOffset[]>(length);
+ return result;
+}
+
+ScopedArgumentsTable* ScopedArgumentsTable::clone(VM& vm)
+{
+ ScopedArgumentsTable* result = create(vm, m_length);
+ for (unsigned i = m_length; i--;)
+ result->m_arguments[i] = m_arguments[i];
+ return result;
+}
+
+ScopedArgumentsTable* ScopedArgumentsTable::setLength(VM& vm, uint32_t newLength)
+{
+ if (LIKELY(!m_locked)) {
+ std::unique_ptr<ScopeOffset[]> newArguments = std::make_unique<ScopeOffset[]>(newLength);
+ for (unsigned i = std::min(m_length, newLength); i--;)
+ newArguments[i] = m_arguments[i];
+ m_length = newLength;
+ m_arguments = WTFMove(newArguments);
+ return this;
+ }
+
+ ScopedArgumentsTable* result = create(vm, newLength);
+ for (unsigned i = std::min(m_length, newLength); i--;)
+ result->m_arguments[i] = m_arguments[i];
+ return result;
+}
+
+ScopedArgumentsTable* ScopedArgumentsTable::set(VM& vm, uint32_t i, ScopeOffset value)
+{
+ ScopedArgumentsTable* result;
+ if (UNLIKELY(m_locked))
+ result = clone(vm);
+ else
+ result = this;
+ result->at(i) = value;
+ return result;
+}
+
+Structure* ScopedArgumentsTable::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/runtime/ScopedArgumentsTable.h b/Source/JavaScriptCore/runtime/ScopedArgumentsTable.h
new file mode 100644
index 000000000..b6d7ddc17
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ScopedArgumentsTable.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#ifndef ScopedArgumentsTable_h
+#define ScopedArgumentsTable_h
+
+#include "JSCell.h"
+#include "ScopeOffset.h"
+#include <wtf/Assertions.h>
+
+namespace JSC {
+
+// This class's only job is to hold onto the list of ScopeOffsets for each argument that a
+// function has. Most of the time, the BytecodeGenerator will create one of these and it will
+// never be modified subsequently. There is a rare case where a ScopedArguments object is created
+// and aliases one of these and then decides to modify it; in that case we do copy-on-write. This
+// makes sense because such modifications are so uncommon. You'd have to do something crazy like
+// "delete arguments[i]" or some variant of defineOwnProperty.
+class ScopedArgumentsTable final : public JSCell {
+public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+private:
+ ScopedArgumentsTable(VM&);
+ ~ScopedArgumentsTable();
+
+public:
+ static ScopedArgumentsTable* create(VM&);
+ static ScopedArgumentsTable* create(VM&, uint32_t length);
+
+ static const bool needsDestruction = true;
+ static void destroy(JSCell*);
+
+ ScopedArgumentsTable* clone(VM&);
+
+ uint32_t length() const { return m_length; }
+ ScopedArgumentsTable* setLength(VM&, uint32_t newLength);
+
+ ScopeOffset get(uint32_t i) const
+ {
+ return const_cast<ScopedArgumentsTable*>(this)->at(i);
+ }
+
+ void lock()
+ {
+ m_locked = true;
+ }
+
+ ScopedArgumentsTable* set(VM&, uint32_t index, ScopeOffset);
+
+ DECLARE_INFO;
+
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+
+ static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(ScopedArgumentsTable, m_length); }
+ static ptrdiff_t offsetOfArguments() { return OBJECT_OFFSETOF(ScopedArgumentsTable, m_arguments); }
+
+private:
+ ScopeOffset& at(uint32_t i)
+ {
+ ASSERT_WITH_SECURITY_IMPLICATION(i < m_length);
+ return m_arguments[i];
+ }
+
+ uint32_t m_length;
+ bool m_locked; // Being locked means that there are multiple references to this object and none of them expect to see the others' modifications. This means that modifications need to make a copy first.
+ std::unique_ptr<ScopeOffset[]> m_arguments;
+};
+
+} // namespace JSC
+
+#endif // ScopedArgumentsTable_h
+
diff --git a/Source/JavaScriptCore/runtime/SetConstructor.cpp b/Source/JavaScriptCore/runtime/SetConstructor.cpp
index b203888d3..ee42ece20 100644
--- a/Source/JavaScriptCore/runtime/SetConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/SetConstructor.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -27,49 +27,89 @@
#include "SetConstructor.h"
#include "Error.h"
+#include "GetterSetter.h"
+#include "IteratorOperations.h"
#include "JSCJSValueInlines.h"
#include "JSCellInlines.h"
#include "JSGlobalObject.h"
#include "JSSet.h"
#include "MapData.h"
#include "SetPrototype.h"
+#include "StructureInlines.h"
namespace JSC {
-const ClassInfo SetConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(SetConstructor) };
+const ClassInfo SetConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(SetConstructor) };
-void SetConstructor::finishCreation(VM& vm, SetPrototype* setPrototype)
+void SetConstructor::finishCreation(VM& vm, SetPrototype* setPrototype, GetterSetter* speciesSymbol)
{
Base::finishCreation(vm, setPrototype->classInfo()->className);
putDirectWithoutTransition(vm, vm.propertyNames->prototype, setPrototype, DontEnum | DontDelete | ReadOnly);
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum | DontDelete);
+ putDirectNonIndexAccessor(vm, vm.propertyNames->speciesSymbol, speciesSymbol, Accessor | ReadOnly | DontEnum);
}
-static EncodedJSValue JSC_HOST_CALL callSet(CallFrame* callFrame)
+static EncodedJSValue JSC_HOST_CALL callSet(ExecState* exec)
{
- // Until we have iterators we throw if we've been given
- // any arguments that could require us to throw.
- if (!callFrame->argument(0).isUndefinedOrNull())
- return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Set does not accept arguments when called as a function")));
- if (!callFrame->argument(1).isUndefined())
- return throwVMError(callFrame, createRangeError(callFrame, WTF::ASCIILiteral("Invalid comparator function")));
-
- JSGlobalObject* globalObject = asInternalFunction(callFrame->callee())->globalObject();
- Structure* setStructure = globalObject->setStructure();
- return JSValue::encode(JSSet::create(callFrame, setStructure));
+ return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(exec, "Set"));
}
-static EncodedJSValue JSC_HOST_CALL constructSet(CallFrame* callFrame)
+static EncodedJSValue JSC_HOST_CALL constructSet(ExecState* exec)
{
- JSGlobalObject* globalObject = asInternalFunction(callFrame->callee())->globalObject();
- Structure* setStructure = globalObject->setStructure();
- JSSet* set = JSSet::create(callFrame, setStructure);
- MapData* mapData = set->mapData();
- size_t count = callFrame->argumentCount();
- for (size_t i = 0; i < count; i++) {
- JSValue item = callFrame->uncheckedArgument(i);
- mapData->set(callFrame, item, item);
+ JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject();
+ Structure* setStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), globalObject->setStructure());
+ JSSet* set = JSSet::create(exec, setStructure);
+ JSValue iterable = exec->argument(0);
+ if (iterable.isUndefinedOrNull())
+ return JSValue::encode(set);
+
+ JSValue adderFunction = set->get(exec, exec->propertyNames().add);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ CallData adderFunctionCallData;
+ CallType adderFunctionCallType = getCallData(adderFunction, adderFunctionCallData);
+ if (adderFunctionCallType == CallTypeNone)
+ return JSValue::encode(throwTypeError(exec));
+
+ JSValue iteratorFunction = iterable.get(exec, exec->propertyNames().iteratorSymbol);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ CallData iteratorFunctionCallData;
+ CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData);
+ if (iteratorFunctionCallType == CallTypeNone)
+ return JSValue::encode(throwTypeError(exec));
+
+ ArgList iteratorFunctionArguments;
+ JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (!iterator.isObject())
+ return JSValue::encode(throwTypeError(exec));
+
+ while (true) {
+ JSValue next = iteratorStep(exec, iterator);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (next.isFalse())
+ return JSValue::encode(set);
+
+ JSValue nextValue = iteratorValue(exec, next);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(nextValue);
+ call(exec, adderFunction, adderFunctionCallType, adderFunctionCallData, set, arguments);
+ if (exec->hadException()) {
+ iteratorClose(exec, iterator);
+ return JSValue::encode(jsUndefined());
+ }
}
+ RELEASE_ASSERT_NOT_REACHED();
return JSValue::encode(set);
}
diff --git a/Source/JavaScriptCore/runtime/SetConstructor.h b/Source/JavaScriptCore/runtime/SetConstructor.h
index efbd88bb3..42fe3eefc 100644
--- a/Source/JavaScriptCore/runtime/SetConstructor.h
+++ b/Source/JavaScriptCore/runtime/SetConstructor.h
@@ -31,15 +31,16 @@
namespace JSC {
class SetPrototype;
+class GetterSetter;
class SetConstructor : public InternalFunction {
public:
typedef InternalFunction Base;
- static SetConstructor* create(VM& vm, Structure* structure, SetPrototype* setPrototype)
+ static SetConstructor* create(VM& vm, Structure* structure, SetPrototype* setPrototype, GetterSetter* speciesSymbol)
{
SetConstructor* constructor = new (NotNull, allocateCell<SetConstructor>(vm.heap)) SetConstructor(vm, structure);
- constructor->finishCreation(vm, setPrototype);
+ constructor->finishCreation(vm, setPrototype, speciesSymbol);
return constructor;
}
@@ -55,7 +56,7 @@ private:
: Base(vm, structure)
{
}
- void finishCreation(VM&, SetPrototype*);
+ void finishCreation(VM&, SetPrototype*, GetterSetter* speciesSymbol);
static ConstructType getConstructData(JSCell*, ConstructData&);
static CallType getCallData(JSCell*, CallData&);
};
diff --git a/Source/JavaScriptCore/runtime/SetIteratorPrototype.cpp b/Source/JavaScriptCore/runtime/SetIteratorPrototype.cpp
index 442d555ef..4448832f8 100644
--- a/Source/JavaScriptCore/runtime/SetIteratorPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/SetIteratorPrototype.cpp
@@ -26,31 +26,26 @@
#include "config.h"
#include "SetIteratorPrototype.h"
+#include "IteratorOperations.h"
#include "JSCJSValueInlines.h"
#include "JSCellInlines.h"
#include "JSSetIterator.h"
+#include "StructureInlines.h"
namespace JSC {
-const ClassInfo SetIteratorPrototype::s_info = { "Set Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(SetIteratorPrototype) };
+const ClassInfo SetIteratorPrototype::s_info = { "Set Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(SetIteratorPrototype) };
-static EncodedJSValue JSC_HOST_CALL SetIteratorPrototypeFuncIterator(ExecState*);
static EncodedJSValue JSC_HOST_CALL SetIteratorPrototypeFuncNext(ExecState*);
-
void SetIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
{
Base::finishCreation(vm);
ASSERT(inherits(info()));
vm.prototypeMap.addPrototype(this);
- JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, SetIteratorPrototypeFuncIterator, DontEnum, 0);
- JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorNextPrivateName, SetIteratorPrototypeFuncNext, DontEnum, 0);
-}
-
-EncodedJSValue JSC_HOST_CALL SetIteratorPrototypeFuncIterator(CallFrame* callFrame)
-{
- return JSValue::encode(callFrame->thisValue());
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->next, SetIteratorPrototypeFuncNext, DontEnum, 0);
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Set Iterator"), DontEnum | ReadOnly);
}
EncodedJSValue JSC_HOST_CALL SetIteratorPrototypeFuncNext(CallFrame* callFrame)
@@ -61,10 +56,9 @@ EncodedJSValue JSC_HOST_CALL SetIteratorPrototypeFuncNext(CallFrame* callFrame)
return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot call SetIterator.next() on a non-SetIterator object")));
if (iterator->next(callFrame, result))
- return JSValue::encode(result);
+ return JSValue::encode(createIteratorResultObject(callFrame, result, false));
iterator->finish();
- return JSValue::encode(callFrame->vm().iterationTerminator.get());
+ return JSValue::encode(createIteratorResultObject(callFrame, jsUndefined(), true));
}
-
}
diff --git a/Source/JavaScriptCore/runtime/SetPrototype.cpp b/Source/JavaScriptCore/runtime/SetPrototype.cpp
index 5eac51eee..c79b74b76 100644
--- a/Source/JavaScriptCore/runtime/SetPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/SetPrototype.cpp
@@ -30,22 +30,31 @@
#include "Error.h"
#include "ExceptionHelpers.h"
#include "GetterSetter.h"
+#include "IteratorOperations.h"
#include "JSCJSValueInlines.h"
#include "JSFunctionInlines.h"
#include "JSSet.h"
#include "JSSetIterator.h"
-#include "MapData.h"
+#include "Lookup.h"
+#include "MapDataInlines.h"
+#include "StructureInlines.h"
+
+#include "SetPrototype.lut.h"
namespace JSC {
-const ClassInfo SetPrototype::s_info = { "Set", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(SetPrototype) };
+const ClassInfo SetPrototype::s_info = { "Set", &Base::s_info, &setPrototypeTable, CREATE_METHOD_TABLE(SetPrototype) };
+
+/* Source for SetIteratorPrototype.lut.h
+@begin setPrototypeTable
+ forEach JSBuiltin DontEnum|Function 0
+@end
+*/
static EncodedJSValue JSC_HOST_CALL setProtoFuncAdd(ExecState*);
static EncodedJSValue JSC_HOST_CALL setProtoFuncClear(ExecState*);
static EncodedJSValue JSC_HOST_CALL setProtoFuncDelete(ExecState*);
-static EncodedJSValue JSC_HOST_CALL setProtoFuncForEach(ExecState*);
static EncodedJSValue JSC_HOST_CALL setProtoFuncHas(ExecState*);
-static EncodedJSValue JSC_HOST_CALL setProtoFuncKeys(ExecState*);
static EncodedJSValue JSC_HOST_CALL setProtoFuncValues(ExecState*);
static EncodedJSValue JSC_HOST_CALL setProtoFuncEntries(ExecState*);
@@ -58,113 +67,92 @@ void SetPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
ASSERT(inherits(info()));
vm.prototypeMap.addPrototype(this);
- JSC_NATIVE_FUNCTION(vm.propertyNames->add, setProtoFuncAdd, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->clear, setProtoFuncClear, DontEnum, 0);
- JSC_NATIVE_FUNCTION(vm.propertyNames->deleteKeyword, setProtoFuncDelete, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->forEach, setProtoFuncForEach, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->has, setProtoFuncHas, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->keys, setProtoFuncKeys, DontEnum, 0);
- JSC_NATIVE_FUNCTION(vm.propertyNames->values, setProtoFuncValues, DontEnum, 0);
- JSC_NATIVE_FUNCTION(vm.propertyNames->entries, setProtoFuncEntries, DontEnum, 0);
- JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, setProtoFuncKeys, DontEnum, 0);
-
- GetterSetter* accessor = GetterSetter::create(vm);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->add, setProtoFuncAdd, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->clear, setProtoFuncClear, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->deleteKeyword, setProtoFuncDelete, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, setProtoFuncHas, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->entries, setProtoFuncEntries, DontEnum, 0);
+
+ JSFunction* values = JSFunction::create(vm, globalObject, 0, vm.propertyNames->values.string(), setProtoFuncValues);
+ putDirectWithoutTransition(vm, vm.propertyNames->values, values, DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->keys, values, DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, values, DontEnum);
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Set"), DontEnum | ReadOnly);
+
+ GetterSetter* accessor = GetterSetter::create(vm, globalObject);
JSFunction* function = JSFunction::create(vm, globalObject, 0, vm.propertyNames->size.string(), setProtoFuncSize);
- accessor->setGetter(vm, function);
+ accessor->setGetter(vm, globalObject, function);
putDirectNonIndexAccessor(vm, vm.propertyNames->size, accessor, DontEnum | Accessor);
}
-ALWAYS_INLINE static MapData* getMapData(CallFrame* callFrame, JSValue thisValue)
+bool SetPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<Base>(exec, setPrototypeTable, jsCast<SetPrototype*>(object), propertyName, slot);
+}
+
+
+ALWAYS_INLINE static JSSet* getSet(CallFrame* callFrame, JSValue thisValue)
{
if (!thisValue.isObject()) {
throwVMError(callFrame, createNotAnObjectError(callFrame, thisValue));
- return 0;
+ return nullptr;
}
JSSet* set = jsDynamicCast<JSSet*>(thisValue);
if (!set) {
throwTypeError(callFrame, ASCIILiteral("Set operation called on non-Set object"));
- return 0;
+ return nullptr;
}
- return set->mapData();
+ return set;
}
EncodedJSValue JSC_HOST_CALL setProtoFuncAdd(CallFrame* callFrame)
{
- MapData* data = getMapData(callFrame, callFrame->thisValue());
- if (!data)
+ JSValue thisValue = callFrame->thisValue();
+ JSSet* set = getSet(callFrame, thisValue);
+ if (!set)
return JSValue::encode(jsUndefined());
- data->set(callFrame, callFrame->argument(0), callFrame->argument(0));
- return JSValue::encode(callFrame->thisValue());
+ set->add(callFrame, callFrame->argument(0));
+ return JSValue::encode(thisValue);
}
EncodedJSValue JSC_HOST_CALL setProtoFuncClear(CallFrame* callFrame)
{
- MapData* data = getMapData(callFrame, callFrame->thisValue());
- if (!data)
+ JSSet* set = getSet(callFrame, callFrame->thisValue());
+ if (!set)
return JSValue::encode(jsUndefined());
- data->clear();
+ set->clear(callFrame);
return JSValue::encode(jsUndefined());
}
EncodedJSValue JSC_HOST_CALL setProtoFuncDelete(CallFrame* callFrame)
{
- MapData* data = getMapData(callFrame, callFrame->thisValue());
- if (!data)
+ JSSet* set = getSet(callFrame, callFrame->thisValue());
+ if (!set)
return JSValue::encode(jsUndefined());
- return JSValue::encode(jsBoolean(data->remove(callFrame, callFrame->argument(0))));
-}
-
-EncodedJSValue JSC_HOST_CALL setProtoFuncForEach(CallFrame* callFrame)
-{
- MapData* data = getMapData(callFrame, callFrame->thisValue());
- if (!data)
- return JSValue::encode(jsUndefined());
- JSValue callBack = callFrame->argument(0);
- CallData callData;
- CallType callType = getCallData(callBack, callData);
- if (callType == CallTypeNone)
- return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("Set.prototype.forEach called without callback")));
- JSValue thisValue = callFrame->argument(1);
- VM* vm = &callFrame->vm();
- if (callType == CallTypeJS) {
- JSFunction* function = jsCast<JSFunction*>(callBack);
- CachedCall cachedCall(callFrame, function, 1);
- for (auto ptr = data->begin(), end = data->end(); ptr != end && !vm->exception(); ++ptr) {
- cachedCall.setThis(thisValue);
- cachedCall.setArgument(0, ptr.key());
- cachedCall.call();
- }
- } else {
- for (auto ptr = data->begin(), end = data->end(); ptr != end && !vm->exception(); ++ptr) {
- MarkedArgumentBuffer args;
- args.append(ptr.key());
- JSC::call(callFrame, callBack, callType, callData, thisValue, args);
- }
- }
- return JSValue::encode(jsUndefined());
+ return JSValue::encode(jsBoolean(set->remove(callFrame, callFrame->argument(0))));
}
EncodedJSValue JSC_HOST_CALL setProtoFuncHas(CallFrame* callFrame)
{
- MapData* data = getMapData(callFrame, callFrame->thisValue());
- if (!data)
+ JSSet* set = getSet(callFrame, callFrame->thisValue());
+ if (!set)
return JSValue::encode(jsUndefined());
- return JSValue::encode(jsBoolean(data->contains(callFrame, callFrame->argument(0))));
+ return JSValue::encode(jsBoolean(set->has(callFrame, callFrame->argument(0))));
}
EncodedJSValue JSC_HOST_CALL setProtoFuncSize(CallFrame* callFrame)
{
- MapData* data = getMapData(callFrame, callFrame->thisValue());
- if (!data)
+ JSSet* set = getSet(callFrame, callFrame->thisValue());
+ if (!set)
return JSValue::encode(jsUndefined());
- return JSValue::encode(jsNumber(data->size(callFrame)));
+ return JSValue::encode(jsNumber(set->size(callFrame)));
}
EncodedJSValue JSC_HOST_CALL setProtoFuncValues(CallFrame* callFrame)
{
JSSet* thisObj = jsDynamicCast<JSSet*>(callFrame->thisValue());
if (!thisObj)
- return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Map value iterator for a non-Map object.")));
+ return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Set value iterator for a non-Set object.")));
return JSValue::encode(JSSetIterator::create(callFrame->vm(), callFrame->callee()->globalObject()->setIteratorStructure(), thisObj, SetIterateValue));
}
@@ -172,16 +160,34 @@ EncodedJSValue JSC_HOST_CALL setProtoFuncEntries(CallFrame* callFrame)
{
JSSet* thisObj = jsDynamicCast<JSSet*>(callFrame->thisValue());
if (!thisObj)
- return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Map key iterator for a non-Map object.")));
+ return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Set entry iterator for a non-Set object.")));
return JSValue::encode(JSSetIterator::create(callFrame->vm(), callFrame->callee()->globalObject()->setIteratorStructure(), thisObj, SetIterateKeyValue));
}
-EncodedJSValue JSC_HOST_CALL setProtoFuncKeys(CallFrame* callFrame)
+EncodedJSValue JSC_HOST_CALL privateFuncIsSet(ExecState* exec)
{
- JSSet* thisObj = jsDynamicCast<JSSet*>(callFrame->thisValue());
- if (!thisObj)
- return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot create a Map entry iterator for a non-Map object.")));
- return JSValue::encode(JSSetIterator::create(callFrame->vm(), callFrame->callee()->globalObject()->setIteratorStructure(), thisObj, SetIterateKey));
+ return JSValue::encode(jsBoolean(jsDynamicCast<JSSet*>(exec->uncheckedArgument(0))));
+}
+
+EncodedJSValue JSC_HOST_CALL privateFuncSetIterator(ExecState* exec)
+{
+ ASSERT(jsDynamicCast<JSSet*>(exec->uncheckedArgument(0)));
+ JSSet* set = jsCast<JSSet*>(exec->uncheckedArgument(0));
+ return JSValue::encode(JSSetIterator::create(exec->vm(), exec->callee()->globalObject()->setIteratorStructure(), set, SetIterateKey));
+}
+
+EncodedJSValue JSC_HOST_CALL privateFuncSetIteratorNext(ExecState* exec)
+{
+ ASSERT(jsDynamicCast<JSSetIterator*>(exec->thisValue()));
+ JSSetIterator* iterator = jsCast<JSSetIterator*>(exec->thisValue());
+ JSValue result;
+ if (iterator->next(exec, result)) {
+ JSArray* resultArray = jsCast<JSArray*>(exec->uncheckedArgument(0));
+ resultArray->putDirectIndex(exec, 0, result);
+ return JSValue::encode(jsBoolean(false));
+ }
+ iterator->finish();
+ return JSValue::encode(jsBoolean(true));
}
}
diff --git a/Source/JavaScriptCore/runtime/SetPrototype.h b/Source/JavaScriptCore/runtime/SetPrototype.h
index bdf90f433..e2719a62a 100644
--- a/Source/JavaScriptCore/runtime/SetPrototype.h
+++ b/Source/JavaScriptCore/runtime/SetPrototype.h
@@ -34,6 +34,8 @@ class SetPrototype : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | Base::StructureFlags;
+
static SetPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
{
SetPrototype* prototype = new (NotNull, allocateCell<SetPrototype>(vm.heap)) SetPrototype(vm, structure);
@@ -54,8 +56,13 @@ private:
{
}
void finishCreation(VM&, JSGlobalObject*);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
};
+EncodedJSValue JSC_HOST_CALL privateFuncIsSet(ExecState*);
+EncodedJSValue JSC_HOST_CALL privateFuncSetIterator(ExecState*);
+EncodedJSValue JSC_HOST_CALL privateFuncSetIteratorNext(ExecState*);
+
}
#endif // !defined(SetPrototype_h)
diff --git a/Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp b/Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp
index dd68aac2a..9245c2c5d 100644
--- a/Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp
+++ b/Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp
@@ -28,7 +28,7 @@
#include "ArrayBuffer.h"
#include "JSArrayBuffer.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
diff --git a/Source/JavaScriptCore/runtime/SlowPathReturnType.h b/Source/JavaScriptCore/runtime/SlowPathReturnType.h
new file mode 100644
index 000000000..27cfb951c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/SlowPathReturnType.h
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#ifndef SlowPathReturnType_h
+#define SlowPathReturnType_h
+
+#include <wtf/StdLibExtras.h>
+
+namespace JSC {
+
+#if USE(JSVALUE64)
+// According to C++ rules, a type used for the return signature of function with C linkage (i.e.
+// 'extern "C"') needs to be POD; hence putting any constructors into it could cause either compiler
+// warnings, or worse, a change in the ABI used to return these types.
+struct SlowPathReturnType {
+ void* a;
+ void* b;
+};
+
+inline SlowPathReturnType encodeResult(void* a, void* b)
+{
+ SlowPathReturnType result;
+ result.a = a;
+ result.b = b;
+ return result;
+}
+
+inline void decodeResult(SlowPathReturnType result, void*& a, void*& b)
+{
+ a = result.a;
+ b = result.b;
+}
+
+#else // USE(JSVALUE32_64)
+typedef int64_t SlowPathReturnType;
+
+typedef union {
+ struct {
+ void* a;
+ void* b;
+ } pair;
+ int64_t i;
+} SlowPathReturnTypeEncoding;
+
+inline SlowPathReturnType encodeResult(void* a, void* b)
+{
+ SlowPathReturnTypeEncoding u;
+ u.pair.a = a;
+ u.pair.b = b;
+ return u.i;
+}
+
+inline void decodeResult(SlowPathReturnType result, void*& a, void*& b)
+{
+ SlowPathReturnTypeEncoding u;
+ u.i = result;
+ a = u.pair.a;
+ b = u.pair.b;
+}
+#endif // USE(JSVALUE32_64)
+
+} // namespace JSC
+
+#endif // SlowPathReturnType_h
diff --git a/Source/JavaScriptCore/runtime/SmallStrings.cpp b/Source/JavaScriptCore/runtime/SmallStrings.cpp
index ff304039c..947518607 100644
--- a/Source/JavaScriptCore/runtime/SmallStrings.cpp
+++ b/Source/JavaScriptCore/runtime/SmallStrings.cpp
@@ -29,9 +29,8 @@
#include "HeapRootVisitor.h"
#include "JSGlobalObject.h"
#include "JSString.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include <wtf/Noncopyable.h>
-#include <wtf/PassOwnPtr.h>
#include <wtf/text/StringImpl.h>
namespace JSC {
@@ -58,7 +57,7 @@ SmallStringsStorage::SmallStringsStorage()
RefPtr<StringImpl> baseString = StringImpl::createUninitialized(singleCharacterStringCount, characterBuffer);
for (unsigned i = 0; i < singleCharacterStringCount; ++i) {
characterBuffer[i] = i;
- m_reps[i] = StringImpl::create(baseString, i, 1);
+ m_reps[i] = AtomicStringImpl::add(PassRefPtr<StringImpl>(StringImpl::createSubstringSharingImpl(baseString, i, 1)).get());
}
}
@@ -67,6 +66,10 @@ SmallStrings::SmallStrings()
#define JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE(name) , m_##name(0)
JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE)
#undef JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE
+ , m_objectStringStart(nullptr)
+ , m_nullObjectString(nullptr)
+ , m_undefinedObjectString(nullptr)
+ , m_needsToBeVisited(true)
{
COMPILE_ASSERT(singleCharacterStringCount == sizeof(m_singleCharacterStrings) / sizeof(m_singleCharacterStrings[0]), IsNumCharactersConstInSyncWithClassUsage);
@@ -82,16 +85,23 @@ void SmallStrings::initializeCommonStrings(VM& vm)
#define JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE(name) initialize(&vm, m_##name, #name);
JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE)
#undef JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE
+ initialize(&vm, m_objectStringStart, "[object ");
+ initialize(&vm, m_nullObjectString, "[object Null]");
+ initialize(&vm, m_undefinedObjectString, "[object Undefined]");
}
void SmallStrings::visitStrongReferences(SlotVisitor& visitor)
{
+ m_needsToBeVisited = false;
visitor.appendUnbarrieredPointer(&m_emptyString);
for (unsigned i = 0; i <= maxSingleCharacterString; ++i)
visitor.appendUnbarrieredPointer(m_singleCharacterStrings + i);
#define JSC_COMMON_STRINGS_ATTRIBUTE_VISIT(name) visitor.appendUnbarrieredPointer(&m_##name);
JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_VISIT)
#undef JSC_COMMON_STRINGS_ATTRIBUTE_VISIT
+ visitor.appendUnbarrieredPointer(&m_objectStringStart);
+ visitor.appendUnbarrieredPointer(&m_nullObjectString);
+ visitor.appendUnbarrieredPointer(&m_undefinedObjectString);
}
SmallStrings::~SmallStrings()
@@ -102,26 +112,29 @@ void SmallStrings::createEmptyString(VM* vm)
{
ASSERT(!m_emptyString);
m_emptyString = JSString::createHasOtherOwner(*vm, StringImpl::empty());
+ ASSERT(m_needsToBeVisited);
}
void SmallStrings::createSingleCharacterString(VM* vm, unsigned char character)
{
if (!m_storage)
- m_storage = adoptPtr(new SmallStringsStorage);
+ m_storage = std::make_unique<SmallStringsStorage>();
ASSERT(!m_singleCharacterStrings[character]);
m_singleCharacterStrings[character] = JSString::createHasOtherOwner(*vm, PassRefPtr<StringImpl>(m_storage->rep(character)));
+ ASSERT(m_needsToBeVisited);
}
StringImpl* SmallStrings::singleCharacterStringRep(unsigned char character)
{
if (!m_storage)
- m_storage = adoptPtr(new SmallStringsStorage);
+ m_storage = std::make_unique<SmallStringsStorage>();
return m_storage->rep(character);
}
-void SmallStrings::initialize(VM* vm, JSString*& string, const char* value) const
+void SmallStrings::initialize(VM* vm, JSString*& string, const char* value)
{
- string = JSString::create(*vm, StringImpl::create(value));
+ string = JSString::create(*vm, Identifier::fromString(vm, value).impl());
+ ASSERT(m_needsToBeVisited);
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/SmallStrings.h b/Source/JavaScriptCore/runtime/SmallStrings.h
index 0e8646a71..b90394edb 100644
--- a/Source/JavaScriptCore/runtime/SmallStrings.h
+++ b/Source/JavaScriptCore/runtime/SmallStrings.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2009, 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
@@ -26,9 +26,9 @@
#ifndef SmallStrings_h
#define SmallStrings_h
+#include "TypeofType.h"
#include "WriteBarrier.h"
#include <wtf/Noncopyable.h>
-#include <wtf/OwnPtr.h>
#define JSC_COMMON_STRINGS_EACH_NAME(macro) \
macro(boolean) \
@@ -39,6 +39,7 @@
macro(object) \
macro(undefined) \
macro(string) \
+ macro(symbol) \
macro(true)
namespace WTF {
@@ -47,60 +48,97 @@ class StringImpl;
namespace JSC {
- class HeapRootVisitor;
- class VM;
- class JSString;
- class SmallStringsStorage;
- class SlotVisitor;
+class VM;
+class JSString;
+class SmallStringsStorage;
+class SlotVisitor;
- static const unsigned maxSingleCharacterString = 0xFF;
+static const unsigned maxSingleCharacterString = 0xFF;
- class SmallStrings {
- WTF_MAKE_NONCOPYABLE(SmallStrings);
- public:
- SmallStrings();
- ~SmallStrings();
+class SmallStrings {
+ WTF_MAKE_NONCOPYABLE(SmallStrings);
+public:
+ SmallStrings();
+ ~SmallStrings();
- JSString* emptyString()
- {
- return m_emptyString;
- }
+ JSString* emptyString()
+ {
+ return m_emptyString;
+ }
- JSString* singleCharacterString(unsigned char character)
- {
- return m_singleCharacterStrings[character];
- }
+ JSString* singleCharacterString(unsigned char character)
+ {
+ return m_singleCharacterStrings[character];
+ }
- JS_EXPORT_PRIVATE WTF::StringImpl* singleCharacterStringRep(unsigned char character);
+ JS_EXPORT_PRIVATE WTF::StringImpl* singleCharacterStringRep(unsigned char character);
- JSString** singleCharacterStrings() { return &m_singleCharacterStrings[0]; }
+ JSString** singleCharacterStrings() { return &m_singleCharacterStrings[0]; }
- void initializeCommonStrings(VM&);
- void visitStrongReferences(SlotVisitor&);
+ void initializeCommonStrings(VM&);
+ void visitStrongReferences(SlotVisitor&);
#define JSC_COMMON_STRINGS_ACCESSOR_DEFINITION(name) \
- JSString* name##String() const \
- { \
- return m_##name; \
- }
- JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ACCESSOR_DEFINITION)
+ JSString* name##String() const \
+ { \
+ return m_##name; \
+ }
+ JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ACCESSOR_DEFINITION)
#undef JSC_COMMON_STRINGS_ACCESSOR_DEFINITION
+
+ JSString* typeString(TypeofType type) const
+ {
+ switch (type) {
+ case TypeofType::Undefined:
+ return undefinedString();
+ case TypeofType::Boolean:
+ return booleanString();
+ case TypeofType::Number:
+ return numberString();
+ case TypeofType::String:
+ return stringString();
+ case TypeofType::Symbol:
+ return symbolString();
+ case TypeofType::Object:
+ return objectString();
+ case TypeofType::Function:
+ return functionString();
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+ return nullptr;
+ }
+
+ JSString* objectStringStart() const { return m_objectStringStart; }
+ JSString* nullObjectString() const { return m_nullObjectString; }
+ JSString* undefinedObjectString() const { return m_undefinedObjectString; }
+
+ bool needsToBeVisited(HeapOperation collectionType) const
+ {
+ if (collectionType == FullCollection)
+ return true;
+ return m_needsToBeVisited;
+ }
- private:
- static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1;
+private:
+ static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1;
- JS_EXPORT_PRIVATE void createEmptyString(VM*);
- JS_EXPORT_PRIVATE void createSingleCharacterString(VM*, unsigned char);
+ void createEmptyString(VM*);
+ void createSingleCharacterString(VM*, unsigned char);
- void initialize(VM* vm, JSString*& string, const char* value) const;
+ void initialize(VM*, JSString*&, const char* value);
- JSString* m_emptyString;
+ JSString* m_emptyString;
#define JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION(name) JSString* m_##name;
- JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION)
+ JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION)
#undef JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION
- JSString* m_singleCharacterStrings[singleCharacterStringCount];
- OwnPtr<SmallStringsStorage> m_storage;
- };
+ JSString* m_objectStringStart;
+ JSString* m_nullObjectString;
+ JSString* m_undefinedObjectString;
+ JSString* m_singleCharacterStrings[singleCharacterStringCount];
+ std::unique_ptr<SmallStringsStorage> m_storage;
+ bool m_needsToBeVisited;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp b/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp
index 0db43b7b6..24d5244af 100644
--- a/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp
+++ b/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 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
@@ -29,7 +29,7 @@
#include "ClassInfo.h"
#include "GetterSetter.h"
#include "JSObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "PropertySlot.h"
#include "Reject.h"
#include "SlotVisitor.h"
@@ -37,7 +37,7 @@
namespace JSC {
-const ClassInfo SparseArrayValueMap::s_info = { "SparseArrayValueMap", 0, 0, 0, CREATE_METHOD_TABLE(SparseArrayValueMap) };
+const ClassInfo SparseArrayValueMap::s_info = { "SparseArrayValueMap", 0, 0, CREATE_METHOD_TABLE(SparseArrayValueMap) };
SparseArrayValueMap::SparseArrayValueMap(VM& vm)
: Base(vm, vm.sparseArrayValueMapStructure.get())
@@ -69,7 +69,7 @@ void SparseArrayValueMap::destroy(JSCell* cell)
Structure* SparseArrayValueMap::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), info());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
}
SparseArrayValueMap::AddResult SparseArrayValueMap::add(JSObject* array, unsigned i)
@@ -80,7 +80,9 @@ SparseArrayValueMap::AddResult SparseArrayValueMap::add(JSObject* array, unsigne
AddResult result = m_map.add(i, entry);
size_t capacity = m_map.capacity();
if (capacity != m_reportedCapacity) {
- Heap::heap(array)->reportExtraMemoryCost((capacity - m_reportedCapacity) * (sizeof(unsigned) + sizeof(WriteBarrier<Unknown>)));
+ // FIXME: Adopt reportExtraMemoryVisited, and switch to reportExtraMemoryAllocated.
+ // https://bugs.webkit.org/show_bug.cgi?id=142595
+ Heap::heap(array)->deprecatedReportExtraMemory((capacity - m_reportedCapacity) * (sizeof(unsigned) + sizeof(WriteBarrier<Unknown>)));
m_reportedCapacity = capacity;
}
return result;
@@ -88,6 +90,8 @@ SparseArrayValueMap::AddResult SparseArrayValueMap::add(JSObject* array, unsigne
void SparseArrayValueMap::putEntry(ExecState* exec, JSObject* array, unsigned i, JSValue value, bool shouldThrow)
{
+ ASSERT(value);
+
AddResult result = add(array, i);
SparseArrayEntry& entry = result.iterator->value;
@@ -106,6 +110,8 @@ void SparseArrayValueMap::putEntry(ExecState* exec, JSObject* array, unsigned i,
bool SparseArrayValueMap::putDirect(ExecState* exec, JSObject* array, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode)
{
+ ASSERT(value);
+
AddResult result = add(array, i);
SparseArrayEntry& entry = result.iterator->value;
@@ -140,17 +146,6 @@ void SparseArrayEntry::get(PropertyDescriptor& descriptor) const
descriptor.setDescriptor(Base::get(), attributes);
}
-JSValue SparseArrayEntry::get(ExecState* exec, JSObject* array) const
-{
- JSValue value = Base::get();
- ASSERT(value);
-
- if (LIKELY(!value.isGetterSetter()))
- return value;
-
- return callGetter(exec, array, jsCast<GetterSetter*>(value));
-}
-
void SparseArrayEntry::put(ExecState* exec, JSValue thisValue, SparseArrayValueMap* map, JSValue value, bool shouldThrow)
{
if (!(attributes & Accessor)) {
diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMap.h b/Source/JavaScriptCore/runtime/SparseArrayValueMap.h
index 113beb350..0754b53d9 100644
--- a/Source/JavaScriptCore/runtime/SparseArrayValueMap.h
+++ b/Source/JavaScriptCore/runtime/SparseArrayValueMap.h
@@ -32,7 +32,6 @@
#include "PutDirectIndexMode.h"
#include "WriteBarrier.h"
#include <wtf/HashMap.h>
-#include <wtf/Platform.h>
namespace JSC {
@@ -43,7 +42,6 @@ struct SparseArrayEntry : public WriteBarrier<Unknown> {
SparseArrayEntry() : attributes(0) { }
- JSValue get(ExecState*, JSObject*) const;
void get(JSObject*, PropertySlot&) const;
void get(PropertyDescriptor&) const;
void put(ExecState*, JSValue thisValue, SparseArrayValueMap*, JSValue, bool shouldThrow);
@@ -52,9 +50,10 @@ struct SparseArrayEntry : public WriteBarrier<Unknown> {
unsigned attributes;
};
-class SparseArrayValueMap : public JSCell {
+class SparseArrayValueMap final : public JSCell {
public:
typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
private:
typedef HashMap<uint64_t, SparseArrayEntry, WTF::IntHash<uint64_t>, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>> Map;
@@ -70,8 +69,6 @@ private:
void finishCreation(VM&);
- static const unsigned StructureFlags = OverridesVisitChildren | JSCell::StructureFlags;
-
public:
DECLARE_EXPORT_INFO;
@@ -82,7 +79,6 @@ public:
static SparseArrayValueMap* create(VM&);
static const bool needsDestruction = true;
- static const bool hasImmortalStructure = true;
static void destroy(JSCell*);
static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
diff --git a/Source/JavaScriptCore/runtime/StackAlignment.h b/Source/JavaScriptCore/runtime/StackAlignment.h
index b803e4ded..d29802b3f 100644
--- a/Source/JavaScriptCore/runtime/StackAlignment.h
+++ b/Source/JavaScriptCore/runtime/StackAlignment.h
@@ -27,6 +27,8 @@
#define StackAlignment_h
#include "JSCJSValue.h"
+#include "JSStack.h"
+#include <wtf/MathExtras.h>
namespace JSC {
@@ -38,6 +40,25 @@ inline unsigned stackAlignmentRegisters()
return stackAlignmentBytes() / sizeof(EncodedJSValue);
}
+// Align argument count taking into account the CallFrameHeaderSize may be
+// an "unaligned" count of registers.
+inline unsigned roundArgumentCountToAlignFrame(unsigned argumentCount)
+{
+ return WTF::roundUpToMultipleOf(stackAlignmentRegisters(), argumentCount + JSStack::CallFrameHeaderSize) - JSStack::CallFrameHeaderSize;
+}
+
+// Align local register count to make the last local end on a stack aligned address given the
+// CallFrame is at an address that is stack aligned minus JSStack::CallerFrameAndPCSize
+inline unsigned roundLocalRegisterCountForFramePointerOffset(unsigned localRegisterCount)
+{
+ return WTF::roundUpToMultipleOf(stackAlignmentRegisters(), localRegisterCount + JSStack::CallerFrameAndPCSize) - JSStack::CallerFrameAndPCSize;
+}
+
+inline unsigned logStackAlignmentRegisters()
+{
+ return WTF::fastLog2(stackAlignmentRegisters());
+}
+
} // namespace JSC
#endif // StackAlignment_h
diff --git a/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp b/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp
index e2ff9acd7..4260e10b9 100644
--- a/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp
+++ b/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp
@@ -27,19 +27,19 @@
#include "StrictEvalActivation.h"
#include "JSGlobalObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(StrictEvalActivation);
-const ClassInfo StrictEvalActivation::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(StrictEvalActivation) };
+const ClassInfo StrictEvalActivation::s_info = { "Object", &Base::s_info, 0, CREATE_METHOD_TABLE(StrictEvalActivation) };
-StrictEvalActivation::StrictEvalActivation(ExecState* exec)
+StrictEvalActivation::StrictEvalActivation(ExecState* exec, JSScope* currentScope)
: Base(
exec->vm(),
exec->lexicalGlobalObject()->strictEvalActivationStructure(),
- exec->scope()
+ currentScope
)
{
}
diff --git a/Source/JavaScriptCore/runtime/StrictEvalActivation.h b/Source/JavaScriptCore/runtime/StrictEvalActivation.h
index e02bb615d..13157f68a 100644
--- a/Source/JavaScriptCore/runtime/StrictEvalActivation.h
+++ b/Source/JavaScriptCore/runtime/StrictEvalActivation.h
@@ -33,12 +33,13 @@ namespace JSC {
class StrictEvalActivation : public JSScope {
public:
typedef JSScope Base;
+ static const unsigned StructureFlags = Base::StructureFlags | IsEnvironmentRecord;
- static StrictEvalActivation* create(ExecState* exec)
+ static StrictEvalActivation* create(ExecState* exec, JSScope* currentScope)
{
- StrictEvalActivation* activation = new (NotNull, allocateCell<StrictEvalActivation>(*exec->heap())) StrictEvalActivation(exec);
- activation->finishCreation(exec->vm());
- return activation;
+ StrictEvalActivation* lexicalEnvironment = new (NotNull, allocateCell<StrictEvalActivation>(*exec->heap())) StrictEvalActivation(exec, currentScope);
+ lexicalEnvironment->finishCreation(exec->vm());
+ return lexicalEnvironment;
}
static bool deleteProperty(JSCell*, ExecState*, PropertyName);
@@ -51,11 +52,8 @@ public:
DECLARE_INFO;
-protected:
- static const unsigned StructureFlags = IsEnvironmentRecord | Base::StructureFlags;
-
private:
- StrictEvalActivation(ExecState*);
+ StrictEvalActivation(ExecState*, JSScope*);
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StringConstructor.cpp b/Source/JavaScriptCore/runtime/StringConstructor.cpp
index 207d8585a..835d24649 100644
--- a/Source/JavaScriptCore/runtime/StringConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/StringConstructor.cpp
@@ -21,16 +21,18 @@
#include "config.h"
#include "StringConstructor.h"
+#include "Error.h"
#include "Executable.h"
#include "JITCode.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "StringPrototype.h"
namespace JSC {
static EncodedJSValue JSC_HOST_CALL stringFromCharCode(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringFromCodePoint(ExecState*);
}
@@ -38,11 +40,13 @@ static EncodedJSValue JSC_HOST_CALL stringFromCharCode(ExecState*);
namespace JSC {
-const ClassInfo StringConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::stringConstructorTable, CREATE_METHOD_TABLE(StringConstructor) };
+const ClassInfo StringConstructor::s_info = { "Function", &InternalFunction::s_info, &stringConstructorTable, CREATE_METHOD_TABLE(StringConstructor) };
/* Source for StringConstructor.lut.h
@begin stringConstructorTable
fromCharCode stringFromCharCode DontEnum|Function 1
+ fromCodePoint stringFromCodePoint DontEnum|Function 1
+ raw JSBuiltin DontEnum|Function 1
@end
*/
@@ -62,7 +66,7 @@ void StringConstructor::finishCreation(VM& vm, StringPrototype* stringPrototype)
bool StringConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
{
- return getStaticFunctionSlot<InternalFunction>(exec, ExecState::stringConstructorTable(exec->vm()), jsCast<StringConstructor*>(object), propertyName, slot);
+ return getStaticFunctionSlot<InternalFunction>(exec, stringConstructorTable, jsCast<StringConstructor*>(object), propertyName, slot);
}
// ------------------------------ Functions --------------------------------
@@ -89,15 +93,42 @@ JSCell* JSC_HOST_CALL stringFromCharCode(ExecState* exec, int32_t arg)
return jsSingleCharacterString(exec, arg);
}
+static EncodedJSValue JSC_HOST_CALL stringFromCodePoint(ExecState* exec)
+{
+ unsigned length = exec->argumentCount();
+ StringBuilder builder;
+ builder.reserveCapacity(length);
+
+ for (unsigned i = 0; i < length; ++i) {
+ double codePointAsDouble = exec->uncheckedArgument(i).toNumber(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ uint32_t codePoint = static_cast<uint32_t>(codePointAsDouble);
+
+ if (codePoint != codePointAsDouble || codePoint > UCHAR_MAX_VALUE)
+ return throwVMError(exec, createRangeError(exec, ASCIILiteral("Arguments contain a value that is out of range of code points")));
+
+ if (U_IS_BMP(codePoint))
+ builder.append(static_cast<UChar>(codePoint));
+ else {
+ builder.append(U16_LEAD(codePoint));
+ builder.append(U16_TRAIL(codePoint));
+ }
+ }
+
+ return JSValue::encode(jsString(exec, builder.toString()));
+}
+
static EncodedJSValue JSC_HOST_CALL constructWithStringConstructor(ExecState* exec)
{
JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject();
VM& vm = exec->vm();
if (!exec->argumentCount())
- return JSValue::encode(StringObject::create(vm, globalObject->stringObjectStructure()));
-
- return JSValue::encode(StringObject::create(vm, globalObject->stringObjectStructure(), exec->uncheckedArgument(0).toString(exec)));
+ return JSValue::encode(StringObject::create(vm, InternalFunction::createSubclassStructure(exec, exec->newTarget(), globalObject->stringObjectStructure())));
+
+ return JSValue::encode(StringObject::create(vm, InternalFunction::createSubclassStructure(exec, exec->newTarget(), globalObject->stringObjectStructure()), exec->uncheckedArgument(0).toString(exec)));
}
ConstructType StringConstructor::getConstructData(JSCell*, ConstructData& constructData)
@@ -106,11 +137,18 @@ ConstructType StringConstructor::getConstructData(JSCell*, ConstructData& constr
return ConstructTypeHost;
}
+JSCell* stringConstructor(ExecState* exec, JSValue argument)
+{
+ if (argument.isSymbol())
+ return jsNontrivialString(exec, asSymbol(argument)->descriptiveString());
+ return argument.toString(exec);
+}
+
static EncodedJSValue JSC_HOST_CALL callStringConstructor(ExecState* exec)
{
if (!exec->argumentCount())
return JSValue::encode(jsEmptyString(exec));
- return JSValue::encode(exec->uncheckedArgument(0).toString(exec));
+ return JSValue::encode(stringConstructor(exec, exec->uncheckedArgument(0)));
}
CallType StringConstructor::getCallData(JSCell*, CallData& callData)
diff --git a/Source/JavaScriptCore/runtime/StringConstructor.h b/Source/JavaScriptCore/runtime/StringConstructor.h
index a2c08231e..15083bfc0 100644
--- a/Source/JavaScriptCore/runtime/StringConstructor.h
+++ b/Source/JavaScriptCore/runtime/StringConstructor.h
@@ -25,39 +25,39 @@
namespace JSC {
- class StringPrototype;
+class StringPrototype;
+class GetterSetter;
- class StringConstructor : public InternalFunction {
- public:
- typedef InternalFunction Base;
+class StringConstructor : public InternalFunction {
+public:
+ typedef InternalFunction Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
- static StringConstructor* create(VM& vm, Structure* structure, StringPrototype* stringPrototype)
- {
- StringConstructor* constructor = new (NotNull, allocateCell<StringConstructor>(vm.heap)) StringConstructor(vm, structure);
- constructor->finishCreation(vm, stringPrototype);
- return constructor;
- }
+ static StringConstructor* create(VM& vm, Structure* structure, StringPrototype* stringPrototype, GetterSetter*)
+ {
+ StringConstructor* constructor = new (NotNull, allocateCell<StringConstructor>(vm.heap)) StringConstructor(vm, structure);
+ constructor->finishCreation(vm, stringPrototype);
+ return constructor;
+ }
- DECLARE_INFO;
+ DECLARE_INFO;
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
- protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
+private:
+ StringConstructor(VM&, Structure*);
+ void finishCreation(VM&, StringPrototype*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
- private:
- StringConstructor(VM&, Structure*);
- void finishCreation(VM&, StringPrototype*);
- static ConstructType getConstructData(JSCell*, ConstructData&);
- static CallType getCallData(JSCell*, CallData&);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+};
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- };
-
- JSCell* JSC_HOST_CALL stringFromCharCode(ExecState*, int32_t);
+JSCell* JSC_HOST_CALL stringFromCharCode(ExecState*, int32_t);
+JSCell* stringConstructor(ExecState*, JSValue);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StringIteratorPrototype.cpp b/Source/JavaScriptCore/runtime/StringIteratorPrototype.cpp
new file mode 100644
index 000000000..bd5b68cec
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StringIteratorPrototype.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2013 Apple, Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 "StringIteratorPrototype.h"
+
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSGlobalObject.h"
+#include "JSStringIterator.h"
+#include "ObjectConstructor.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+}
+
+#include "StringIteratorPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo StringIteratorPrototype::s_info = { "String Iterator", &Base::s_info, &stringIteratorPrototypeTable, CREATE_METHOD_TABLE(StringIteratorPrototype) };
+
+/* Source for StringIteratorPrototype.lut.h
+@begin stringIteratorPrototypeTable
+ next JSBuiltin DontEnum|Function 0
+@end
+*/
+
+void StringIteratorPrototype::finishCreation(VM& vm, JSGlobalObject*)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "String Iterator"), DontEnum | ReadOnly);
+ vm.prototypeMap.addPrototype(this);
+}
+
+bool StringIteratorPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<Base>(exec, stringIteratorPrototypeTable, jsCast<StringIteratorPrototype*>(object), propertyName, slot);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StringIteratorPrototype.h b/Source/JavaScriptCore/runtime/StringIteratorPrototype.h
new file mode 100644
index 000000000..393af560f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StringIteratorPrototype.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2013 Apple, Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 StringIteratorPrototype_h
+#define StringIteratorPrototype_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class StringIteratorPrototype : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+
+ static StringIteratorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+ {
+ StringIteratorPrototype* prototype = new (NotNull, allocateCell<StringIteratorPrototype>(vm.heap)) StringIteratorPrototype(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:
+ StringIteratorPrototype(VM& vm, Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+ void finishCreation(VM&, JSGlobalObject*);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+};
+
+}
+
+#endif // !defined(StringIteratorPrototype_h)
diff --git a/Source/JavaScriptCore/runtime/StringObject.cpp b/Source/JavaScriptCore/runtime/StringObject.cpp
index 440a60942..b5aa3f72d 100644
--- a/Source/JavaScriptCore/runtime/StringObject.cpp
+++ b/Source/JavaScriptCore/runtime/StringObject.cpp
@@ -23,14 +23,14 @@
#include "Error.h"
#include "JSGlobalObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "PropertyNameArray.h"
namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(StringObject);
-const ClassInfo StringObject::s_info = { "String", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(StringObject) };
+const ClassInfo StringObject::s_info = { "String", &JSWrapperObject::s_info, 0, CREATE_METHOD_TABLE(StringObject) };
StringObject::StringObject(VM& vm, Structure* structure)
: JSWrapperObject(vm, structure)
@@ -93,7 +93,7 @@ bool StringObject::defineOwnProperty(JSObject* object, ExecState* exec, Property
}
if (descriptor.configurablePresent() && descriptor.configurable()) {
if (throwException)
- exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to configurable attribute of unconfigurable property.")));
+ exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change configurable attribute of unconfigurable property.")));
return false;
}
if (descriptor.enumerablePresent() && descriptor.enumerable()) {
@@ -128,9 +128,8 @@ bool StringObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName pr
StringObject* thisObject = jsCast<StringObject*>(cell);
if (propertyName == exec->propertyNames().length)
return false;
- unsigned i = propertyName.asIndex();
- if (thisObject->internalValue()->canGetIndex(i)) {
- ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail!
+ Optional<uint32_t> index = parseIndex(propertyName);
+ if (index && thisObject->internalValue()->canGetIndex(index.value())) {
return false;
}
return JSObject::deleteProperty(thisObject, exec, propertyName);
@@ -147,10 +146,12 @@ bool StringObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned
void StringObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
StringObject* thisObject = jsCast<StringObject*>(object);
- int size = thisObject->internalValue()->length();
- for (int i = 0; i < size; ++i)
- propertyNames.add(Identifier::from(exec, i));
- if (mode == IncludeDontEnumProperties)
+ if (propertyNames.includeStringProperties()) {
+ int size = thisObject->internalValue()->length();
+ for (int i = 0; i < size; ++i)
+ propertyNames.add(Identifier::from(exec, i));
+ }
+ if (mode.includeDontEnumProperties())
propertyNames.add(exec->propertyNames().length);
return JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
}
diff --git a/Source/JavaScriptCore/runtime/StringObject.h b/Source/JavaScriptCore/runtime/StringObject.h
index df6361474..90e6e5cca 100644
--- a/Source/JavaScriptCore/runtime/StringObject.h
+++ b/Source/JavaScriptCore/runtime/StringObject.h
@@ -26,60 +26,60 @@
namespace JSC {
- class StringObject : public JSWrapperObject {
- public:
- typedef JSWrapperObject Base;
-
- static StringObject* create(VM& vm, Structure* structure)
- {
- JSString* string = jsEmptyString(&vm);
- StringObject* object = new (NotNull, allocateCell<StringObject>(vm.heap)) StringObject(vm, structure);
- object->finishCreation(vm, string);
- return object;
- }
- static StringObject* create(VM& vm, Structure* structure, JSString* string)
- {
- StringObject* object = new (NotNull, allocateCell<StringObject>(vm.heap)) StringObject(vm, structure);
- object->finishCreation(vm, string);
- return object;
- }
- static StringObject* create(VM&, JSGlobalObject*, JSString*);
-
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
- static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
-
- 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 void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
- static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
-
- DECLARE_EXPORT_INFO;
-
- JSString* internalValue() const { return asString(JSWrapperObject::internalValue());}
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
-
- protected:
- JS_EXPORT_PRIVATE void finishCreation(VM&, JSString*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | JSWrapperObject::StructureFlags;
- JS_EXPORT_PRIVATE StringObject(VM&, Structure*);
- };
-
- StringObject* asStringObject(JSValue);
-
- inline StringObject* asStringObject(JSValue value)
+class StringObject : public JSWrapperObject {
+public:
+ typedef JSWrapperObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames;
+
+ static StringObject* create(VM& vm, Structure* structure)
+ {
+ JSString* string = jsEmptyString(&vm);
+ StringObject* object = new (NotNull, allocateCell<StringObject>(vm.heap)) StringObject(vm, structure);
+ object->finishCreation(vm, string);
+ return object;
+ }
+ static StringObject* create(VM& vm, Structure* structure, JSString* string)
+ {
+ StringObject* object = new (NotNull, allocateCell<StringObject>(vm.heap)) StringObject(vm, structure);
+ object->finishCreation(vm, string);
+ return object;
+ }
+ static StringObject* create(VM&, JSGlobalObject*, JSString*);
+
+ JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
+
+ JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+ JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
+
+ JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName);
+ JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
+ JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
+
+ DECLARE_EXPORT_INFO;
+
+ JSString* internalValue() const { return asString(JSWrapperObject::internalValue());}
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- ASSERT(asObject(value)->inherits(StringObject::info()));
- return static_cast<StringObject*>(asObject(value));
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}
- JS_EXPORT_PRIVATE StringObject* constructString(VM&, JSGlobalObject*, JSValue);
+protected:
+ JS_EXPORT_PRIVATE void finishCreation(VM&, JSString*);
+ JS_EXPORT_PRIVATE StringObject(VM&, Structure*);
+};
+
+StringObject* asStringObject(JSValue);
+
+inline StringObject* asStringObject(JSValue value)
+{
+ ASSERT(asObject(value)->inherits(StringObject::info()));
+ return static_cast<StringObject*>(asObject(value));
+}
+
+JS_EXPORT_PRIVATE StringObject* constructString(VM&, JSGlobalObject*, JSValue);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp
index 83306a0eb..7e379fb8c 100644
--- a/Source/JavaScriptCore/runtime/StringPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp
@@ -1,7 +1,8 @@
/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2009 Torch Mobile, Inc.
+ * Copyright (C) 2015 Jordan Harband (ljharb@gmail.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -27,20 +28,28 @@
#include "CopiedSpaceInlines.h"
#include "Error.h"
#include "Executable.h"
+#include "IntlObject.h"
+#include "JSCBuiltins.h"
+#include "JSCInlines.h"
#include "JSGlobalObjectFunctions.h"
#include "JSArray.h"
#include "JSFunction.h"
#include "JSStringBuilder.h"
+#include "JSStringIterator.h"
#include "Lookup.h"
#include "ObjectPrototype.h"
-#include "Operations.h"
#include "PropertyNameArray.h"
#include "RegExpCache.h"
#include "RegExpConstructor.h"
#include "RegExpMatchesArray.h"
#include "RegExpObject.h"
+#include <algorithm>
+#include <unicode/uconfig.h>
+#include <unicode/unorm.h>
+#include <unicode/ustring.h>
#include <wtf/ASCIICType.h>
#include <wtf/MathExtras.h>
+#include <wtf/text/StringView.h>
#include <wtf/unicode/Collator.h>
using namespace WTF;
@@ -49,40 +58,61 @@ namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(StringPrototype);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*);
-static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*);
-
-const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, 0, CREATE_METHOD_TABLE(StringPrototype) };
+EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncCodePointAt(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncRepeat(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncToLocaleLowerCase(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncToLocaleUpperCase(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncStartsWith(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncEndsWith(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncIncludes(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncNormalize(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncIterator(ExecState*);
+
+}
+
+#include "StringPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, &stringPrototypeTable, CREATE_METHOD_TABLE(StringPrototype) };
+
+/* Source for StringConstructor.lut.h
+@begin stringPrototypeTable
+ search JSBuiltin DontEnum|Function 1
+@end
+*/
// ECMA 15.5.4
StringPrototype::StringPrototype(VM& vm, Structure* structure)
@@ -95,41 +125,55 @@ void StringPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject, JSStr
Base::finishCreation(vm, nameAndMessage);
ASSERT(inherits(info()));
- JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->toString, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic);
- JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->valueOf, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic);
- JSC_NATIVE_INTRINSIC_FUNCTION("charAt", stringProtoFuncCharAt, DontEnum, 1, CharAtIntrinsic);
- JSC_NATIVE_INTRINSIC_FUNCTION("charCodeAt", stringProtoFuncCharCodeAt, DontEnum, 1, CharCodeAtIntrinsic);
- JSC_NATIVE_FUNCTION("concat", stringProtoFuncConcat, DontEnum, 1);
- JSC_NATIVE_FUNCTION("indexOf", stringProtoFuncIndexOf, DontEnum, 1);
- JSC_NATIVE_FUNCTION("lastIndexOf", stringProtoFuncLastIndexOf, DontEnum, 1);
- JSC_NATIVE_FUNCTION("match", stringProtoFuncMatch, DontEnum, 1);
- JSC_NATIVE_FUNCTION("replace", stringProtoFuncReplace, DontEnum, 2);
- JSC_NATIVE_FUNCTION("search", stringProtoFuncSearch, DontEnum, 1);
- JSC_NATIVE_FUNCTION("slice", stringProtoFuncSlice, DontEnum, 2);
- JSC_NATIVE_FUNCTION("split", stringProtoFuncSplit, DontEnum, 2);
- JSC_NATIVE_FUNCTION("substr", stringProtoFuncSubstr, DontEnum, 2);
- JSC_NATIVE_FUNCTION("substring", stringProtoFuncSubstring, DontEnum, 2);
- JSC_NATIVE_FUNCTION("toLowerCase", stringProtoFuncToLowerCase, DontEnum, 0);
- JSC_NATIVE_FUNCTION("toUpperCase", stringProtoFuncToUpperCase, DontEnum, 0);
- JSC_NATIVE_FUNCTION("localeCompare", stringProtoFuncLocaleCompare, DontEnum, 1);
- JSC_NATIVE_FUNCTION("toLocaleLowerCase", stringProtoFuncToLowerCase, DontEnum, 0);
- JSC_NATIVE_FUNCTION("toLocaleUpperCase", stringProtoFuncToUpperCase, DontEnum, 0);
- JSC_NATIVE_FUNCTION("big", stringProtoFuncBig, DontEnum, 0);
- JSC_NATIVE_FUNCTION("small", stringProtoFuncSmall, DontEnum, 0);
- JSC_NATIVE_FUNCTION("blink", stringProtoFuncBlink, DontEnum, 0);
- JSC_NATIVE_FUNCTION("bold", stringProtoFuncBold, DontEnum, 0);
- JSC_NATIVE_FUNCTION("fixed", stringProtoFuncFixed, DontEnum, 0);
- JSC_NATIVE_FUNCTION("italics", stringProtoFuncItalics, DontEnum, 0);
- JSC_NATIVE_FUNCTION("strike", stringProtoFuncStrike, DontEnum, 0);
- JSC_NATIVE_FUNCTION("sub", stringProtoFuncSub, DontEnum, 0);
- JSC_NATIVE_FUNCTION("sup", stringProtoFuncSup, DontEnum, 0);
- JSC_NATIVE_FUNCTION("fontcolor", stringProtoFuncFontcolor, DontEnum, 1);
- JSC_NATIVE_FUNCTION("fontsize", stringProtoFuncFontsize, DontEnum, 1);
- JSC_NATIVE_FUNCTION("anchor", stringProtoFuncAnchor, DontEnum, 1);
- JSC_NATIVE_FUNCTION("link", stringProtoFuncLink, DontEnum, 1);
- JSC_NATIVE_FUNCTION("trim", stringProtoFuncTrim, DontEnum, 0);
- JSC_NATIVE_FUNCTION("trimLeft", stringProtoFuncTrimLeft, DontEnum, 0);
- JSC_NATIVE_FUNCTION("trimRight", stringProtoFuncTrimRight, DontEnum, 0);
+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toString, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic);
+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->valueOf, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic);
+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("charAt", stringProtoFuncCharAt, DontEnum, 1, CharAtIntrinsic);
+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("charCodeAt", stringProtoFuncCharCodeAt, DontEnum, 1, CharCodeAtIntrinsic);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("codePointAt", stringProtoFuncCodePointAt, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("concat", stringProtoFuncConcat, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("indexOf", stringProtoFuncIndexOf, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("lastIndexOf", stringProtoFuncLastIndexOf, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("match", stringProtoFuncMatch, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("repeat", stringProtoFuncRepeat, DontEnum, 1);
+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION("replace", stringProtoFuncReplace, DontEnum, 2, StringPrototypeReplaceIntrinsic);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("slice", stringProtoFuncSlice, DontEnum, 2);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("split", stringProtoFuncSplit, DontEnum, 2);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("substr", stringProtoFuncSubstr, DontEnum, 2);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("substring", stringProtoFuncSubstring, DontEnum, 2);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("toLowerCase", stringProtoFuncToLowerCase, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("toUpperCase", stringProtoFuncToUpperCase, DontEnum, 0);
+#if ENABLE(INTL)
+ JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("localeCompare", stringPrototypeLocaleCompareCodeGenerator, DontEnum);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("toLocaleLowerCase", stringProtoFuncToLocaleLowerCase, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("toLocaleUpperCase", stringProtoFuncToLocaleUpperCase, DontEnum, 0);
+#else
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("localeCompare", stringProtoFuncLocaleCompare, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("toLocaleLowerCase", stringProtoFuncToLowerCase, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("toLocaleUpperCase", stringProtoFuncToUpperCase, DontEnum, 0);
+#endif
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("big", stringProtoFuncBig, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("small", stringProtoFuncSmall, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("blink", stringProtoFuncBlink, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("bold", stringProtoFuncBold, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("fixed", stringProtoFuncFixed, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("italics", stringProtoFuncItalics, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("strike", stringProtoFuncStrike, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("sub", stringProtoFuncSub, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("sup", stringProtoFuncSup, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("fontcolor", stringProtoFuncFontcolor, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("fontsize", stringProtoFuncFontsize, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("anchor", stringProtoFuncAnchor, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("link", stringProtoFuncLink, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("trim", stringProtoFuncTrim, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("trimLeft", stringProtoFuncTrimLeft, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("trimRight", stringProtoFuncTrimRight, DontEnum, 0);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("startsWith", stringProtoFuncStartsWith, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("endsWith", stringProtoFuncEndsWith, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("includes", stringProtoFuncIncludes, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("normalize", stringProtoFuncNormalize, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->iteratorSymbol, stringProtoFuncIterator, DontEnum, 0);
+
+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->charCodeAtPrivateName, stringProtoFuncCharCodeAt, DontEnum, 1, CharCodeAtIntrinsic);
// The constructor will be added later, after StringConstructor has been built
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
@@ -143,6 +187,11 @@ StringPrototype* StringPrototype::create(VM& vm, JSGlobalObject* globalObject, S
return prototype;
}
+bool StringPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<Base>(exec, stringPrototypeTable, jsCast<StringPrototype*>(object), propertyName, slot);
+}
+
// ------------------------------ Functions --------------------------
// Helper for producing a JSString for 'string', where 'string' was been produced by
@@ -157,10 +206,19 @@ static inline JSString* jsStringWithReuse(ExecState* exec, JSValue originalValue
return jsString(exec, string);
}
-template <typename CharType>
-static NEVER_INLINE String substituteBackreferencesSlow(const String& replacement, const String& source, const int* ovector, RegExp* reg, size_t i)
+// Helper that tries to use the JSString substring sharing mechanism if 'originalValue' is a JSString.
+static inline JSString* jsSubstring(ExecState* exec, JSValue originalValue, const String& string, unsigned offset, unsigned length)
{
- Vector<CharType> substitutedReplacement;
+ if (originalValue.isString()) {
+ ASSERT(asString(originalValue)->value(exec) == string);
+ return jsSubstring(exec, asString(originalValue), offset, length);
+ }
+ return jsSubstring(exec, string, offset, length);
+}
+
+static NEVER_INLINE String substituteBackreferencesSlow(StringView replacement, StringView source, const int* ovector, RegExp* reg, size_t i)
+{
+ StringBuilder substitutedReplacement;
int offset = 0;
do {
if (i + 1 == replacement.length())
@@ -170,7 +228,7 @@ static NEVER_INLINE String substituteBackreferencesSlow(const String& replacemen
if (ref == '$') {
// "$$" -> "$"
++i;
- substitutedReplacement.append(replacement.getCharactersWithUpconvert<CharType>() + offset, i - offset);
+ substitutedReplacement.append(replacement.substring(offset, i - offset));
offset = i + 1;
continue;
}
@@ -210,38 +268,29 @@ static NEVER_INLINE String substituteBackreferencesSlow(const String& replacemen
continue;
if (i - offset)
- substitutedReplacement.append(replacement.getCharactersWithUpconvert<CharType>() + offset, i - offset);
+ substitutedReplacement.append(replacement.substring(offset, i - offset));
i += 1 + advance;
offset = i + 1;
if (backrefStart >= 0)
- substitutedReplacement.append(source.getCharactersWithUpconvert<CharType>() + backrefStart, backrefLength);
+ substitutedReplacement.append(source.substring(backrefStart, backrefLength));
} while ((i = replacement.find('$', i + 1)) != notFound);
if (replacement.length() - offset)
- substitutedReplacement.append(replacement.getCharactersWithUpconvert<CharType>() + offset, replacement.length() - offset);
+ substitutedReplacement.append(replacement.substring(offset));
- substitutedReplacement.shrinkToFit();
- return String::adopt(substitutedReplacement);
+ return substitutedReplacement.toString();
}
-static inline String substituteBackreferences(const String& replacement, const String& source, const int* ovector, RegExp* reg)
+static inline String substituteBackreferences(const String& replacement, StringView source, const int* ovector, RegExp* reg)
{
size_t i = replacement.find('$');
- if (UNLIKELY(i != notFound)) {
- if (replacement.is8Bit() && source.is8Bit())
- return substituteBackreferencesSlow<LChar>(replacement, source, ovector, reg, i);
- return substituteBackreferencesSlow<UChar>(replacement, source, ovector, reg, i);
- }
- return replacement;
-}
+ if (UNLIKELY(i != notFound))
+ return substituteBackreferencesSlow(replacement, source, ovector, reg, i);
-static inline int localeCompare(const String& a, const String& b)
-{
- return Collator::userDefault()->collate(reinterpret_cast<const ::UChar*>(a.deprecatedCharacters()), a.length(), reinterpret_cast<const ::UChar*>(b.deprecatedCharacters()), b.length());
+ return replacement;
}
struct StringRange {
-public:
StringRange(int pos, int len)
: position(pos)
, length(len)
@@ -265,7 +314,7 @@ static ALWAYS_INLINE JSValue jsSpliceSubstrings(ExecState* exec, JSString* sourc
if (position <= 0 && length >= sourceSize)
return sourceVal;
// We could call String::substringSharingImpl(), but this would result in redundant checks.
- return jsString(exec, StringImpl::create(source.impl(), std::max(0, position), std::min(sourceSize, length)));
+ return jsString(exec, StringImpl::createSubstringSharingImpl(source.impl(), std::max(0, position), std::min(sourceSize, length)));
}
int totalLength = 0;
@@ -320,7 +369,7 @@ static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, J
if (position <= 0 && length >= sourceSize)
return sourceVal;
// We could call String::substringSharingImpl(), but this would result in redundant checks.
- return jsString(exec, StringImpl::create(source.impl(), std::max(0, position), std::min(sourceSize, length)));
+ return jsString(exec, StringImpl::createSubstringSharingImpl(source.impl(), std::max(0, position), std::min(sourceSize, length)));
}
Checked<int, RecordOverflow> totalLength = 0;
@@ -397,7 +446,7 @@ static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, J
return jsString(exec, impl.release());
}
-static NEVER_INLINE EncodedJSValue removeUsingRegExpSearch(ExecState* exec, JSString* string, const String& source, RegExp* regExp)
+static ALWAYS_INLINE EncodedJSValue removeUsingRegExpSearch(ExecState* exec, JSString* string, const String& source, RegExp* regExp)
{
size_t lastIndex = 0;
unsigned startPosition = 0;
@@ -435,19 +484,14 @@ static NEVER_INLINE EncodedJSValue removeUsingRegExpSearch(ExecState* exec, JSSt
return JSValue::encode(jsSpliceSubstrings(exec, string, source, sourceRanges.data(), sourceRanges.size()));
}
-static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSString* string, JSValue searchValue)
+static ALWAYS_INLINE EncodedJSValue replaceUsingRegExpSearch(
+ ExecState* exec, JSString* string, JSValue searchValue, CallData& callData, CallType callType,
+ String& replacementString, JSValue replaceValue)
{
- JSValue replaceValue = exec->argument(1);
- String replacementString;
- CallData callData;
- CallType callType = getCallData(replaceValue, callData);
- if (callType == CallTypeNone)
- replacementString = replaceValue.toString(exec)->value(exec);
-
const String& source = string->value(exec);
unsigned sourceLen = source.length();
if (exec->hadException())
- return JSValue::encode(JSValue());
+ return JSValue::encode(jsUndefined());
RegExpObject* regExpObject = asRegExpObject(searchValue);
RegExp* regExp = regExpObject->regExp();
bool global = regExp->global();
@@ -456,12 +500,14 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
// ES5.1 15.5.4.10 step 8.a.
regExpObject->setLastIndex(exec, 0);
if (exec->hadException())
- return JSValue::encode(JSValue());
+ return JSValue::encode(jsUndefined());
if (callType == CallTypeNone && !replacementString.length())
return removeUsingRegExpSearch(exec, string, source, regExp);
}
+ // FIXME: This is wrong because we may be called directly from the FTL.
+ // https://bugs.webkit.org/show_bug.cgi?id=154874
RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
size_t lastIndex = 0;
@@ -477,7 +523,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
JSFunction* func = jsCast<JSFunction*>(replaceValue);
CachedCall cachedCall(exec, func, argCount);
if (exec->hadException())
- return JSValue::encode(jsNull());
+ return JSValue::encode(jsUndefined());
VM* vm = &exec->vm();
if (source.is8Bit()) {
while (true) {
@@ -496,7 +542,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
if (matchStart < 0)
cachedCall.setArgument(i, jsUndefined());
else
- cachedCall.setArgument(i, jsSubstring8(vm, source, matchStart, matchLen));
+ cachedCall.setArgument(i, jsSubstring(vm, source, matchStart, matchLen));
}
cachedCall.setArgument(i++, jsNumber(result.start));
@@ -506,7 +552,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
JSValue jsResult = cachedCall.call();
replacements.append(jsResult.toString(exec)->value(exec));
if (exec->hadException())
- break;
+ return JSValue::encode(jsUndefined());
lastIndex = result.end;
startPosition = lastIndex;
@@ -545,7 +591,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
JSValue jsResult = cachedCall.call();
replacements.append(jsResult.toString(exec)->value(exec));
if (exec->hadException())
- break;
+ return JSValue::encode(jsUndefined());
lastIndex = result.end;
startPosition = lastIndex;
@@ -586,7 +632,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
replacements.append(call(exec, replaceValue, callType, callData, jsUndefined(), args).toString(exec)->value(exec));
if (exec->hadException())
- break;
+ return JSValue::encode(jsUndefined());
} else {
int replLen = replacementString.length();
if (lastIndex < result.start || replLen) {
@@ -620,7 +666,49 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
return JSValue::encode(jsSpliceSubstringsWithSeparators(exec, string, source, sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size()));
}
-static inline EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* jsString, JSValue searchValue)
+EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceRegExpEmptyStr(
+ ExecState* exec, JSString* thisValue, RegExpObject* searchValue)
+{
+ RegExp* regExp = searchValue->regExp();
+ if (regExp->global()) {
+ // ES5.1 15.5.4.10 step 8.a.
+ searchValue->setLastIndex(exec, 0);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ return removeUsingRegExpSearch(exec, thisValue, thisValue->value(exec), regExp);
+ }
+
+ CallData callData;
+ String replacementString = emptyString();
+ return replaceUsingRegExpSearch(
+ exec, thisValue, searchValue, callData, CallTypeNone, replacementString, JSValue());
+}
+
+EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceRegExpString(
+ ExecState* exec, JSString* thisValue, RegExpObject* searchValue, JSString* replaceString)
+{
+ CallData callData;
+ String replacementString = replaceString->value(exec);
+ return replaceUsingRegExpSearch(
+ exec, thisValue, searchValue, callData, CallTypeNone, replacementString, replaceString);
+}
+
+static ALWAYS_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSString* string, JSValue searchValue, JSValue replaceValue)
+{
+ String replacementString;
+ CallData callData;
+ CallType callType = getCallData(replaceValue, callData);
+ if (callType == CallTypeNone) {
+ replacementString = replaceValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ }
+
+ return replaceUsingRegExpSearch(
+ exec, string, searchValue, callData, callType, replacementString, replaceValue);
+}
+
+static ALWAYS_INLINE EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* jsString, JSValue searchValue, JSValue replaceValue)
{
const String& string = jsString->value(exec);
String searchString = searchValue.toString(exec)->value(exec);
@@ -632,7 +720,6 @@ static inline EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString*
if (matchStart == notFound)
return JSValue::encode(jsString);
- JSValue replaceValue = exec->argument(1);
CallData callData;
CallType callType = getCallData(replaceValue, callData);
if (callType != CallTypeNone) {
@@ -650,14 +737,14 @@ static inline EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString*
return JSValue::encode(jsUndefined());
StringImpl* stringImpl = string.impl();
- String leftPart(StringImpl::create(stringImpl, 0, matchStart));
+ String leftPart(StringImpl::createSubstringSharingImpl(stringImpl, 0, matchStart));
size_t matchEnd = matchStart + searchString.impl()->length();
int ovector[2] = { static_cast<int>(matchStart), static_cast<int>(matchEnd)};
String middlePart = substituteBackreferences(replaceString, string, ovector, 0);
size_t leftLength = stringImpl->length() - matchEnd;
- String rightPart(StringImpl::create(stringImpl, matchEnd, leftLength));
+ String rightPart(StringImpl::createSubstringSharingImpl(stringImpl, matchEnd, leftLength));
return JSValue::encode(JSC::jsString(exec, leftPart, middlePart, rightPart));
}
@@ -675,22 +762,102 @@ static inline bool checkObjectCoercible(JSValue thisValue)
return true;
}
-EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
+template <typename CharacterType>
+static inline JSValue repeatCharacter(ExecState* exec, CharacterType character, unsigned repeatCount)
{
- JSValue thisValue = exec->hostThisValue();
+ CharacterType* buffer = nullptr;
+ RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(repeatCount, buffer);
+ if (!impl)
+ return throwOutOfMemoryError(exec);
+
+ std::fill_n(buffer, repeatCount, character);
+
+ return jsString(exec, impl.release());
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncRepeat(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
+
JSString* string = thisValue.toString(exec);
- JSValue searchValue = exec->argument(0);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ double repeatCountDouble = exec->argument(0).toInteger(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (repeatCountDouble < 0 || std::isinf(repeatCountDouble))
+ return throwVMError(exec, createRangeError(exec, ASCIILiteral("repeat() argument must be greater than or equal to 0 and not be infinity")));
+ VM& vm = exec->vm();
+
+ if (!string->length() || !repeatCountDouble)
+ return JSValue::encode(jsEmptyString(&vm));
+
+ if (repeatCountDouble == 1)
+ return JSValue::encode(string);
+
+ // JSString requires the limitation that its length is in the range of int32_t.
+ if (repeatCountDouble > std::numeric_limits<int32_t>::max() / string->length())
+ return JSValue::encode(throwOutOfMemoryError(exec));
+ unsigned repeatCount = static_cast<unsigned>(repeatCountDouble);
+
+ // For a string which length is small, instead of creating ropes,
+ // allocating a sequential buffer and fill with the repeated string for efficiency.
+ if (string->length() == 1) {
+ String repeatedString = string->value(exec);
+ UChar character = repeatedString.at(0);
+ if (!(character & ~0xff))
+ return JSValue::encode(repeatCharacter(exec, static_cast<LChar>(character), repeatCount));
+ return JSValue::encode(repeatCharacter(exec, character, repeatCount));
+ }
+
+ JSRopeString::RopeBuilder ropeBuilder(vm);
+ for (unsigned i = 0; i < repeatCount; ++i) {
+ if (!ropeBuilder.append(string))
+ return JSValue::encode(throwOutOfMemoryError(exec));
+ }
+ return JSValue::encode(ropeBuilder.release());
+}
+
+ALWAYS_INLINE EncodedJSValue replace(
+ ExecState* exec, JSString* string, JSValue searchValue, JSValue replaceValue)
+{
if (searchValue.inherits(RegExpObject::info()))
- return replaceUsingRegExpSearch(exec, string, searchValue);
- return replaceUsingStringSearch(exec, string, searchValue);
+ return replaceUsingRegExpSearch(exec, string, searchValue, replaceValue);
+ return replaceUsingStringSearch(exec, string, searchValue, replaceValue);
+}
+
+ALWAYS_INLINE EncodedJSValue replace(
+ ExecState* exec, JSValue thisValue, JSValue searchValue, JSValue replaceValue)
+{
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(exec);
+ JSString* string = thisValue.toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ return replace(exec, string, searchValue, replaceValue);
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
+{
+ return replace(exec, exec->thisValue(), exec->argument(0), exec->argument(1));
+}
+
+EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceGeneric(
+ ExecState* exec, EncodedJSValue thisValue, EncodedJSValue searchValue,
+ EncodedJSValue replaceValue)
+{
+ return replace(
+ exec, JSValue::decode(thisValue), JSValue::decode(searchValue),
+ JSValue::decode(replaceValue));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
// Also used for valueOf.
if (thisValue.isString())
@@ -704,50 +871,81 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec)
EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
- String s = thisValue.toString(exec)->value(exec);
- unsigned len = s.length();
+ JSString::SafeView string = thisValue.toString(exec)->view(exec);
JSValue a0 = exec->argument(0);
if (a0.isUInt32()) {
uint32_t i = a0.asUInt32();
- if (i < len)
- return JSValue::encode(jsSingleCharacterSubstring(exec, s, i));
+ if (i < string.length())
+ return JSValue::encode(jsSingleCharacterString(exec, string[i]));
return JSValue::encode(jsEmptyString(exec));
}
double dpos = a0.toInteger(exec);
- if (dpos >= 0 && dpos < len)
- return JSValue::encode(jsSingleCharacterSubstring(exec, s, static_cast<unsigned>(dpos)));
+ if (dpos >= 0 && dpos < string.length())
+ return JSValue::encode(jsSingleCharacterString(exec, string[static_cast<unsigned>(dpos)]));
return JSValue::encode(jsEmptyString(exec));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
- String s = thisValue.toString(exec)->value(exec);
- unsigned len = s.length();
+ JSString::SafeView string = thisValue.toString(exec)->view(exec);
JSValue a0 = exec->argument(0);
if (a0.isUInt32()) {
uint32_t i = a0.asUInt32();
- if (i < len) {
- if (s.is8Bit())
- return JSValue::encode(jsNumber(s.characters8()[i]));
- return JSValue::encode(jsNumber(s.characters16()[i]));
- }
+ if (i < string.length())
+ return JSValue::encode(jsNumber(string[i]));
return JSValue::encode(jsNaN());
}
double dpos = a0.toInteger(exec);
- if (dpos >= 0 && dpos < len)
- return JSValue::encode(jsNumber(s[static_cast<int>(dpos)]));
+ if (dpos >= 0 && dpos < string.length())
+ return JSValue::encode(jsNumber(string[static_cast<int>(dpos)]));
return JSValue::encode(jsNaN());
}
+static inline UChar32 codePointAt(const String& string, unsigned position, unsigned length)
+{
+ RELEASE_ASSERT(position < length);
+ if (string.is8Bit())
+ return string.characters8()[position];
+ UChar32 character;
+ U16_NEXT(string.characters16(), position, length, character);
+ return character;
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncCodePointAt(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(exec);
+
+ String string = thisValue.toWTFString(exec);
+ unsigned length = string.length();
+
+ JSValue argument0 = exec->argument(0);
+ if (argument0.isUInt32()) {
+ unsigned position = argument0.asUInt32();
+ if (position < length)
+ return JSValue::encode(jsNumber(codePointAt(string, position, length)));
+ return JSValue::encode(jsUndefined());
+ }
+
+ if (UNLIKELY(exec->hadException()))
+ return JSValue::encode(jsUndefined());
+
+ double doublePosition = argument0.toInteger(exec);
+ if (doublePosition >= 0 && doublePosition < length)
+ return JSValue::encode(jsNumber(codePointAt(string, static_cast<unsigned>(doublePosition), length)));
+ return JSValue::encode(jsUndefined());
+}
+
EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (thisValue.isString() && exec->argumentCount() == 1)
return JSValue::encode(jsString(exec, asString(thisValue), exec->uncheckedArgument(0).toString(exec)));
@@ -758,21 +956,19 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec)
EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
- String s = thisValue.toString(exec)->value(exec);
JSValue a0 = exec->argument(0);
JSValue a1 = exec->argument(1);
- String u2 = a0.toString(exec)->value(exec);
- size_t result;
- if (a1.isUndefined())
- result = s.find(u2);
- else {
- unsigned pos;
- int len = s.length();
+ JSString* thisJSString = thisValue.toString(exec);
+ JSString* otherJSString = a0.toString(exec);
+
+ unsigned pos = 0;
+ if (!a1.isUndefined()) {
+ int len = thisJSString->length();
RELEASE_ASSERT(len >= 0);
if (a1.isUInt32())
pos = std::min<uint32_t>(a1.asUInt32(), len);
@@ -784,9 +980,12 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec)
dpos = len;
pos = static_cast<unsigned>(dpos);
}
- result = s.find(u2, pos);
}
+ if (thisJSString->length() < otherJSString->length() + pos)
+ return JSValue::encode(jsNumber(-1));
+
+ size_t result = thisJSString->view(exec).get().find(otherJSString->view(exec).get(), pos);
if (result == notFound)
return JSValue::encode(jsNumber(-1));
return JSValue::encode(jsNumber(result));
@@ -794,28 +993,36 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec)
EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
- String s = thisValue.toString(exec)->value(exec);
- int len = s.length();
JSValue a0 = exec->argument(0);
JSValue a1 = exec->argument(1);
- String u2 = a0.toString(exec)->value(exec);
+ JSString* thisJSString = thisValue.toString(exec);
+ unsigned len = thisJSString->length();
+ JSString* otherJSString = a0.toString(exec);
+
double dpos = a1.toIntegerPreserveNaN(exec);
+ unsigned startPosition;
if (dpos < 0)
- dpos = 0;
+ startPosition = 0;
else if (!(dpos <= len)) // true for NaN
- dpos = len;
+ startPosition = len;
+ else
+ startPosition = static_cast<unsigned>(dpos);
+
+ if (len < otherJSString->length())
+ return JSValue::encode(jsNumber(-1));
+ String thisString = thisJSString->value(exec);
+ String otherString = otherJSString->value(exec);
size_t result;
- unsigned startPosition = static_cast<unsigned>(dpos);
if (!startPosition)
- result = s.startsWith(u2) ? 0 : notFound;
+ result = thisString.startsWith(otherString) ? 0 : notFound;
else
- result = s.reverseFind(u2, startPosition);
+ result = thisString.reverseFind(otherString, startPosition);
if (result == notFound)
return JSValue::encode(jsNumber(-1));
return JSValue::encode(jsNumber(result));
@@ -823,7 +1030,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec)
EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
JSString* string = thisValue.toString(exec);
@@ -841,7 +1048,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
// ES5.1 15.5.4.10 step 8.a.
regExpObject->setLastIndex(exec, 0);
if (exec->hadException())
- return JSValue::encode(JSValue());
+ return JSValue::encode(jsUndefined());
}
} else {
/*
@@ -850,7 +1057,13 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
* replaced with the result of the expression new RegExp(regexp).
* Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string.
*/
- regExp = RegExp::create(exec->vm(), a0.isUndefined() ? emptyString() : a0.toString(exec)->value(exec), NoFlags);
+ String patternString = emptyString();
+ if (!a0.isUndefined()) {
+ patternString = a0.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ }
+ regExp = RegExp::create(exec->vm(), patternString, NoFlags);
if (!regExp->isValid())
return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage()));
}
@@ -858,11 +1071,18 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
MatchResult result = regExpConstructor->performMatch(*vm, regExp, string, s, 0);
// case without 'g' flag is handled like RegExp.prototype.exec
if (!global)
- return JSValue::encode(result ? RegExpMatchesArray::create(exec, string, regExp, result) : jsNull());
+ return JSValue::encode(result ? createRegExpMatchesArray(exec, string, regExp, result) : jsNull());
// return array of matches
MarkedArgumentBuffer list;
while (result) {
+ // We defend ourselves from crazy.
+ const size_t maximumReasonableMatchSize = 1000000000;
+ if (list.size() > maximumReasonableMatchSize) {
+ throwOutOfMemoryError(exec);
+ return JSValue::encode(jsUndefined());
+ }
+
size_t end = result.end;
size_t length = end - result.start;
list.append(jsSubstring(exec, s, result.start, length));
@@ -880,42 +1100,15 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
return JSValue::encode(constructArray(exec, static_cast<ArrayAllocationProfile*>(0), list));
}
-EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec)
-{
- JSValue thisValue = exec->hostThisValue();
- if (!checkObjectCoercible(thisValue))
- return throwVMTypeError(exec);
- JSString* string = thisValue.toString(exec);
- String s = string->value(exec);
- VM* vm = &exec->vm();
-
- JSValue a0 = exec->argument(0);
-
- RegExp* reg;
- if (a0.inherits(RegExpObject::info()))
- reg = asRegExpObject(a0)->regExp();
- else {
- /*
- * ECMA 15.5.4.12 String.prototype.search (regexp)
- * If regexp is not an object whose [[Class]] property is "RegExp", it is
- * replaced with the result of the expression new RegExp(regexp).
- * Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string.
- */
- reg = RegExp::create(exec->vm(), a0.isUndefined() ? emptyString() : a0.toString(exec)->value(exec), NoFlags);
- if (!reg->isValid())
- return throwVMError(exec, createSyntaxError(exec, reg->errorMessage()));
- }
- RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
- MatchResult result = regExpConstructor->performMatch(*vm, reg, string, s, 0);
- return JSValue::encode(result ? jsNumber(result.start) : jsNumber(-1));
-}
-
EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
int len = s.length();
RELEASE_ASSERT(len >= 0);
@@ -940,11 +1133,11 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec)
// Return true in case of early return (resultLength got to limitLength).
template<typename CharacterType>
-static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray* result, const String& input, StringImpl* string, UChar separatorCharacter, size_t& position, unsigned& resultLength, unsigned limitLength)
+static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray* result, JSValue originalValue, const String& input, StringImpl* string, UChar separatorCharacter, size_t& position, unsigned& resultLength, unsigned limitLength)
{
// 12. Let q = p.
size_t matchPosition;
- const CharacterType* characters = string->getCharacters<CharacterType>();
+ const CharacterType* characters = string->characters<CharacterType>();
// 13. Repeat, while q != s
// a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
// b. If z is failure, then let q = q+1.
@@ -954,7 +1147,7 @@ static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray
// through q (exclusive).
// 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
// Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
- result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position));
+ result->putDirectIndex(exec, resultLength, jsSubstring(exec, originalValue, input, position, matchPosition - position));
// 3. Increment lengthA by 1.
// 4. If lengthA == lim, return A.
if (++resultLength == limitLength)
@@ -971,13 +1164,16 @@ static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray
EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
{
// 1. Call CheckObjectCoercible passing the this value as its argument.
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
// 2. Let S be the result of calling ToString, giving it the this value as its argument.
// 6. Let s be the number of characters in S.
String input = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ ASSERT(!input.isNull());
// 3. Let A be a new array created as if by the expression new Array()
// where Array is the standard built-in constructor with that name.
@@ -1032,11 +1228,16 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
// a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
Vector<int, 32> ovector;
int mpos = reg->match(*vm, input, matchPosition, ovector);
- // b. If z is failure, then let q = q + 1.
+
+ // b. If z is a failure then we can break because there are no matches
if (mpos < 0)
break;
matchPosition = mpos;
+ // if the match is the empty match at the end, break.
+ if (matchPosition >= input.length())
+ break;
+
// c. Else, z is not failure
// i. z must be a State. Let e be z's endIndex and let cap be z's captures array.
size_t matchEnd = ovector[1];
@@ -1046,17 +1247,36 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
++matchPosition;
continue;
}
+ // iii. if matchEnd == 0 then position should also be zero and thus matchEnd should equal position.
+ ASSERT(matchEnd);
+
// iii. Else, e != p
// 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
// through q (exclusive).
// 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
// Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
- result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position));
+ result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
+
// 3. Increment lengthA by 1.
// 4. If lengthA == lim, return A.
- if (++resultLength == limit)
+ ++resultLength;
+ if (resultLength == limit)
return JSValue::encode(result);
+ if (resultLength >= MAX_STORAGE_VECTOR_INDEX) {
+ // Let's consider what's best for users here. We're about to increase the length of
+ // the split array beyond the maximum length that we can support efficiently. This
+ // will cause us to use a HashMap for the new entries after this point. That's going
+ // to result in a very long running time of this function and very large memory
+ // usage. In my experiments, JSC will sit spinning for minutes after getting here and
+ // it was using >4GB of memory and eventually grew to 8GB. It kept running without
+ // finishing until I killed it. That's probably not what the user wanted. The user,
+ // or the program that the user is running, probably made a mistake by calling this
+ // method in such a way that it resulted in such an obnoxious array. Therefore, to
+ // protect ourselves, we bail at this point.
+ throwOutOfMemoryError(exec);
+ return JSValue::encode(jsUndefined());
+ }
// 5. Let p = e.
// 8. Let q = p.
@@ -1071,7 +1291,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
// ToString(lengthA), Property Descriptor {[[Value]]: cap[i], [[Writable]]:
// true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
int sub = ovector[i * 2];
- result->putDirectIndex(exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, input, sub, ovector[i * 2 + 1] - sub));
+ result->putDirectIndex(exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, thisValue, input, sub, ovector[i * 2 + 1] - sub));
// c Increment lengthA by 1.
// d If lengthA == lim, return A.
if (++resultLength == limit)
@@ -1080,6 +1300,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
}
} else {
String separator = separatorValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
// 9. If lim == 0, return A.
if (!limit)
@@ -1114,7 +1336,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
ASSERT(limit);
do {
- result->putDirectIndex(exec, position, jsSingleCharacterSubstring(exec, input, position));
+ result->putDirectIndex(exec, position, jsSingleCharacterString(exec, input[position]));
} while (++position < limit);
return JSValue::encode(result);
@@ -1136,10 +1358,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
separatorCharacter = separatorImpl->characters16()[0];
if (stringImpl->is8Bit()) {
- if (splitStringByOneCharacterImpl<LChar>(exec, result, input, stringImpl, separatorCharacter, position, resultLength, limit))
+ if (splitStringByOneCharacterImpl<LChar>(exec, result, thisValue, input, stringImpl, separatorCharacter, position, resultLength, limit))
return JSValue::encode(result);
} else {
- if (splitStringByOneCharacterImpl<UChar>(exec, result, input, stringImpl, separatorCharacter, position, resultLength, limit))
+ if (splitStringByOneCharacterImpl<UChar>(exec, result, thisValue, input, stringImpl, separatorCharacter, position, resultLength, limit))
return JSValue::encode(result);
}
} else {
@@ -1154,7 +1376,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
// through q (exclusive).
// 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
// Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
- result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position));
+ result->putDirectIndex(exec, resultLength, jsSubstring(exec, thisValue, input, position, matchPosition - position));
// 3. Increment lengthA by 1.
// 4. If lengthA == lim, return A.
if (++resultLength == limit)
@@ -1171,7 +1393,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
// through s (exclusive).
// 15. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA), Property Descriptor
// {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
- result->putDirectIndex(exec, resultLength++, jsSubstring(exec, input, position, input.length() - position));
+ result->putDirectIndex(exec, resultLength++, jsSubstring(exec, thisValue, input, position, input.length() - position));
// 16. Return A.
return JSValue::encode(result);
@@ -1179,7 +1401,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
unsigned len;
@@ -1218,7 +1440,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec)
EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ SamplingRegion samplingRegion("Doing substringing");
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
@@ -1258,141 +1481,253 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec)
EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
JSString* sVal = thisValue.toString(exec);
const String& s = sVal->value(exec);
-
- int sSize = s.length();
- if (!sSize)
+ String lowercasedString = s.convertToLowercaseWithoutLocale();
+ if (lowercasedString.impl() == s.impl())
return JSValue::encode(sVal);
- RELEASE_ASSERT(sSize >= 0);
-
- StringImpl* ourImpl = s.impl();
- RefPtr<StringImpl> lower = ourImpl->lower();
- if (ourImpl == lower)
- return JSValue::encode(sVal);
- return JSValue::encode(jsString(exec, String(lower.release())));
+ return JSValue::encode(jsString(exec, lowercasedString));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
JSString* sVal = thisValue.toString(exec);
const String& s = sVal->value(exec);
-
- int sSize = s.length();
- if (!sSize)
+ String uppercasedString = s.convertToUppercaseWithoutLocale();
+ if (uppercasedString.impl() == s.impl())
return JSValue::encode(sVal);
-
- StringImpl* sImpl = s.impl();
- RefPtr<StringImpl> upper = sImpl->upper();
- if (sImpl == upper)
- return JSValue::encode(sVal);
- return JSValue::encode(jsString(exec, String(upper.release())));
+ return JSValue::encode(jsString(exec, uppercasedString));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
JSValue a0 = exec->argument(0);
- return JSValue::encode(jsNumber(localeCompare(s, a0.toString(exec)->value(exec))));
+ String str = a0.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(jsNumber(Collator().collate(s, str)));
}
+#if ENABLE(INTL)
+static EncodedJSValue toLocaleCase(ExecState* state, int32_t (*convertCase)(UChar*, int32_t, const UChar*, int32_t, const char*, UErrorCode*))
+{
+ // 1. Let O be RequireObjectCoercible(this value).
+ JSValue thisValue = state->thisValue();
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(state);
+
+ // 2. Let S be ToString(O).
+ JSString* sVal = thisValue.toString(state);
+ const String& s = sVal->value(state);
+
+ // 3. ReturnIfAbrupt(S).
+ if (state->hadException())
+ return JSValue::encode(jsUndefined());
+
+ // Optimization for empty strings.
+ if (s.isEmpty())
+ return JSValue::encode(sVal);
+
+ // 4. Let requestedLocales be CanonicalizeLocaleList(locales).
+ Vector<String> requestedLocales = canonicalizeLocaleList(*state, state->argument(0));
+
+ // 5. ReturnIfAbrupt(requestedLocales).
+ if (state->hadException())
+ return JSValue::encode(jsUndefined());
+
+ // 6. Let len be the number of elements in requestedLocales.
+ size_t len = requestedLocales.size();
+
+ // 7. If len > 0, then
+ // a. Let requestedLocale be the first element of requestedLocales.
+ // 8. Else
+ // a. Let requestedLocale be DefaultLocale().
+ String requestedLocale = len > 0 ? requestedLocales.first() : defaultLocale();
+
+ // 9. Let noExtensionsLocale be the String value that is requestedLocale with all Unicode locale extension sequences (6.2.1) removed.
+ String noExtensionsLocale = removeUnicodeLocaleExtension(requestedLocale);
+
+ // 10. Let availableLocales be a List with the language tags of the languages for which the Unicode character database contains language sensitive case mappings.
+ // Note 1: As of Unicode 5.1, the availableLocales list contains the elements "az", "lt", and "tr".
+ const HashSet<String> availableLocales({ ASCIILiteral("az"), ASCIILiteral("lt"), ASCIILiteral("tr") });
+
+ // 11. Let locale be BestAvailableLocale(availableLocales, noExtensionsLocale).
+ String locale = bestAvailableLocale(availableLocales, noExtensionsLocale);
+
+ // 12. If locale is undefined, let locale be "und".
+ if (locale.isNull())
+ locale = ASCIILiteral("und");
+
+ CString utf8LocaleBuffer = locale.utf8();
+ const StringView view(s);
+ const int32_t viewLength = view.length();
+
+ // Delegate the following steps to icu u_strToLower or u_strToUpper.
+ // 13. Let cpList be a List containing in order the code points of S as defined in ES2015, 6.1.4, starting at the first element of S.
+ // 14. For each code point c in cpList, if the Unicode Character Database provides a lower(/upper) case equivalent of c that is either language insensitive or for the language locale, then replace c in cpList with that/those equivalent code point(s).
+ // 15. Let cuList be a new List.
+ // 16. For each code point c in cpList, in order, append to cuList the elements of the UTF-16 Encoding (defined in ES2015, 6.1.4) of c.
+ // 17. Let L be a String whose elements are, in order, the elements of cuList.
+
+ // Most strings lower/upper case will be the same size as original, so try that first.
+ UErrorCode error(U_ZERO_ERROR);
+ Vector<UChar> buffer(viewLength);
+ String lower;
+ const int32_t resultLength = convertCase(buffer.data(), viewLength, view.upconvertedCharacters(), viewLength, utf8LocaleBuffer.data(), &error);
+ if (U_SUCCESS(error))
+ lower = String(buffer.data(), resultLength);
+ else if (error == U_BUFFER_OVERFLOW_ERROR) {
+ // Converted case needs more space than original. Try again.
+ UErrorCode error(U_ZERO_ERROR);
+ Vector<UChar> buffer(resultLength);
+ convertCase(buffer.data(), resultLength, view.upconvertedCharacters(), viewLength, utf8LocaleBuffer.data(), &error);
+ if (U_FAILURE(error))
+ return throwVMTypeError(state, u_errorName(error));
+ lower = String(buffer.data(), resultLength);
+ } else
+ return throwVMTypeError(state, u_errorName(error));
+
+ // 18. Return L.
+ return JSValue::encode(jsString(state, lower));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncToLocaleLowerCase(ExecState* state)
+{
+ // 13.1.2 String.prototype.toLocaleLowerCase ([locales])
+ // http://ecma-international.org/publications/standards/Ecma-402.htm
+ return toLocaleCase(state, u_strToLower);
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncToLocaleUpperCase(ExecState* state)
+{
+ // 13.1.3 String.prototype.toLocaleUpperCase ([locales])
+ // http://ecma-international.org/publications/standards/Ecma-402.htm
+ // This function interprets a string value as a sequence of code points, as described in ES2015, 6.1.4. This function behaves in exactly the same way as String.prototype.toLocaleLowerCase, except that characters are mapped to their uppercase equivalents as specified in the Unicode character database.
+ return toLocaleCase(state, u_strToUpper);
+}
+#endif // ENABLE(INTL)
+
EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
return JSValue::encode(jsMakeNontrivialString(exec, "<big>", s, "</big>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
return JSValue::encode(jsMakeNontrivialString(exec, "<small>", s, "</small>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
return JSValue::encode(jsMakeNontrivialString(exec, "<blink>", s, "</blink>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
return JSValue::encode(jsMakeNontrivialString(exec, "<b>", s, "</b>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
return JSValue::encode(jsMakeNontrivialString(exec, "<tt>", s, "</tt>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
return JSValue::encode(jsMakeNontrivialString(exec, "<i>", s, "</i>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
return JSValue::encode(jsMakeNontrivialString(exec, "<strike>", s, "</strike>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
return JSValue::encode(jsMakeNontrivialString(exec, "<sub>", s, "</sub>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
return JSValue::encode(jsMakeNontrivialString(exec, "<sup>", s, "</sup>"));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
JSValue a0 = exec->argument(0);
String color = a0.toWTFString(exec);
color.replaceWithLiteral('"', "&quot;");
@@ -1402,16 +1737,20 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec)
EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
JSValue a0 = exec->argument(0);
uint32_t smallInteger;
if (a0.getUInt32(smallInteger) && smallInteger <= 9) {
unsigned stringSize = s.length();
unsigned bufferSize = 22 + stringSize;
+ // FIXME: Should we have an 8-bit version of this code path too? Or maybe only an 8-bit version?
UChar* buffer;
PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(bufferSize, buffer);
if (!impl)
@@ -1431,7 +1770,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec)
buffer[12] = '0' + smallInteger;
buffer[13] = '"';
buffer[14] = '>';
- memcpy(&buffer[15], s.deprecatedCharacters(), stringSize * sizeof(UChar));
+ StringView(s).getCharactersWithUpconvert(&buffer[15]);
buffer[15 + stringSize] = '<';
buffer[16 + stringSize] = '/';
buffer[17 + stringSize] = 'f';
@@ -1450,10 +1789,13 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec)
EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
JSValue a0 = exec->argument(0);
String anchor = a0.toWTFString(exec);
anchor.replaceWithLiteral('"', "&quot;");
@@ -1463,10 +1805,13 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec)
EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
if (!checkObjectCoercible(thisValue))
return throwVMTypeError(exec);
String s = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
JSValue a0 = exec->argument(0);
String linkText = a0.toWTFString(exec);
linkText.replaceWithLiteral('"', "&quot;");
@@ -1474,6 +1819,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec)
unsigned linkTextSize = linkText.length();
unsigned stringSize = s.length();
unsigned bufferSize = 15 + linkTextSize + stringSize;
+ // FIXME: Should we have an 8-bit version of this code path too? Or maybe only an 8-bit version?
UChar* buffer;
PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(bufferSize, buffer);
if (!impl)
@@ -1487,10 +1833,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec)
buffer[6] = 'f';
buffer[7] = '=';
buffer[8] = '"';
- memcpy(&buffer[9], linkText.deprecatedCharacters(), linkTextSize * sizeof(UChar));
+ StringView(linkText).getCharactersWithUpconvert(&buffer[9]);
buffer[9 + linkTextSize] = '"';
buffer[10 + linkTextSize] = '>';
- memcpy(&buffer[11 + linkTextSize], s.deprecatedCharacters(), stringSize * sizeof(UChar));
+ StringView(s).getCharactersWithUpconvert(&buffer[11 + linkTextSize]);
buffer[11 + linkTextSize + stringSize] = '<';
buffer[12 + linkTextSize + stringSize] = '/';
buffer[13 + linkTextSize + stringSize] = 'a';
@@ -1503,24 +1849,22 @@ enum {
TrimRight = 2
};
-static inline bool isTrimWhitespace(UChar c)
-{
- return isStrWhiteSpace(c) || c == 0x200b;
-}
-
static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKind)
{
if (!checkObjectCoercible(thisValue))
return throwTypeError(exec);
String str = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return jsUndefined();
+
unsigned left = 0;
if (trimKind & TrimLeft) {
- while (left < str.length() && isTrimWhitespace(str[left]))
+ while (left < str.length() && isStrWhiteSpace(str[left]))
left++;
}
unsigned right = str.length();
if (trimKind & TrimRight) {
- while (right > left && isTrimWhitespace(str[right - 1]))
+ while (right > left && isStrWhiteSpace(str[right - 1]))
right--;
}
@@ -1533,21 +1877,190 @@ static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKin
EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
return JSValue::encode(trimString(exec, thisValue, TrimLeft | TrimRight));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
return JSValue::encode(trimString(exec, thisValue, TrimLeft));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState* exec)
{
- JSValue thisValue = exec->hostThisValue();
+ JSValue thisValue = exec->thisValue();
return JSValue::encode(trimString(exec, thisValue, TrimRight));
}
-
-
+
+static inline unsigned clampAndTruncateToUnsigned(double value, unsigned min, unsigned max)
+{
+ if (value < min)
+ return min;
+ if (value > max)
+ return max;
+ return static_cast<unsigned>(value);
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncStartsWith(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(exec);
+
+ String stringToSearchIn = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue a0 = exec->argument(0);
+ if (jsDynamicCast<RegExpObject*>(a0))
+ return throwVMTypeError(exec);
+
+ String searchString = a0.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue positionArg = exec->argument(1);
+ unsigned start = 0;
+ if (positionArg.isInt32())
+ start = std::max(0, positionArg.asInt32());
+ else {
+ unsigned length = stringToSearchIn.length();
+ start = clampAndTruncateToUnsigned(positionArg.toInteger(exec), 0, length);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ }
+
+ return JSValue::encode(jsBoolean(stringToSearchIn.hasInfixStartingAt(searchString, start)));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncEndsWith(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(exec);
+
+ String stringToSearchIn = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue a0 = exec->argument(0);
+ if (jsDynamicCast<RegExpObject*>(a0))
+ return throwVMTypeError(exec);
+
+ String searchString = a0.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ unsigned length = stringToSearchIn.length();
+
+ JSValue endPositionArg = exec->argument(1);
+ unsigned end = length;
+ if (endPositionArg.isInt32())
+ end = std::max(0, endPositionArg.asInt32());
+ else if (!endPositionArg.isUndefined()) {
+ end = clampAndTruncateToUnsigned(endPositionArg.toInteger(exec), 0, length);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ }
+
+ return JSValue::encode(jsBoolean(stringToSearchIn.hasInfixEndingAt(searchString, std::min(end, length))));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncIncludes(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(exec);
+
+ String stringToSearchIn = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue a0 = exec->argument(0);
+ if (jsDynamicCast<RegExpObject*>(a0))
+ return throwVMTypeError(exec);
+
+ String searchString = a0.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue positionArg = exec->argument(1);
+ unsigned start = 0;
+ if (positionArg.isInt32())
+ start = std::max(0, positionArg.asInt32());
+ else {
+ unsigned length = stringToSearchIn.length();
+ start = clampAndTruncateToUnsigned(positionArg.toInteger(exec), 0, length);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ }
+
+ return JSValue::encode(jsBoolean(stringToSearchIn.contains(searchString, true, start)));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncIterator(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(exec);
+ JSString* string = thisValue.toString(exec);
+ return JSValue::encode(JSStringIterator::create(exec, exec->callee()->globalObject()->stringIteratorStructure(), string));
+}
+
+static JSValue normalize(ExecState* exec, const UChar* source, size_t sourceLength, UNormalizationMode form)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t normalizedStringLength = unorm_normalize(source, sourceLength, form, 0, nullptr, 0, &status);
+
+ if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
+ // The behavior is not specified when normalize fails.
+ // Now we throw a type erorr since it seems that the contents of the string are invalid.
+ return throwTypeError(exec);
+ }
+
+ UChar* buffer = nullptr;
+ RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(normalizedStringLength, buffer);
+ if (!impl)
+ return throwOutOfMemoryError(exec);
+
+ status = U_ZERO_ERROR;
+ unorm_normalize(source, sourceLength, form, 0, buffer, normalizedStringLength, &status);
+ if (U_FAILURE(status))
+ return throwTypeError(exec);
+
+ return jsString(exec, impl.release());
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncNormalize(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(exec);
+ JSString::SafeView source = thisValue.toString(exec)->view(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ UNormalizationMode form = UNORM_NFC;
+ // Verify that the argument is provided and is not undefined.
+ if (!exec->argument(0).isUndefined()) {
+ String formString = exec->uncheckedArgument(0).toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (formString == "NFC")
+ form = UNORM_NFC;
+ else if (formString == "NFD")
+ form = UNORM_NFD;
+ else if (formString == "NFKC")
+ form = UNORM_NFKC;
+ else if (formString == "NFKD")
+ form = UNORM_NFKD;
+ else
+ return throwVMError(exec, createRangeError(exec, ASCIILiteral("argument does not match any normalization form")));
+ }
+
+ return JSValue::encode(normalize(exec, source.get().upconvertedCharacters(), source.length(), form));
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StringPrototype.h b/Source/JavaScriptCore/runtime/StringPrototype.h
index fe22453ad..1855cd92d 100644
--- a/Source/JavaScriptCore/runtime/StringPrototype.h
+++ b/Source/JavaScriptCore/runtime/StringPrototype.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2007, 2008, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2013, 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
@@ -21,33 +21,46 @@
#ifndef StringPrototype_h
#define StringPrototype_h
+#include "JITOperations.h"
#include "StringObject.h"
namespace JSC {
- class ObjectPrototype;
+class ObjectPrototype;
+class RegExpObject;
- class StringPrototype : public StringObject {
- private:
- StringPrototype(VM&, Structure*);
+class StringPrototype : public StringObject {
+private:
+ StringPrototype(VM&, Structure*);
- public:
- typedef StringObject Base;
+public:
+ typedef StringObject Base;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | Base::StructureFlags;
- static StringPrototype* create(VM&, JSGlobalObject*, Structure*);
+ static StringPrototype* create(VM&, JSGlobalObject*, Structure*);
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
- }
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
- DECLARE_INFO;
-
- protected:
- void finishCreation(VM&, JSGlobalObject*, JSString*);
- static const unsigned StructureFlags = StringObject::StructureFlags;
+ DECLARE_INFO;
- };
+protected:
+ void finishCreation(VM&, JSGlobalObject*, JSString*);
+
+private:
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+};
+
+EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceGeneric(
+ ExecState*, EncodedJSValue thisValue, EncodedJSValue searchValue, EncodedJSValue replaceValue);
+
+EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceRegExpEmptyStr(
+ ExecState*, JSString* thisValue, RegExpObject* searchValue);
+
+EncodedJSValue JIT_OPERATION operationStringProtoFuncReplaceRegExpString(
+ ExecState*, JSString* thisValue, RegExpObject* searchValue, JSString* replaceValue);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp b/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp
index 1f204231e..638310787 100644
--- a/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp
+++ b/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp
@@ -22,13 +22,13 @@
#include "Error.h"
#include "ExceptionHelpers.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
JSValue StringRecursionChecker::throwStackOverflowError()
{
- return m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec));
+ return JSC::throwStackOverflowError(m_exec);
}
JSValue StringRecursionChecker::emptyString()
diff --git a/Source/JavaScriptCore/runtime/StringRecursionChecker.h b/Source/JavaScriptCore/runtime/StringRecursionChecker.h
index c99dd4ff1..0f1990e76 100644
--- a/Source/JavaScriptCore/runtime/StringRecursionChecker.h
+++ b/Source/JavaScriptCore/runtime/StringRecursionChecker.h
@@ -52,7 +52,15 @@ inline JSValue StringRecursionChecker::performCheck()
VM& vm = m_exec->vm();
if (!vm.isSafeToRecurse())
return throwStackOverflowError();
- bool alreadyVisited = !vm.stringRecursionCheckVisitedObjects.add(m_thisObject).isNewEntry;
+
+ bool alreadyVisited = false;
+ if (!vm.stringRecursionCheckFirstObject)
+ vm.stringRecursionCheckFirstObject = m_thisObject;
+ else if (vm.stringRecursionCheckFirstObject == m_thisObject)
+ alreadyVisited = true;
+ else
+ alreadyVisited = !vm.stringRecursionCheckVisitedObjects.add(m_thisObject).isNewEntry;
+
if (alreadyVisited)
return emptyString(); // Return empty string to avoid infinite recursion.
return JSValue(); // Indicate success.
@@ -74,8 +82,14 @@ inline StringRecursionChecker::~StringRecursionChecker()
{
if (m_earlyReturnValue)
return;
- ASSERT(m_exec->vm().stringRecursionCheckVisitedObjects.contains(m_thisObject));
- m_exec->vm().stringRecursionCheckVisitedObjects.remove(m_thisObject);
+
+ VM& vm = m_exec->vm();
+ if (vm.stringRecursionCheckFirstObject == m_thisObject)
+ vm.stringRecursionCheckFirstObject = nullptr;
+ else {
+ ASSERT(vm.stringRecursionCheckVisitedObjects.contains(m_thisObject));
+ vm.stringRecursionCheckVisitedObjects.remove(m_thisObject);
+ }
}
}
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index 8781ab007..62c752cb3 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2013-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
@@ -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
@@ -28,13 +28,18 @@
#include "CodeBlock.h"
#include "DumpContext.h"
+#include "JSCInlines.h"
#include "JSObject.h"
-#include "JSPropertyNameIterator.h"
+#include "JSPropertyNameEnumerator.h"
#include "Lookup.h"
+#include "PropertyMapHashTable.h"
#include "PropertyNameArray.h"
#include "StructureChain.h"
#include "StructureRareDataInlines.h"
+#include "WeakGCMapInlines.h"
#include <wtf/CommaPrinter.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/ProcessID.h>
#include <wtf/RefCountedLeakCounter.h>
#include <wtf/RefPtr.h>
#include <wtf/Threading.h>
@@ -50,53 +55,79 @@
using namespace std;
using namespace WTF;
-#if DUMP_PROPERTYMAP_STATS
-
-int numProbes;
-int numCollisions;
-int numRehashes;
-int numRemoves;
-
-#endif
-
namespace JSC {
#if DUMP_STRUCTURE_ID_STATISTICS
static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>);
#endif
-bool StructureTransitionTable::contains(StringImpl* rep, unsigned attributes) const
+class SingleSlotTransitionWeakOwner final : public WeakHandleOwner {
+ void finalize(Handle<Unknown>, void* context) override
+ {
+ StructureTransitionTable* table = reinterpret_cast<StructureTransitionTable*>(context);
+ ASSERT(table->isUsingSingleSlot());
+ WeakSet::deallocate(table->weakImpl());
+ table->m_data = StructureTransitionTable::UsingSingleSlotFlag;
+ }
+};
+
+static SingleSlotTransitionWeakOwner& singleSlotTransitionWeakOwner()
+{
+ static NeverDestroyed<SingleSlotTransitionWeakOwner> owner;
+ return owner;
+}
+
+inline Structure* StructureTransitionTable::singleTransition() const
+{
+ ASSERT(isUsingSingleSlot());
+ if (WeakImpl* impl = this->weakImpl()) {
+ if (impl->state() == WeakImpl::Live)
+ return jsCast<Structure*>(impl->jsValue().asCell());
+ }
+ return nullptr;
+}
+
+inline void StructureTransitionTable::setSingleTransition(Structure* structure)
+{
+ ASSERT(isUsingSingleSlot());
+ if (WeakImpl* impl = this->weakImpl())
+ WeakSet::deallocate(impl);
+ WeakImpl* impl = WeakSet::allocate(structure, &singleSlotTransitionWeakOwner(), this);
+ m_data = reinterpret_cast<intptr_t>(impl) | UsingSingleSlotFlag;
+}
+
+bool StructureTransitionTable::contains(UniquedStringImpl* rep, unsigned attributes) const
{
if (isUsingSingleSlot()) {
Structure* transition = singleTransition();
- return transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes;
+ return transition && transition->m_nameInPrevious == rep && transition->attributesInPrevious() == attributes;
}
return map()->get(std::make_pair(rep, attributes));
}
-inline Structure* StructureTransitionTable::get(StringImpl* rep, unsigned attributes) const
+Structure* StructureTransitionTable::get(UniquedStringImpl* rep, unsigned attributes) const
{
if (isUsingSingleSlot()) {
Structure* transition = singleTransition();
- return (transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes) ? transition : 0;
+ return (transition && transition->m_nameInPrevious == rep && transition->attributesInPrevious() == attributes) ? transition : 0;
}
return map()->get(std::make_pair(rep, attributes));
}
-inline void StructureTransitionTable::add(VM& vm, Structure* structure)
+void StructureTransitionTable::add(VM& vm, Structure* structure)
{
if (isUsingSingleSlot()) {
Structure* existingTransition = singleTransition();
// This handles the first transition being added.
if (!existingTransition) {
- setSingleTransition(vm, structure);
+ setSingleTransition(structure);
return;
}
// This handles the second transition being added
// (or the first transition being despecified!)
- setMap(new TransitionMap());
+ setMap(new TransitionMap(vm));
add(vm, existingTransition);
}
@@ -105,7 +136,7 @@ inline void StructureTransitionTable::add(VM& vm, Structure* structure)
// Newer versions of the STL have an std::make_pair function that takes rvalue references.
// When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue.
// See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details
- map()->set(std::make_pair(structure->m_nameInPrevious.get(), +structure->m_attributesInPrevious), structure);
+ map()->set(std::make_pair(structure->m_nameInPrevious.get(), +structure->attributesInPrevious()), structure);
}
void Structure::dumpStatistics()
@@ -155,33 +186,38 @@ void Structure::dumpStatistics()
Structure::Structure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity)
: JSCell(vm, vm.structureStructure.get())
+ , m_blob(vm.heap.structureIDTable().allocateID(this), indexingType, typeInfo)
+ , m_outOfLineTypeFlags(typeInfo.outOfLineTypeFlags())
, m_globalObject(vm, this, globalObject, WriteBarrier<JSGlobalObject>::MayBeNull)
, m_prototype(vm, this, prototype)
, m_classInfo(classInfo)
, m_transitionWatchpointSet(IsWatched)
, m_offset(invalidOffset)
- , m_typeInfo(typeInfo)
- , m_indexingType(indexingType)
, m_inlineCapacity(inlineCapacity)
- , m_dictionaryKind(NoneDictionaryKind)
- , m_isPinnedPropertyTable(false)
- , m_hasGetterSetterProperties(classInfo->hasStaticSetterOrReadonlyProperties(vm))
- , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(classInfo->hasStaticSetterOrReadonlyProperties(vm))
- , m_hasNonEnumerableProperties(false)
- , m_attributesInPrevious(0)
- , m_specificFunctionThrashCount(0)
- , m_preventExtensions(false)
- , m_didTransition(false)
- , m_staticFunctionReified(false)
+ , m_bitField(0)
{
+ setDictionaryKind(NoneDictionaryKind);
+ setIsPinnedPropertyTable(false);
+ setHasGetterSetterProperties(classInfo->hasStaticSetterOrReadonlyProperties());
+ setHasCustomGetterSetterProperties(false);
+ setHasReadOnlyOrGetterSetterPropertiesExcludingProto(classInfo->hasStaticSetterOrReadonlyProperties());
+ setHasNonEnumerableProperties(false);
+ setAttributesInPrevious(0);
+ setPreventExtensions(false);
+ setDidTransition(false);
+ setStaticFunctionsReified(false);
+ setHasRareData(false);
+ setTransitionWatchpointIsLikelyToBeFired(false);
+ setHasBeenDictionary(false);
+
ASSERT(inlineCapacity <= JSFinalObject::maxInlineCapacity());
ASSERT(static_cast<PropertyOffset>(inlineCapacity) < firstOutOfLineOffset);
- ASSERT(!typeInfo.structureHasRareData());
- ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm));
- ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm));
+ ASSERT(!hasRareData());
+ ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
+ ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
}
-const ClassInfo Structure::s_info = { "Structure", 0, 0, 0, CREATE_METHOD_TABLE(Structure) };
+const ClassInfo Structure::s_info = { "Structure", 0, 0, CREATE_METHOD_TABLE(Structure) };
Structure::Structure(VM& vm)
: JSCell(CreatingEarlyCell)
@@ -189,54 +225,76 @@ Structure::Structure(VM& vm)
, m_classInfo(info())
, m_transitionWatchpointSet(IsWatched)
, m_offset(invalidOffset)
- , m_typeInfo(CompoundType, OverridesVisitChildren)
- , m_indexingType(0)
, m_inlineCapacity(0)
- , m_dictionaryKind(NoneDictionaryKind)
- , m_isPinnedPropertyTable(false)
- , m_hasGetterSetterProperties(m_classInfo->hasStaticSetterOrReadonlyProperties(vm))
- , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(m_classInfo->hasStaticSetterOrReadonlyProperties(vm))
- , m_hasNonEnumerableProperties(false)
- , m_attributesInPrevious(0)
- , m_specificFunctionThrashCount(0)
- , m_preventExtensions(false)
- , m_didTransition(false)
- , m_staticFunctionReified(false)
-{
- ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm));
- ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm));
-}
-
-Structure::Structure(VM& vm, const Structure* previous)
+ , m_bitField(0)
+{
+ setDictionaryKind(NoneDictionaryKind);
+ setIsPinnedPropertyTable(false);
+ setHasGetterSetterProperties(m_classInfo->hasStaticSetterOrReadonlyProperties());
+ setHasCustomGetterSetterProperties(false);
+ setHasReadOnlyOrGetterSetterPropertiesExcludingProto(m_classInfo->hasStaticSetterOrReadonlyProperties());
+ setHasNonEnumerableProperties(false);
+ setAttributesInPrevious(0);
+ setPreventExtensions(false);
+ setDidTransition(false);
+ setStaticFunctionsReified(false);
+ setHasRareData(false);
+ setTransitionWatchpointIsLikelyToBeFired(false);
+ setHasBeenDictionary(false);
+
+ TypeInfo typeInfo = TypeInfo(CellType, StructureFlags);
+ m_blob = StructureIDBlob(vm.heap.structureIDTable().allocateID(this), 0, typeInfo);
+ m_outOfLineTypeFlags = typeInfo.outOfLineTypeFlags();
+
+ ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
+ ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
+}
+
+Structure::Structure(VM& vm, Structure* previous, DeferredStructureTransitionWatchpointFire* deferred)
: JSCell(vm, vm.structureStructure.get())
, m_prototype(vm, this, previous->storedPrototype())
, m_classInfo(previous->m_classInfo)
, m_transitionWatchpointSet(IsWatched)
, m_offset(invalidOffset)
- , m_typeInfo(previous->typeInfo().type(), previous->typeInfo().flags() & ~StructureHasRareData)
- , m_indexingType(previous->indexingTypeIncludingHistory())
, m_inlineCapacity(previous->m_inlineCapacity)
- , m_dictionaryKind(previous->m_dictionaryKind)
- , m_isPinnedPropertyTable(false)
- , m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties)
- , m_hasReadOnlyOrGetterSetterPropertiesExcludingProto(previous->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto)
- , m_hasNonEnumerableProperties(previous->m_hasNonEnumerableProperties)
- , m_attributesInPrevious(0)
- , m_specificFunctionThrashCount(previous->m_specificFunctionThrashCount)
- , m_preventExtensions(previous->m_preventExtensions)
- , m_didTransition(true)
- , m_staticFunctionReified(previous->m_staticFunctionReified)
-{
- if (previous->typeInfo().structureHasRareData() && previous->rareData()->needsCloning())
- cloneRareDataFrom(vm, previous);
- else if (previous->previousID())
- m_previousOrRareData.set(vm, this, previous->previousID());
-
- previous->notifyTransitionFromThisStructure();
+ , m_bitField(0)
+{
+ setDictionaryKind(previous->dictionaryKind());
+ setIsPinnedPropertyTable(previous->hasBeenFlattenedBefore());
+ setHasGetterSetterProperties(previous->hasGetterSetterProperties());
+ setHasCustomGetterSetterProperties(previous->hasCustomGetterSetterProperties());
+ setHasReadOnlyOrGetterSetterPropertiesExcludingProto(previous->hasReadOnlyOrGetterSetterPropertiesExcludingProto());
+ setHasNonEnumerableProperties(previous->hasNonEnumerableProperties());
+ setAttributesInPrevious(0);
+ setPreventExtensions(previous->preventExtensions());
+ setDidTransition(true);
+ setStaticFunctionsReified(previous->staticFunctionsReified());
+ setHasRareData(false);
+ setHasBeenDictionary(previous->hasBeenDictionary());
+
+ TypeInfo typeInfo = previous->typeInfo();
+ m_blob = StructureIDBlob(vm.heap.structureIDTable().allocateID(this), previous->indexingTypeIncludingHistory(), typeInfo);
+ m_outOfLineTypeFlags = typeInfo.outOfLineTypeFlags();
+
+ ASSERT(!previous->typeInfo().structureIsImmortal());
+ setPreviousID(vm, previous);
+
+ previous->didTransitionFromThisStructure(deferred);
+
+ // Copy this bit now, in case previous was being watched.
+ setTransitionWatchpointIsLikelyToBeFired(previous->transitionWatchpointIsLikelyToBeFired());
+
if (previous->m_globalObject)
m_globalObject.set(vm, this, previous->m_globalObject.get());
- ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm));
- ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties(vm));
+ ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
+ ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
+}
+
+Structure::~Structure()
+{
+ if (typeInfo().structureIsImmortal())
+ return;
+ Heap::heap(this)->structureIDTable().deallocateID(this, m_blob.structureID());
}
void Structure::destroy(JSCell* cell)
@@ -279,7 +337,7 @@ void Structure::materializePropertyMap(VM& vm)
findStructuresAndMapForMaterialization(structures, structure, table);
if (table) {
- table = table->copy(vm, structure, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
+ table = table->copy(vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
structure->m_lock.unlock();
}
@@ -292,53 +350,27 @@ void Structure::materializePropertyMap(VM& vm)
else
propertyTable().set(vm, this, table);
+ InferredTypeTable* typeTable = m_inferredTypeTable.get();
+
for (size_t i = structures.size(); i--;) {
structure = structures[i];
if (!structure->m_nameInPrevious)
continue;
- PropertyMapEntry entry(vm, this, structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious.get());
+ PropertyMapEntry entry(structure->m_nameInPrevious.get(), structure->m_offset, structure->attributesInPrevious());
+ if (typeTable && typeTable->get(structure->m_nameInPrevious.get()))
+ entry.hasInferredType = true;
propertyTable()->add(entry, m_offset, PropertyTable::PropertyOffsetMustNotChange);
}
checkOffsetConsistency();
}
-inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity)
-{
- if (!currentCapacity)
- return initialOutOfLineCapacity;
- return currentCapacity * outOfLineGrowthFactor;
-}
-
-size_t Structure::suggestedNewOutOfLineStorageCapacity()
-{
- return nextOutOfLineStorageCapacity(outOfLineCapacity());
-}
-
-void Structure::despecifyDictionaryFunction(VM& vm, PropertyName propertyName)
-{
- StringImpl* rep = propertyName.uid();
-
- DeferGC deferGC(vm.heap);
- materializePropertyMapIfNecessary(vm, deferGC);
-
- ASSERT(isDictionary());
- ASSERT(propertyTable());
-
- PropertyMapEntry* entry = propertyTable()->find(rep).first;
- ASSERT(entry);
- entry->specificValue.clear();
-}
-
-Structure* Structure::addPropertyTransitionToExistingStructureImpl(Structure* structure, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset& offset)
+Structure* Structure::addPropertyTransitionToExistingStructureImpl(Structure* structure, UniquedStringImpl* uid, unsigned attributes, PropertyOffset& offset)
{
ASSERT(!structure->isDictionary());
ASSERT(structure->isObject());
if (Structure* existingTransition = structure->m_transitionTable.get(uid, attributes)) {
- JSCell* specificValueInPrevious = existingTransition->m_specificValueInPrevious.get();
- if (specificValueInPrevious && specificValueInPrevious != specificValue)
- return 0;
validateOffset(existingTransition->m_offset, existingTransition->inlineCapacity());
offset = existingTransition->m_offset;
return existingTransition;
@@ -347,16 +379,16 @@ Structure* Structure::addPropertyTransitionToExistingStructureImpl(Structure* st
return 0;
}
-Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset& offset)
+Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset& offset)
{
ASSERT(!isCompilationThread());
- return addPropertyTransitionToExistingStructureImpl(structure, propertyName.uid(), attributes, specificValue, offset);
+ return addPropertyTransitionToExistingStructureImpl(structure, propertyName.uid(), attributes, offset);
}
-Structure* Structure::addPropertyTransitionToExistingStructureConcurrently(Structure* structure, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset& offset)
+Structure* Structure::addPropertyTransitionToExistingStructureConcurrently(Structure* structure, UniquedStringImpl* uid, unsigned attributes, PropertyOffset& offset)
{
ConcurrentJITLocker locker(structure->m_lock);
- return addPropertyTransitionToExistingStructureImpl(structure, uid, attributes, specificValue, offset);
+ return addPropertyTransitionToExistingStructureImpl(structure, uid, attributes, offset);
}
bool Structure::anyObjectInChainMayInterceptIndexedAccesses() const
@@ -373,6 +405,30 @@ bool Structure::anyObjectInChainMayInterceptIndexedAccesses() const
}
}
+bool Structure::holesMustForwardToPrototype(VM& vm) const
+{
+ if (this->mayInterceptIndexedAccesses())
+ return true;
+
+ JSValue prototype = this->storedPrototype();
+ if (!prototype.isObject())
+ return false;
+ JSObject* object = asObject(prototype);
+
+ while (true) {
+ Structure& structure = *object->structure(vm);
+ if (hasIndexedProperties(object->indexingType()) || structure.mayInterceptIndexedAccesses())
+ return true;
+ prototype = structure.storedPrototype();
+ if (!prototype.isObject())
+ return false;
+ object = asObject(prototype);
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+ return false;
+}
+
bool Structure::needsSlowPutIndexing() const
{
return anyObjectInChainMayInterceptIndexedAccesses()
@@ -387,48 +443,34 @@ NonPropertyTransition Structure::suggestedArrayStorageTransition() const
return AllocateArrayStorage;
}
-Structure* Structure::addPropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset& offset, PutPropertySlot::Context context)
+Structure* Structure::addPropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset& offset, PutPropertySlot::Context context, DeferredStructureTransitionWatchpointFire* deferred)
{
- // If we have a specific function, we may have got to this point if there is
- // already a transition with the correct property name and attributes, but
- // specialized to a different function. In this case we just want to give up
- // and despecialize the transition.
- // In this case we clear the value of specificFunction which will result
- // in us adding a non-specific transition, and any subsequent lookup in
- // Structure::addPropertyTransitionToExistingStructure will just use that.
- if (specificValue && structure->m_transitionTable.contains(propertyName.uid(), attributes))
- specificValue = 0;
-
ASSERT(!structure->isDictionary());
ASSERT(structure->isObject());
- ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset));
+ ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, offset));
- if (structure->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
- specificValue = 0;
-
int maxTransitionLength;
if (context == PutPropertySlot::PutById)
maxTransitionLength = s_maxTransitionLengthForNonEvalPutById;
else
maxTransitionLength = s_maxTransitionLength;
if (structure->transitionCount() > maxTransitionLength) {
- Structure* transition = toCacheableDictionaryTransition(vm, structure);
+ Structure* transition = toCacheableDictionaryTransition(vm, structure, deferred);
ASSERT(structure != transition);
- offset = transition->putSpecificValue(vm, propertyName, attributes, specificValue);
+ offset = transition->add(vm, propertyName, attributes);
return transition;
}
- Structure* transition = create(vm, structure);
+ Structure* transition = create(vm, structure, deferred);
transition->m_cachedPrototypeChain.setMayBeNull(vm, transition, structure->m_cachedPrototypeChain.get());
- transition->setPreviousID(vm, transition, structure);
transition->m_nameInPrevious = propertyName.uid();
- transition->m_attributesInPrevious = attributes;
- transition->m_specificValueInPrevious.setMayBeNull(vm, transition, specificValue);
- transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm, transition));
+ transition->setAttributesInPrevious(attributes);
+ transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm));
transition->m_offset = structure->m_offset;
+ transition->m_inferredTypeTable.setMayBeNull(vm, transition, structure->m_inferredTypeTable.get());
- offset = transition->putSpecificValue(vm, propertyName, attributes, specificValue);
+ offset = transition->add(vm, propertyName, attributes);
checkOffset(transition->m_offset, transition->inlineCapacity());
{
@@ -442,6 +484,24 @@ Structure* Structure::addPropertyTransition(VM& vm, Structure* structure, Proper
Structure* Structure::removePropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, PropertyOffset& offset)
{
+ // NOTE: There are some good reasons why this goes directly to uncacheable dictionary rather than
+ // caching the removal. We can fix all of these things, but we must remember to do so, if we ever try
+ // to optimize this case.
+ //
+ // - Cached transitions usually steal the property table, and assume that this is possible because they
+ // can just rebuild the table by looking at past transitions. That code assumes that the table only
+ // grew and never shrank. To support removals, we'd have to change the property table materialization
+ // code to handle deletions. Also, we have logic to get the list of properties on a structure that
+ // lacks a property table by just looking back through the set of transitions since the last
+ // structure that had a pinned table. That logic would also have to be changed to handle cached
+ // removals.
+ //
+ // - InferredTypeTable assumes that removal has never happened. This is important since if we could
+ // remove a property and then re-add it later, then the "absence means top" optimization wouldn't
+ // work anymore, unless removal also either poisoned type inference (by doing something equivalent to
+ // hasBeenDictionary) or by strongly marking the entry as Top by ensuring that it is not absent, but
+ // instead, has a null entry.
+
ASSERT(!structure->isUncacheableDictionary());
Structure* transition = toUncacheableDictionaryTransition(vm, structure);
@@ -460,7 +520,7 @@ Structure* Structure::changePrototypeTransition(VM& vm, Structure* structure, JS
DeferGC deferGC(vm.heap);
structure->materializePropertyMapIfNecessary(vm, deferGC);
- transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
+ transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm));
transition->m_offset = structure->m_offset;
transition->pin();
@@ -468,30 +528,6 @@ Structure* Structure::changePrototypeTransition(VM& vm, Structure* structure, JS
return transition;
}
-Structure* Structure::despecifyFunctionTransition(VM& vm, Structure* structure, PropertyName replaceFunction)
-{
- ASSERT(structure->m_specificFunctionThrashCount < maxSpecificFunctionThrashCount);
- Structure* transition = create(vm, structure);
-
- ++transition->m_specificFunctionThrashCount;
-
- DeferGC deferGC(vm.heap);
- structure->materializePropertyMapIfNecessary(vm, deferGC);
- transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
- transition->m_offset = structure->m_offset;
- transition->pin();
-
- if (transition->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
- transition->despecifyAllFunctions(vm);
- else {
- bool removed = transition->despecifyFunction(vm, replaceFunction);
- ASSERT_UNUSED(removed, removed);
- }
-
- transition->checkOffsetConsistency();
- return transition;
-}
-
Structure* Structure::attributeChangeTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes)
{
DeferGC deferGC(vm.heap);
@@ -499,7 +535,7 @@ Structure* Structure::attributeChangeTransition(VM& vm, Structure* structure, Pr
Structure* transition = create(vm, structure);
structure->materializePropertyMapIfNecessary(vm, deferGC);
- transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
+ transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm));
transition->m_offset = structure->m_offset;
transition->pin();
@@ -507,7 +543,7 @@ Structure* Structure::attributeChangeTransition(VM& vm, Structure* structure, Pr
}
ASSERT(structure->propertyTable());
- PropertyMapEntry* entry = structure->propertyTable()->find(propertyName.uid()).first;
+ PropertyMapEntry* entry = structure->propertyTable()->get(propertyName.uid());
ASSERT(entry);
entry->attributes = attributes;
@@ -515,26 +551,27 @@ Structure* Structure::attributeChangeTransition(VM& vm, Structure* structure, Pr
return structure;
}
-Structure* Structure::toDictionaryTransition(VM& vm, Structure* structure, DictionaryKind kind)
+Structure* Structure::toDictionaryTransition(VM& vm, Structure* structure, DictionaryKind kind, DeferredStructureTransitionWatchpointFire* deferred)
{
ASSERT(!structure->isUncacheableDictionary());
- Structure* transition = create(vm, structure);
+ Structure* transition = create(vm, structure, deferred);
DeferGC deferGC(vm.heap);
structure->materializePropertyMapIfNecessary(vm, deferGC);
- transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
+ transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm));
transition->m_offset = structure->m_offset;
- transition->m_dictionaryKind = kind;
+ transition->setDictionaryKind(kind);
transition->pin();
+ transition->setHasBeenDictionary(true);
transition->checkOffsetConsistency();
return transition;
}
-Structure* Structure::toCacheableDictionaryTransition(VM& vm, Structure* structure)
+Structure* Structure::toCacheableDictionaryTransition(VM& vm, Structure* structure, DeferredStructureTransitionWatchpointFire* deferred)
{
- return toDictionaryTransition(vm, structure, CachedDictionaryKind);
+ return toDictionaryTransition(vm, structure, CachedDictionaryKind, deferred);
}
Structure* Structure::toUncacheableDictionaryTransition(VM& vm, Structure* structure)
@@ -566,13 +603,13 @@ Structure* Structure::freezeTransition(VM& vm, Structure* structure)
PropertyTable::iterator iter = transition->propertyTable()->begin();
PropertyTable::iterator end = transition->propertyTable()->end();
if (iter != end)
- transition->m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
+ transition->setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
for (; iter != end; ++iter)
iter->attributes |= iter->attributes & Accessor ? DontDelete : (DontDelete | ReadOnly);
}
- ASSERT(transition->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !transition->classInfo()->hasStaticSetterOrReadonlyProperties(vm));
- ASSERT(transition->hasGetterSetterProperties() || !transition->classInfo()->hasStaticSetterOrReadonlyProperties(vm));
+ ASSERT(transition->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !transition->classInfo()->hasStaticSetterOrReadonlyProperties());
+ ASSERT(transition->hasGetterSetterProperties() || !transition->classInfo()->hasStaticSetterOrReadonlyProperties());
transition->checkOffsetConsistency();
return transition;
}
@@ -586,22 +623,22 @@ Structure* Structure::preventExtensionsTransition(VM& vm, Structure* structure)
DeferGC deferGC(vm.heap);
structure->materializePropertyMapIfNecessary(vm, deferGC);
- transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition));
+ transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm));
transition->m_offset = structure->m_offset;
- transition->m_preventExtensions = true;
+ transition->setPreventExtensions(true);
transition->pin();
transition->checkOffsetConsistency();
return transition;
}
-PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM& vm, Structure* owner)
+PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM& vm)
{
DeferGC deferGC(vm.heap);
materializePropertyMapIfNecessaryForPinning(vm, deferGC);
- if (m_isPinnedPropertyTable)
- return propertyTable()->copy(vm, owner, propertyTable()->size() + 1);
+ if (isPinnedPropertyTable())
+ return propertyTable()->copy(vm, propertyTable()->size() + 1);
// Hold the lock while stealing the table - so that getConcurrently() on another thread
// will either have to bypass this structure, or will get to use the property table
@@ -621,27 +658,29 @@ Structure* Structure::nonPropertyTransition(VM& vm, Structure* structure, NonPro
if (globalObject->isOriginalArrayStructure(structure)) {
Structure* result = globalObject->originalArrayStructureForIndexingType(indexingType);
if (result->indexingTypeIncludingHistory() == indexingType) {
- structure->notifyTransitionFromThisStructure();
+ structure->didTransitionFromThisStructure();
return result;
}
}
}
- if (Structure* existingTransition = structure->m_transitionTable.get(0, attributes)) {
- ASSERT(existingTransition->m_attributesInPrevious == attributes);
+ Structure* existingTransition;
+ if (!structure->isDictionary() && (existingTransition = structure->m_transitionTable.get(0, attributes))) {
+ ASSERT(existingTransition->attributesInPrevious() == attributes);
ASSERT(existingTransition->indexingTypeIncludingHistory() == indexingType);
return existingTransition;
}
Structure* transition = create(vm, structure);
- transition->setPreviousID(vm, transition, structure);
- transition->m_attributesInPrevious = attributes;
- transition->m_indexingType = indexingType;
- transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm, transition));
+ transition->setAttributesInPrevious(attributes);
+ transition->m_blob.setIndexingType(indexingType);
+ transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm));
transition->m_offset = structure->m_offset;
checkOffset(transition->m_offset, transition->inlineCapacity());
- {
+ if (structure->isDictionary())
+ transition->pin();
+ else {
ConcurrentJITLocker locker(structure->m_lock);
structure->m_transitionTable.add(vm, transition);
}
@@ -693,6 +732,8 @@ Structure* Structure::flattenDictionaryStructure(VM& vm, JSObject* object)
{
checkOffsetConsistency();
ASSERT(isDictionary());
+
+ size_t beforeOutOfLineCapacity = this->outOfLineCapacity();
if (isUncacheableDictionary()) {
ASSERT(propertyTable());
@@ -718,35 +759,40 @@ Structure* Structure::flattenDictionaryStructure(VM& vm, JSObject* object)
checkOffsetConsistency();
}
- m_dictionaryKind = NoneDictionaryKind;
-
- // If the object had a Butterfly but after flattening/compacting we no longer have need of it,
- // we need to zero it out because the collector depends on the Structure to know the size for copying.
- if (object->butterfly() && !this->outOfLineCapacity() && !this->hasIndexingHeader(object))
- object->setStructureAndButterfly(vm, this, 0);
+ setDictionaryKind(NoneDictionaryKind);
+ setHasBeenFlattenedBefore(true);
+
+ size_t afterOutOfLineCapacity = this->outOfLineCapacity();
+
+ if (beforeOutOfLineCapacity != afterOutOfLineCapacity) {
+ ASSERT(beforeOutOfLineCapacity > afterOutOfLineCapacity);
+ // If the object had a Butterfly but after flattening/compacting we no longer have need of it,
+ // we need to zero it out because the collector depends on the Structure to know the size for copying.
+ if (object->butterfly() && !afterOutOfLineCapacity && !this->hasIndexingHeader(object))
+ object->setStructureAndButterfly(vm, this, 0);
+ // If the object was down-sized to the point where the base of the Butterfly is no longer within the
+ // first CopiedBlock::blockSize bytes, we'll get the wrong answer if we try to mask the base back to
+ // the CopiedBlock header. To prevent this case we need to memmove the Butterfly down.
+ else if (object->butterfly())
+ object->shiftButterflyAfterFlattening(vm, beforeOutOfLineCapacity, afterOutOfLineCapacity);
+ }
return this;
}
-PropertyOffset Structure::addPropertyWithoutTransition(VM& vm, PropertyName propertyName, unsigned attributes, JSCell* specificValue)
+PropertyOffset Structure::addPropertyWithoutTransition(VM& vm, PropertyName propertyName, unsigned attributes)
{
- ASSERT(!enumerationCache());
-
- if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
- specificValue = 0;
-
DeferGC deferGC(vm.heap);
materializePropertyMapIfNecessaryForPinning(vm, deferGC);
pin();
- return putSpecificValue(vm, propertyName, attributes, specificValue);
+ return add(vm, propertyName, attributes);
}
PropertyOffset Structure::removePropertyWithoutTransition(VM& vm, PropertyName propertyName)
{
ASSERT(isUncacheableDictionary());
- ASSERT(!enumerationCache());
DeferGC deferGC(vm.heap);
materializePropertyMapIfNecessaryForPinning(vm, deferGC);
@@ -758,150 +804,181 @@ PropertyOffset Structure::removePropertyWithoutTransition(VM& vm, PropertyName p
void Structure::pin()
{
ASSERT(propertyTable());
- m_isPinnedPropertyTable = true;
+ setIsPinnedPropertyTable(true);
clearPreviousID();
- m_nameInPrevious.clear();
+ m_nameInPrevious = nullptr;
}
void Structure::allocateRareData(VM& vm)
{
- ASSERT(!typeInfo().structureHasRareData());
+ ASSERT(!hasRareData());
StructureRareData* rareData = StructureRareData::create(vm, previous());
- m_typeInfo = TypeInfo(typeInfo().type(), typeInfo().flags() | StructureHasRareData);
+ WTF::storeStoreFence();
m_previousOrRareData.set(vm, this, rareData);
+ WTF::storeStoreFence();
+ setHasRareData(true);
+ ASSERT(hasRareData());
+}
+
+WatchpointSet* Structure::ensurePropertyReplacementWatchpointSet(VM& vm, PropertyOffset offset)
+{
+ ASSERT(!isUncacheableDictionary());
+
+ // In some places it's convenient to call this with an invalid offset. So, we do the check here.
+ if (!isValidOffset(offset))
+ return nullptr;
+
+ if (!hasRareData())
+ allocateRareData(vm);
+ ConcurrentJITLocker locker(m_lock);
+ StructureRareData* rareData = this->rareData();
+ if (!rareData->m_replacementWatchpointSets) {
+ rareData->m_replacementWatchpointSets =
+ std::make_unique<StructureRareData::PropertyWatchpointMap>();
+ WTF::storeStoreFence();
+ }
+ auto result = rareData->m_replacementWatchpointSets->add(offset, nullptr);
+ if (result.isNewEntry)
+ result.iterator->value = adoptRef(new WatchpointSet(IsWatched));
+ return result.iterator->value.get();
}
-void Structure::cloneRareDataFrom(VM& vm, const Structure* other)
+void Structure::startWatchingPropertyForReplacements(VM& vm, PropertyName propertyName)
{
- ASSERT(other->typeInfo().structureHasRareData());
- StructureRareData* newRareData = StructureRareData::clone(vm, other->rareData());
- m_typeInfo = TypeInfo(typeInfo().type(), typeInfo().flags() | StructureHasRareData);
- m_previousOrRareData.set(vm, this, newRareData);
+ ASSERT(!isUncacheableDictionary());
+
+ startWatchingPropertyForReplacements(vm, get(vm, propertyName));
+}
+
+void Structure::didCachePropertyReplacement(VM& vm, PropertyOffset offset)
+{
+ ensurePropertyReplacementWatchpointSet(vm, offset)->fireAll("Did cache property replacement");
+}
+
+void Structure::startWatchingInternalProperties(VM& vm)
+{
+ if (!isUncacheableDictionary()) {
+ startWatchingPropertyForReplacements(vm, vm.propertyNames->toString);
+ startWatchingPropertyForReplacements(vm, vm.propertyNames->valueOf);
+ }
+ setDidWatchInternalProperties(true);
+}
+
+void Structure::willStoreValueSlow(
+ VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize,
+ InferredTypeTable::StoredPropertyAge age)
+{
+ ASSERT(!isCompilationThread());
+ ASSERT(structure()->classInfo() == info());
+ ASSERT(!hasBeenDictionary());
+
+ // Create the inferred type table before doing anything else, so that we don't GC after we have already
+ // grabbed a pointer into the property map.
+ InferredTypeTable* table = m_inferredTypeTable.get();
+ if (!table) {
+ table = InferredTypeTable::create(vm);
+ WTF::storeStoreFence();
+ m_inferredTypeTable.set(vm, this, table);
+ }
+
+ // This only works if we've got a property table.
+ PropertyTable* propertyTable;
+ materializePropertyMapIfNecessary(vm, propertyTable);
+
+ // We must be calling this after having created the given property or confirmed that it was present
+ // already, so we must have a property table now.
+ ASSERT(propertyTable);
+
+ // ... and the property must be present.
+ PropertyMapEntry* entry = propertyTable->get(propertyName.uid());
+ ASSERT(entry);
+
+ if (shouldOptimize)
+ entry->hasInferredType = table->willStoreValue(vm, propertyName, value, age);
+ else {
+ table->makeTop(vm, propertyName, age);
+ entry->hasInferredType = false;
+ }
}
#if DUMP_PROPERTYMAP_STATS
+PropertyMapHashTableStats* propertyMapHashTableStats = 0;
+
struct PropertyMapStatisticsExitLogger {
+ PropertyMapStatisticsExitLogger();
~PropertyMapStatisticsExitLogger();
};
-static PropertyMapStatisticsExitLogger logger;
+DEFINE_GLOBAL_FOR_LOGGING(PropertyMapStatisticsExitLogger, logger, );
-PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger()
+PropertyMapStatisticsExitLogger::PropertyMapStatisticsExitLogger()
{
- dataLogF("\nJSC::PropertyMap statistics\n\n");
- dataLogF("%d probes\n", numProbes);
- dataLogF("%d collisions (%.1f%%)\n", numCollisions, 100.0 * numCollisions / numProbes);
- dataLogF("%d rehashes\n", numRehashes);
- dataLogF("%d removes\n", numRemoves);
+ propertyMapHashTableStats = adoptPtr(new PropertyMapHashTableStats()).leakPtr();
}
-#endif
-
-#if !DO_PROPERTYMAP_CONSTENCY_CHECK
-
-inline void Structure::checkConsistency()
+PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger()
{
- checkOffsetConsistency();
+ unsigned finds = propertyMapHashTableStats->numFinds;
+ unsigned collisions = propertyMapHashTableStats->numCollisions;
+ dataLogF("\nJSC::PropertyMap statistics for process %d\n\n", getCurrentProcessID());
+ dataLogF("%d finds\n", finds);
+ dataLogF("%d collisions (%.1f%%)\n", collisions, 100.0 * collisions / finds);
+ dataLogF("%d lookups\n", propertyMapHashTableStats->numLookups.load());
+ dataLogF("%d lookup probings\n", propertyMapHashTableStats->numLookupProbing.load());
+ dataLogF("%d adds\n", propertyMapHashTableStats->numAdds.load());
+ dataLogF("%d removes\n", propertyMapHashTableStats->numRemoves.load());
+ dataLogF("%d rehashes\n", propertyMapHashTableStats->numRehashes.load());
+ dataLogF("%d reinserts\n", propertyMapHashTableStats->numReinserts.load());
}
#endif
-PropertyTable* Structure::copyPropertyTable(VM& vm, Structure* owner)
+PropertyTable* Structure::copyPropertyTable(VM& vm)
{
if (!propertyTable())
return 0;
- return PropertyTable::clone(vm, owner, *propertyTable().get());
+ return PropertyTable::clone(vm, *propertyTable().get());
}
-PropertyTable* Structure::copyPropertyTableForPinning(VM& vm, Structure* owner)
+PropertyTable* Structure::copyPropertyTableForPinning(VM& vm)
{
if (propertyTable())
- return PropertyTable::clone(vm, owner, *propertyTable().get());
+ return PropertyTable::clone(vm, *propertyTable().get());
return PropertyTable::create(vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity));
}
-PropertyOffset Structure::getConcurrently(VM&, StringImpl* uid, unsigned& attributes, JSCell*& specificValue)
+PropertyOffset Structure::getConcurrently(UniquedStringImpl* uid, unsigned& attributes)
{
- Vector<Structure*, 8> structures;
- Structure* structure;
- PropertyTable* table;
-
- findStructuresAndMapForMaterialization(structures, structure, table);
+ PropertyOffset result = invalidOffset;
- if (table) {
- PropertyMapEntry* entry = table->find(uid).first;
- if (entry) {
- attributes = entry->attributes;
- specificValue = entry->specificValue.get();
- PropertyOffset result = entry->offset;
- structure->m_lock.unlock();
- return result;
- }
- structure->m_lock.unlock();
- }
-
- for (unsigned i = structures.size(); i--;) {
- structure = structures[i];
- if (structure->m_nameInPrevious.get() != uid)
- continue;
-
- attributes = structure->m_attributesInPrevious;
- specificValue = structure->m_specificValueInPrevious.get();
- return structure->m_offset;
- }
+ forEachPropertyConcurrently(
+ [&] (const PropertyMapEntry& candidate) -> bool {
+ if (candidate.key != uid)
+ return true;
+
+ result = candidate.offset;
+ attributes = candidate.attributes;
+ return false;
+ });
- return invalidOffset;
-}
-
-PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attributes, JSCell*& specificValue)
-{
- ASSERT(!isCompilationThread());
- ASSERT(structure()->classInfo() == info());
-
- DeferGC deferGC(vm.heap);
- materializePropertyMapIfNecessary(vm, deferGC);
- if (!propertyTable())
- return invalidOffset;
-
- PropertyMapEntry* entry = propertyTable()->find(propertyName.uid()).first;
- if (!entry)
- return invalidOffset;
-
- attributes = entry->attributes;
- specificValue = entry->specificValue.get();
- return entry->offset;
-}
-
-bool Structure::despecifyFunction(VM& vm, PropertyName propertyName)
-{
- DeferGC deferGC(vm.heap);
- materializePropertyMapIfNecessary(vm, deferGC);
- if (!propertyTable())
- return false;
-
- PropertyMapEntry* entry = propertyTable()->find(propertyName.uid()).first;
- if (!entry)
- return false;
-
- ASSERT(entry->specificValue);
- entry->specificValue.clear();
- return true;
+ return result;
}
-void Structure::despecifyAllFunctions(VM& vm)
+Vector<PropertyMapEntry> Structure::getPropertiesConcurrently()
{
- DeferGC deferGC(vm.heap);
- materializePropertyMapIfNecessary(vm, deferGC);
- if (!propertyTable())
- return;
+ Vector<PropertyMapEntry> result;
- PropertyTable::iterator end = propertyTable()->end();
- for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter)
- iter->specificValue.clear();
+ forEachPropertyConcurrently(
+ [&] (const PropertyMapEntry& entry) -> bool {
+ result.append(entry);
+ return true;
+ });
+
+ return result;
}
-PropertyOffset Structure::putSpecificValue(VM& vm, PropertyName propertyName, unsigned attributes, JSCell* specificValue)
+PropertyOffset Structure::add(VM& vm, PropertyName propertyName, unsigned attributes)
{
GCSafeConcurrentJITLocker locker(m_lock, vm.heap);
@@ -909,16 +986,16 @@ PropertyOffset Structure::putSpecificValue(VM& vm, PropertyName propertyName, un
checkConsistency();
if (attributes & DontEnum)
- m_hasNonEnumerableProperties = true;
+ setHasNonEnumerableProperties(true);
- StringImpl* rep = propertyName.uid();
+ auto rep = propertyName.uid();
if (!propertyTable())
createPropertyMap(locker, vm);
PropertyOffset newOffset = propertyTable()->nextOffset(m_inlineCapacity);
- propertyTable()->add(PropertyMapEntry(vm, this, rep, newOffset, attributes, specificValue), m_offset, PropertyTable::PropertyOffsetMayChange);
+ propertyTable()->add(PropertyMapEntry(rep, newOffset, attributes), m_offset, PropertyTable::PropertyOffsetMayChange);
checkConsistency();
return newOffset;
@@ -930,7 +1007,7 @@ PropertyOffset Structure::remove(PropertyName propertyName)
checkConsistency();
- StringImpl* rep = propertyName.uid();
+ auto rep = propertyName.uid();
if (!propertyTable())
return invalidOffset;
@@ -963,12 +1040,14 @@ void Structure::getPropertyNamesFromStructure(VM& vm, PropertyNameArray& propert
if (!propertyTable())
return;
- bool knownUnique = !propertyNames.size();
+ bool knownUnique = propertyNames.canAddKnownUniqueForStructure();
PropertyTable::iterator end = propertyTable()->end();
for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) {
- ASSERT(m_hasNonEnumerableProperties || !(iter->attributes & DontEnum));
- if (iter->key->isIdentifier() && (!(iter->attributes & DontEnum) || mode == IncludeDontEnumProperties)) {
+ ASSERT(hasNonEnumerableProperties() || !(iter->attributes & DontEnum));
+ if (!(iter->attributes & DontEnum) || mode.includeDontEnumProperties()) {
+ if (iter->key->isSymbol() && !propertyNames.includeSymbolProperties())
+ continue;
if (knownUnique)
propertyNames.addKnownUnique(iter->key);
else
@@ -977,6 +1056,43 @@ void Structure::getPropertyNamesFromStructure(VM& vm, PropertyNameArray& propert
}
}
+void StructureFireDetail::dump(PrintStream& out) const
+{
+ out.print("Structure transition from ", *m_structure);
+}
+
+DeferredStructureTransitionWatchpointFire::DeferredStructureTransitionWatchpointFire()
+ : m_structure(nullptr)
+{
+}
+
+DeferredStructureTransitionWatchpointFire::~DeferredStructureTransitionWatchpointFire()
+{
+ if (m_structure)
+ m_structure->transitionWatchpointSet().fireAll(StructureFireDetail(m_structure));
+}
+
+void DeferredStructureTransitionWatchpointFire::add(const Structure* structure)
+{
+ RELEASE_ASSERT(!m_structure);
+ RELEASE_ASSERT(structure);
+ m_structure = structure;
+}
+
+void Structure::didTransitionFromThisStructure(DeferredStructureTransitionWatchpointFire* deferred) const
+{
+ // If the structure is being watched, and this is the kind of structure that the DFG would
+ // like to watch, then make sure to note for all future versions of this structure that it's
+ // unwise to watch it.
+ if (m_transitionWatchpointSet.isBeingWatched())
+ const_cast<Structure*>(this)->setTransitionWatchpointIsLikelyToBeFired(true);
+
+ if (deferred)
+ deferred->add(this);
+ else
+ m_transitionWatchpointSet.fireAll(StructureFireDetail(this));
+}
+
JSValue Structure::prototypeForLookup(CodeBlock* codeBlock) const
{
return prototypeForLookup(codeBlock->globalObject());
@@ -986,7 +1102,6 @@ void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
Structure* thisObject = jsCast<Structure*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
JSCell::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_globalObject);
@@ -997,19 +1112,19 @@ void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitor.append(&thisObject->m_cachedPrototypeChain);
}
visitor.append(&thisObject->m_previousOrRareData);
- visitor.append(&thisObject->m_specificValueInPrevious);
- if (thisObject->m_isPinnedPropertyTable) {
+ if (thisObject->isPinnedPropertyTable()) {
ASSERT(thisObject->m_propertyTableUnsafe);
visitor.append(&thisObject->m_propertyTableUnsafe);
} else if (thisObject->m_propertyTableUnsafe)
thisObject->m_propertyTableUnsafe.clear();
+
+ visitor.append(&thisObject->m_inferredTypeTable);
}
bool Structure::prototypeChainMayInterceptStoreTo(VM& vm, PropertyName propertyName)
{
- unsigned i = propertyName.asIndex();
- if (i != PropertyName::NotAnIndex)
+ if (parseIndex(propertyName))
return anyObjectInChainMayInterceptIndexedAccesses();
for (Structure* current = this; ;) {
@@ -1017,11 +1132,10 @@ bool Structure::prototypeChainMayInterceptStoreTo(VM& vm, PropertyName propertyN
if (prototype.isNull())
return false;
- current = prototype.asCell()->structure();
+ current = prototype.asCell()->structure(vm);
unsigned attributes;
- JSCell* specificValue;
- PropertyOffset offset = current->get(vm, propertyName, attributes, specificValue);
+ PropertyOffset offset = current->get(vm, propertyName, attributes);
if (!JSC::isValidOffset(offset))
continue;
@@ -1032,39 +1146,83 @@ bool Structure::prototypeChainMayInterceptStoreTo(VM& vm, PropertyName propertyN
}
}
+PassRefPtr<StructureShape> Structure::toStructureShape(JSValue value)
+{
+ RefPtr<StructureShape> baseShape = StructureShape::create();
+ RefPtr<StructureShape> curShape = baseShape;
+ Structure* curStructure = this;
+ JSValue curValue = value;
+ while (curStructure) {
+ curStructure->forEachPropertyConcurrently(
+ [&] (const PropertyMapEntry& entry) -> bool {
+ curShape->addProperty(*entry.key);
+ return true;
+ });
+
+ if (JSObject* curObject = curValue.getObject())
+ curShape->setConstructorName(JSObject::calculatedClassName(curObject));
+ else
+ curShape->setConstructorName(curStructure->classInfo()->className);
+
+ if (curStructure->isDictionary())
+ curShape->enterDictionaryMode();
+
+ curShape->markAsFinal();
+
+ if (curStructure->storedPrototypeStructure()) {
+ RefPtr<StructureShape> newShape = StructureShape::create();
+ curShape->setProto(newShape);
+ curShape = newShape.release();
+ curValue = curStructure->storedPrototype();
+ }
+
+ curStructure = curStructure->storedPrototypeStructure();
+ }
+
+ return baseShape.release();
+}
+
+bool Structure::canUseForAllocationsOf(Structure* other)
+{
+ return inlineCapacity() == other->inlineCapacity()
+ && storedPrototype() == other->storedPrototype()
+ && objectInitializationBlob() == other->objectInitializationBlob();
+}
+
void Structure::dump(PrintStream& out) const
{
out.print(RawPointer(this), ":[", classInfo()->className, ", {");
- Vector<Structure*, 8> structures;
- Structure* structure;
- PropertyTable* table;
-
- const_cast<Structure*>(this)->findStructuresAndMapForMaterialization(
- structures, structure, table);
-
CommaPrinter comma;
- if (table) {
- PropertyTable::iterator iter = table->begin();
- PropertyTable::iterator end = table->end();
- for (; iter != end; ++iter)
- out.print(comma, iter->key, ":", static_cast<int>(iter->offset));
-
- structure->m_lock.unlock();
- }
-
- for (unsigned i = structures.size(); i--;) {
- Structure* structure = structures[i];
- if (!structure->m_nameInPrevious)
- continue;
- out.print(comma, structure->m_nameInPrevious.get(), ":", static_cast<int>(structure->m_offset));
- }
+ const_cast<Structure*>(this)->forEachPropertyConcurrently(
+ [&] (const PropertyMapEntry& entry) -> bool {
+ out.print(comma, entry.key, ":", static_cast<int>(entry.offset));
+ return true;
+ });
out.print("}, ", IndexingTypeDump(indexingType()));
if (m_prototype.get().isCell())
out.print(", Proto:", RawPointer(m_prototype.get().asCell()));
+
+ switch (dictionaryKind()) {
+ case NoneDictionaryKind:
+ if (hasBeenDictionary())
+ out.print(", Has been dictionary");
+ break;
+ case CachedDictionaryKind:
+ out.print(", Dictionary");
+ break;
+ case UncachedDictionaryKind:
+ out.print(", UncacheableDictionary");
+ break;
+ }
+
+ if (transitionWatchpointSetIsStillValid())
+ out.print(", Leaf");
+ else if (transitionWatchpointIsLikelyToBeFired())
+ out.print(", Shady leaf");
out.print("]");
}
@@ -1091,7 +1249,6 @@ void Structure::dumpContextHeader(PrintStream& out)
void PropertyTable::checkConsistency()
{
- checkOffsetConsistency();
ASSERT(m_indexSize >= PropertyTable::MinimumTableSize);
ASSERT(m_indexMask);
ASSERT(m_indexSize == m_indexMask + 1);
@@ -1129,7 +1286,7 @@ void PropertyTable::checkConsistency()
if (rep == PROPERTY_MAP_DELETED_ENTRY_KEY)
continue;
++nonEmptyEntryCount;
- unsigned i = rep->existingHash();
+ unsigned i = IdentifierRepHash::hash(rep);
unsigned k = 0;
unsigned entryIndex;
while (1) {
@@ -1138,7 +1295,7 @@ void PropertyTable::checkConsistency()
if (rep == table()[entryIndex - 1].key)
break;
if (k == 0)
- k = 1 | doubleHash(rep->existingHash());
+ k = 1 | doubleHash(IdentifierRepHash::hash(rep));
i += k;
}
ASSERT(entryIndex == c + 1);
@@ -1149,10 +1306,12 @@ void PropertyTable::checkConsistency()
void Structure::checkConsistency()
{
+ checkOffsetConsistency();
+
if (!propertyTable())
return;
- if (!m_hasNonEnumerableProperties) {
+ if (!hasNonEnumerableProperties()) {
PropertyTable::iterator end = propertyTable()->end();
for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) {
ASSERT(!(iter->attributes & DontEnum));
@@ -1162,12 +1321,19 @@ void Structure::checkConsistency()
propertyTable()->checkConsistency();
}
+#else
+
+inline void Structure::checkConsistency()
+{
+ checkOffsetConsistency();
+}
+
#endif // DO_PROPERTYMAP_CONSTENCY_CHECK
-bool ClassInfo::hasStaticSetterOrReadonlyProperties(VM& vm) const
+bool ClassInfo::hasStaticSetterOrReadonlyProperties() const
{
for (const ClassInfo* ci = this; ci; ci = ci->parentClass) {
- if (const HashTable* table = ci->propHashTable(vm)) {
+ if (const HashTable* table = ci->staticPropHashTable) {
if (table->hasSetterOrReadonlyProperties)
return true;
}
@@ -1175,4 +1341,55 @@ bool ClassInfo::hasStaticSetterOrReadonlyProperties(VM& vm) const
return false;
}
+void Structure::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
+{
+ ASSERT(!isDictionary());
+ if (!hasRareData())
+ allocateRareData(vm);
+ rareData()->setCachedPropertyNameEnumerator(vm, enumerator);
+}
+
+JSPropertyNameEnumerator* Structure::cachedPropertyNameEnumerator() const
+{
+ if (!hasRareData())
+ return nullptr;
+ return rareData()->cachedPropertyNameEnumerator();
+}
+
+bool Structure::canCachePropertyNameEnumerator() const
+{
+ if (isDictionary())
+ return false;
+
+ if (hasIndexedProperties(indexingType()))
+ return false;
+
+ if (typeInfo().overridesGetPropertyNames())
+ return false;
+
+ StructureChain* structureChain = m_cachedPrototypeChain.get();
+ ASSERT(structureChain);
+ WriteBarrier<Structure>* structure = structureChain->head();
+ while (true) {
+ if (!structure->get())
+ break;
+ if (structure->get()->typeInfo().overridesGetPropertyNames())
+ return false;
+ structure++;
+ }
+
+ return true;
+}
+
+bool Structure::canAccessPropertiesQuickly() const
+{
+ if (hasNonEnumerableProperties())
+ return false;
+ if (hasGetterSetterProperties())
+ return false;
+ if (isUncacheableDictionary())
+ return false;
+ return true;
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index c73e8cb96..392ca9176 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 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
@@ -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
@@ -29,6 +29,7 @@
#include "ClassInfo.h"
#include "ConcurrentJITLock.h"
#include "IndexingType.h"
+#include "InferredTypeTable.h"
#include "JSCJSValue.h"
#include "JSCell.h"
#include "JSType.h"
@@ -37,17 +38,24 @@
#include "PropertyOffset.h"
#include "Protect.h"
#include "PutPropertySlot.h"
+#include "StructureIDBlob.h"
#include "StructureRareData.h"
+#include "StructureRareDataInlines.h"
#include "StructureTransitionTable.h"
#include "JSTypeInfo.h"
#include "Watchpoint.h"
#include "Weak.h"
+#include "WriteBarrierInlines.h"
#include <wtf/CompilationThread.h>
#include <wtf/PassRefPtr.h>
#include <wtf/PrintStream.h>
#include <wtf/RefCounted.h>
-#include <wtf/text/StringImpl.h>
+namespace WTF {
+
+class UniquedStringImpl;
+
+} // namespace WTF
namespace JSC {
@@ -57,6 +65,7 @@ class PropertyNameArray;
class PropertyNameArrayData;
class PropertyTable;
class StructureChain;
+class StructureShape;
class SlotVisitor;
class JSString;
struct DumpContext;
@@ -70,14 +79,66 @@ static const unsigned initialOutOfLineCapacity = 4;
// initial allocation.
static const unsigned outOfLineGrowthFactor = 2;
-class Structure : public JSCell {
+struct PropertyMapEntry {
+ UniquedStringImpl* key;
+ PropertyOffset offset;
+ uint8_t attributes;
+ bool hasInferredType; // This caches whether or not a property has an inferred type in the inferred type table, and is used for a fast check in JSObject::putDirectInternal().
+
+ PropertyMapEntry()
+ : key(nullptr)
+ , offset(invalidOffset)
+ , attributes(0)
+ , hasInferredType(false)
+ {
+ }
+
+ PropertyMapEntry(UniquedStringImpl* key, PropertyOffset offset, unsigned attributes)
+ : key(key)
+ , offset(offset)
+ , attributes(attributes)
+ , hasInferredType(false)
+ {
+ ASSERT(this->attributes == attributes);
+ }
+};
+
+class StructureFireDetail : public FireDetail {
+public:
+ StructureFireDetail(const Structure* structure)
+ : m_structure(structure)
+ {
+ }
+
+ virtual void dump(PrintStream& out) const override;
+
+private:
+ const Structure* m_structure;
+};
+
+class DeferredStructureTransitionWatchpointFire {
+ WTF_MAKE_NONCOPYABLE(DeferredStructureTransitionWatchpointFire);
+public:
+ JS_EXPORT_PRIVATE DeferredStructureTransitionWatchpointFire();
+ JS_EXPORT_PRIVATE ~DeferredStructureTransitionWatchpointFire();
+
+ void add(const Structure*);
+
+private:
+ const Structure* m_structure;
+};
+
+class Structure final : public JSCell {
public:
friend class StructureTransitionTable;
typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
static Structure* create(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, unsigned inlineCapacity = 0);
+ ~Structure();
+
protected:
void finishCreation(VM& vm)
{
@@ -95,66 +156,90 @@ protected:
}
public:
+ StructureID id() const { return m_blob.structureID(); }
+ int32_t objectInitializationBlob() const { return m_blob.blobExcludingStructureID(); }
+ int64_t idBlob() const { return m_blob.blob(); }
+
+ bool isProxy() const
+ {
+ JSType type = m_blob.type();
+ return type == ImpureProxyType || type == PureForwardingProxyType;
+ }
+
static void dumpStatistics();
- JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext);
- static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset&);
- JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&);
+ JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext, DeferredStructureTransitionWatchpointFire* = nullptr);
+ static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&);
+ JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, PropertyOffset&);
static Structure* removePropertyTransition(VM&, Structure*, PropertyName, PropertyOffset&);
JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(VM&, Structure*, JSValue prototype);
- JS_EXPORT_PRIVATE static Structure* despecifyFunctionTransition(VM&, Structure*, PropertyName);
- static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes);
- static Structure* toCacheableDictionaryTransition(VM&, Structure*);
+ JS_EXPORT_PRIVATE static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes);
+ JS_EXPORT_PRIVATE static Structure* toCacheableDictionaryTransition(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr);
static Structure* toUncacheableDictionaryTransition(VM&, Structure*);
- static Structure* sealTransition(VM&, Structure*);
- static Structure* freezeTransition(VM&, Structure*);
+ JS_EXPORT_PRIVATE static Structure* sealTransition(VM&, Structure*);
+ JS_EXPORT_PRIVATE static Structure* freezeTransition(VM&, Structure*);
static Structure* preventExtensionsTransition(VM&, Structure*);
- static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition);
+ JS_EXPORT_PRIVATE static Structure* nonPropertyTransition(VM&, Structure*, NonPropertyTransition);
- bool isSealed(VM&);
- bool isFrozen(VM&);
- bool isExtensible() const { return !m_preventExtensions; }
- bool didTransition() const { return m_didTransition; }
+ JS_EXPORT_PRIVATE bool isSealed(VM&);
+ JS_EXPORT_PRIVATE bool isFrozen(VM&);
+ bool isExtensible() const { return !preventExtensions(); }
bool putWillGrowOutOfLineStorage();
- JS_EXPORT_PRIVATE size_t suggestedNewOutOfLineStorageCapacity();
+ size_t suggestedNewOutOfLineStorageCapacity();
- Structure* flattenDictionaryStructure(VM&, JSObject*);
+ JS_EXPORT_PRIVATE Structure* flattenDictionaryStructure(VM&, JSObject*);
static const bool needsDestruction = true;
- static const bool hasImmortalStructure = true;
static void destroy(JSCell*);
// These should be used with caution.
- JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(VM&, PropertyName, unsigned attributes, JSCell* specificValue);
+ JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(VM&, PropertyName, unsigned attributes);
PropertyOffset removePropertyWithoutTransition(VM&, PropertyName);
void setPrototypeWithoutTransition(VM& vm, JSValue prototype) { m_prototype.set(vm, this, prototype); }
- bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
- bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
+ bool isDictionary() const { return dictionaryKind() != NoneDictionaryKind; }
+ bool isUncacheableDictionary() const { return dictionaryKind() == UncachedDictionaryKind; }
+
+ bool propertyAccessesAreCacheable()
+ {
+ return dictionaryKind() != UncachedDictionaryKind
+ && !typeInfo().prohibitsPropertyCaching()
+ && !(typeInfo().getOwnPropertySlotIsImpure() && !typeInfo().newImpurePropertyFiresWatchpoints());
+ }
- bool propertyAccessesAreCacheable() { return m_dictionaryKind != UncachedDictionaryKind && !typeInfo().prohibitsPropertyCaching(); }
+ bool propertyAccessesAreCacheableForAbsence()
+ {
+ return !typeInfo().getOwnPropertySlotIsImpureForPropertyAbsence();
+ }
+
+ bool needImpurePropertyWatchpoint()
+ {
+ return propertyAccessesAreCacheable()
+ && typeInfo().getOwnPropertySlotIsImpure()
+ && typeInfo().newImpurePropertyFiresWatchpoints();
+ }
// We use SlowPath in GetByIdStatus for structures that may get new impure properties later to prevent
// DFG from inlining property accesses since structures don't transition when a new impure property appears.
bool takesSlowPathInDFGForImpureProperty()
{
- ASSERT(!typeInfo().hasImpureGetOwnPropertySlot() || typeInfo().newImpurePropertyFiresWatchpoints());
- return typeInfo().hasImpureGetOwnPropertySlot();
+ return typeInfo().getOwnPropertySlotIsImpure();
}
-
+
// Type accessors.
- const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == info()); return m_typeInfo; }
+ TypeInfo typeInfo() const { ASSERT(structure()->classInfo() == info()); return m_blob.typeInfo(m_outOfLineTypeFlags); }
bool isObject() const { return typeInfo().isObject(); }
- IndexingType indexingType() const { return m_indexingType & AllArrayTypes; }
- IndexingType indexingTypeIncludingHistory() const { return m_indexingType; }
+ IndexingType indexingType() const { return m_blob.indexingType() & AllArrayTypes; }
+ IndexingType indexingTypeIncludingHistory() const { return m_blob.indexingType(); }
bool mayInterceptIndexedAccesses() const
{
return !!(indexingTypeIncludingHistory() & MayHaveIndexedAccessors);
}
- bool anyObjectInChainMayInterceptIndexedAccesses() const;
+ JS_EXPORT_PRIVATE bool anyObjectInChainMayInterceptIndexedAccesses() const;
+ bool holesMustForwardToPrototype(VM&) const;
bool needsSlowPutIndexing() const;
NonPropertyTransition suggestedArrayStorageTransition() const;
@@ -173,14 +258,12 @@ public:
static void visitChildren(JSCell*, SlotVisitor&);
// Will just the prototype chain intercept this property access?
- bool prototypeChainMayInterceptStoreTo(VM&, PropertyName);
-
- bool transitionDidInvolveSpecificValue() const { return !!m_specificValueInPrevious; }
+ JS_EXPORT_PRIVATE bool prototypeChainMayInterceptStoreTo(VM&, PropertyName);
Structure* previousID() const
{
ASSERT(structure()->classInfo() == info());
- if (typeInfo().structureHasRareData())
+ if (hasRareData())
return rareData()->previousID();
return previous();
}
@@ -237,11 +320,16 @@ public:
&& offset <= m_offset
&& (offset < m_inlineCapacity || offset >= firstOutOfLineOffset);
}
+
+ bool hijacksIndexingHeader() const
+ {
+ return isTypedView(m_classInfo->typedArrayStorageType);
+ }
bool couldHaveIndexingHeader() const
{
return hasIndexedProperties(indexingType())
- || isTypedView(m_classInfo->typedArrayStorageType);
+ || hijacksIndexingHeader();
}
bool hasIndexingHeader(const JSCell*) const;
@@ -249,66 +337,66 @@ public:
bool masqueradesAsUndefined(JSGlobalObject* lexicalGlobalObject);
PropertyOffset get(VM&, PropertyName);
- PropertyOffset get(VM&, const WTF::String& name);
- JS_EXPORT_PRIVATE PropertyOffset get(VM&, PropertyName, unsigned& attributes, JSCell*& specificValue);
-
- PropertyOffset getConcurrently(VM&, StringImpl* uid);
- PropertyOffset getConcurrently(VM&, StringImpl* uid, unsigned& attributes, JSCell*& specificValue);
-
- bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
- bool hasReadOnlyOrGetterSetterPropertiesExcludingProto() const { return m_hasReadOnlyOrGetterSetterPropertiesExcludingProto; }
- void setHasGetterSetterProperties(bool is__proto__)
+ PropertyOffset get(VM&, PropertyName, unsigned& attributes);
+ PropertyOffset get(VM&, PropertyName, unsigned& attributes, bool& hasInferredType);
+
+ // This is a somewhat internalish method. It will call your functor while possibly holding the
+ // Structure's lock. There is no guarantee whether the lock is held or not in any particular
+ // call. So, you have to assume the worst. Also, the functor returns true if it wishes for you
+ // to continue or false if it's done.
+ template<typename Functor>
+ void forEachPropertyConcurrently(const Functor&);
+
+ PropertyOffset getConcurrently(UniquedStringImpl* uid);
+ PropertyOffset getConcurrently(UniquedStringImpl* uid, unsigned& attributes);
+
+ Vector<PropertyMapEntry> getPropertiesConcurrently();
+
+ void setHasGetterSetterPropertiesWithProtoCheck(bool is__proto__)
{
- m_hasGetterSetterProperties = true;
+ setHasGetterSetterProperties(true);
if (!is__proto__)
- m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
+ setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
}
- void setContainsReadOnlyProperties()
+
+ void setContainsReadOnlyProperties() { setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true); }
+
+ void setHasCustomGetterSetterPropertiesWithProtoCheck(bool is__proto__)
{
- m_hasReadOnlyOrGetterSetterPropertiesExcludingProto = true;
+ setHasCustomGetterSetterProperties(true);
+ if (!is__proto__)
+ setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
}
-
- bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
-
+
bool isEmpty() const
{
ASSERT(checkOffsetConsistency());
return !JSC::isValidOffset(m_offset);
}
- JS_EXPORT_PRIVATE void despecifyDictionaryFunction(VM&, PropertyName);
- void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
+ void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
+ JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
+ bool canCachePropertyNameEnumerator() const;
+ bool canAccessPropertiesQuickly() const;
- void setEnumerationCache(VM&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
- JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode);
JSString* objectToStringValue()
{
- if (!typeInfo().structureHasRareData())
+ if (!hasRareData())
return 0;
return rareData()->objectToStringValue();
}
- void setObjectToStringValue(VM& vm, const JSCell* owner, JSString* value)
- {
- if (!typeInfo().structureHasRareData())
- allocateRareData(vm);
- rareData()->setObjectToStringValue(vm, owner, value);
- }
+ void setObjectToStringValue(ExecState*, VM&, JSString* value, PropertySlot toStringTagSymbolSlot);
- bool staticFunctionsReified()
- {
- return m_staticFunctionReified;
- }
+ const ClassInfo* classInfo() const { return m_classInfo; }
- void setStaticFunctionsReified()
+ static ptrdiff_t structureIDOffset()
{
- m_staticFunctionReified = true;
+ return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::structureIDOffset();
}
- const ClassInfo* classInfo() const { return m_classInfo; }
-
static ptrdiff_t prototypeOffset()
{
return OBJECT_OFFSETOF(Structure, m_prototype);
@@ -319,16 +407,6 @@ public:
return OBJECT_OFFSETOF(Structure, m_globalObject);
}
- static ptrdiff_t typeInfoFlagsOffset()
- {
- return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset();
- }
-
- static ptrdiff_t typeInfoTypeOffset()
- {
- return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
- }
-
static ptrdiff_t classInfoOffset()
{
return OBJECT_OFFSETOF(Structure, m_classInfo);
@@ -336,7 +414,7 @@ public:
static ptrdiff_t indexingTypeOffset()
{
- return OBJECT_OFFSETOF(Structure, m_indexingType);
+ return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingTypeOffset();
}
static Structure* createStructure(VM&);
@@ -350,23 +428,125 @@ public:
{
return m_transitionWatchpointSet.isStillValid();
}
+
+ bool dfgShouldWatchIfPossible() const
+ {
+ // FIXME: We would like to not watch things that are unprofitable to watch, like
+ // dictionaries. Unfortunately, we can't do such things: a dictionary could get flattened,
+ // in which case it will start to appear watchable and so the DFG will think that it is
+ // watching it. We should come up with a comprehensive story for not watching things that
+ // aren't profitable to watch.
+ // https://bugs.webkit.org/show_bug.cgi?id=133625
- void addTransitionWatchpoint(Watchpoint* watchpoint) const
+ // - We don't watch Structures that either decided not to be watched, or whose predecessors
+ // decided not to be watched. This happens either when a transition is fired while being
+ // watched.
+ if (transitionWatchpointIsLikelyToBeFired())
+ return false;
+
+ // - Don't watch Structures that had been dictionaries.
+ if (hasBeenDictionary())
+ return false;
+
+ return true;
+ }
+
+ bool dfgShouldWatch() const
{
- ASSERT(transitionWatchpointSetIsStillValid());
- m_transitionWatchpointSet.add(watchpoint);
+ return dfgShouldWatchIfPossible() && transitionWatchpointSetIsStillValid();
}
- void notifyTransitionFromThisStructure() const
+ void addTransitionWatchpoint(Watchpoint* watchpoint) const
{
- m_transitionWatchpointSet.fireAll();
+ ASSERT(transitionWatchpointSetIsStillValid());
+ m_transitionWatchpointSet.add(watchpoint);
}
+ void didTransitionFromThisStructure(DeferredStructureTransitionWatchpointFire* = nullptr) const;
+
InlineWatchpointSet& transitionWatchpointSet() const
{
return m_transitionWatchpointSet;
}
+ WatchpointSet* ensurePropertyReplacementWatchpointSet(VM&, PropertyOffset);
+ void startWatchingPropertyForReplacements(VM& vm, PropertyOffset offset)
+ {
+ ensurePropertyReplacementWatchpointSet(vm, offset);
+ }
+ void startWatchingPropertyForReplacements(VM&, PropertyName);
+ WatchpointSet* propertyReplacementWatchpointSet(PropertyOffset);
+ void didReplaceProperty(PropertyOffset);
+ void didCachePropertyReplacement(VM&, PropertyOffset);
+
+ void startWatchingInternalPropertiesIfNecessary(VM& vm)
+ {
+ if (LIKELY(didWatchInternalProperties()))
+ return;
+ startWatchingInternalProperties(vm);
+ }
+
+ void startWatchingInternalPropertiesIfNecessaryForEntireChain(VM& vm)
+ {
+ for (Structure* structure = this; structure; structure = structure->storedPrototypeStructure())
+ structure->startWatchingInternalPropertiesIfNecessary(vm);
+ }
+
+ bool hasInferredTypes() const
+ {
+ return !!m_inferredTypeTable;
+ }
+
+ InferredType* inferredTypeFor(UniquedStringImpl* uid)
+ {
+ if (InferredTypeTable* table = m_inferredTypeTable.get())
+ return table->get(uid);
+ return nullptr;
+ }
+
+ InferredType::Descriptor inferredTypeDescriptorFor(UniquedStringImpl* uid)
+ {
+ if (InferredType* result = inferredTypeFor(uid))
+ return result->descriptor();
+ return InferredType::Top;
+ }
+
+ // Call this when we know that this is a brand new property. Note that it's not enough for the
+ // property to be brand new to some object. It has to be brand new to the Structure.
+ ALWAYS_INLINE void willStoreValueForNewTransition(
+ VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize)
+ {
+ if (hasBeenDictionary() || (!shouldOptimize && !m_inferredTypeTable))
+ return;
+ willStoreValueSlow(vm, propertyName, value, shouldOptimize, InferredTypeTable::NewProperty);
+ }
+
+ // Call this when we know that this is a new property for the object, but not new for the
+ // structure. Therefore, under the InferredTypeTable's rules, absence of the property from the
+ // table means Top rather than Bottom.
+ ALWAYS_INLINE void willStoreValueForExistingTransition(
+ VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize)
+ {
+ if (hasBeenDictionary() || !m_inferredTypeTable)
+ return;
+ willStoreValueSlow(vm, propertyName, value, shouldOptimize, InferredTypeTable::NewProperty);
+ }
+
+ // Call this when we know that the inferred type table exists and has an entry for this property.
+ ALWAYS_INLINE void willStoreValueForReplace(
+ VM& vm, PropertyName propertyName, JSValue value, bool shouldOptimize)
+ {
+ if (hasBeenDictionary())
+ return;
+ willStoreValueSlow(vm, propertyName, value, shouldOptimize, InferredTypeTable::OldProperty);
+ }
+
+ PassRefPtr<StructureShape> toStructureShape(JSValue);
+
+ // Determines if the two structures match enough that this one could be used for allocations
+ // of the other one.
+ bool canUseForAllocationsOf(Structure*);
+
void dump(PrintStream&) const;
void dumpInContext(PrintStream&, DumpContext*) const;
void dumpBrief(PrintStream&, const CString&) const;
@@ -376,15 +556,49 @@ public:
DECLARE_EXPORT_INFO;
private:
+ typedef enum {
+ NoneDictionaryKind = 0,
+ CachedDictionaryKind = 1,
+ UncachedDictionaryKind = 2
+ } DictionaryKind;
+
+public:
+#define DEFINE_BITFIELD(type, lowerName, upperName, width, offset) \
+ static const uint32_t s_##lowerName##Shift = offset;\
+ static const uint32_t s_##lowerName##Mask = ((1 << (width - 1)) | ((1 << (width - 1)) - 1));\
+ type lowerName() const { return static_cast<type>((m_bitField >> offset) & s_##lowerName##Mask); }\
+ void set##upperName(type newValue) \
+ {\
+ m_bitField &= ~(s_##lowerName##Mask << offset);\
+ m_bitField |= (newValue & s_##lowerName##Mask) << offset;\
+ }
+
+ DEFINE_BITFIELD(DictionaryKind, dictionaryKind, DictionaryKind, 2, 0);
+ DEFINE_BITFIELD(bool, isPinnedPropertyTable, IsPinnedPropertyTable, 1, 2);
+ DEFINE_BITFIELD(bool, hasGetterSetterProperties, HasGetterSetterProperties, 1, 3);
+ DEFINE_BITFIELD(bool, hasReadOnlyOrGetterSetterPropertiesExcludingProto, HasReadOnlyOrGetterSetterPropertiesExcludingProto, 1, 4);
+ DEFINE_BITFIELD(bool, hasNonEnumerableProperties, HasNonEnumerableProperties, 1, 5);
+ DEFINE_BITFIELD(unsigned, attributesInPrevious, AttributesInPrevious, 14, 6);
+ DEFINE_BITFIELD(bool, preventExtensions, PreventExtensions, 1, 20);
+ DEFINE_BITFIELD(bool, didTransition, DidTransition, 1, 21);
+ DEFINE_BITFIELD(bool, staticFunctionsReified, StaticFunctionsReified, 1, 22);
+ DEFINE_BITFIELD(bool, hasRareData, HasRareData, 1, 23);
+ DEFINE_BITFIELD(bool, hasBeenFlattenedBefore, HasBeenFlattenedBefore, 1, 24);
+ DEFINE_BITFIELD(bool, hasCustomGetterSetterProperties, HasCustomGetterSetterProperties, 1, 25);
+ DEFINE_BITFIELD(bool, didWatchInternalProperties, DidWatchInternalProperties, 1, 26);
+ DEFINE_BITFIELD(bool, transitionWatchpointIsLikelyToBeFired, TransitionWatchpointIsLikelyToBeFired, 1, 27);
+ DEFINE_BITFIELD(bool, hasBeenDictionary, HasBeenDictionary, 1, 28);
+
+private:
friend class LLIntOffsetsExtractor;
JS_EXPORT_PRIVATE Structure(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, unsigned inlineCapacity);
Structure(VM&);
- Structure(VM&, const Structure*);
+ Structure(VM&, Structure*, DeferredStructureTransitionWatchpointFire*);
- static Structure* create(VM&, const Structure*);
+ static Structure* create(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr);
- static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset&);
+ static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&);
// This will return the structure that has a usable property table, that property table,
// and the list of structures that we visited before we got to it. If it returns a
@@ -392,28 +606,20 @@ private:
// to unlock it.
void findStructuresAndMapForMaterialization(Vector<Structure*, 8>& structures, Structure*&, PropertyTable*&);
- typedef enum {
- NoneDictionaryKind = 0,
- CachedDictionaryKind = 1,
- UncachedDictionaryKind = 2
- } DictionaryKind;
- static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind);
+ static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind, DeferredStructureTransitionWatchpointFire* = nullptr);
- PropertyOffset putSpecificValue(VM&, PropertyName, unsigned attributes, JSCell* specificValue);
+ PropertyOffset add(VM&, PropertyName, unsigned attributes);
PropertyOffset remove(PropertyName);
void createPropertyMap(const GCSafeConcurrentJITLocker&, VM&, unsigned keyCount = 0);
void checkConsistency();
- bool despecifyFunction(VM&, PropertyName);
- void despecifyAllFunctions(VM&);
-
WriteBarrier<PropertyTable>& propertyTable();
- PropertyTable* takePropertyTableOrCloneIfPinned(VM&, Structure* owner);
- PropertyTable* copyPropertyTable(VM&, Structure* owner);
- PropertyTable* copyPropertyTableForPinning(VM&, Structure* owner);
+ PropertyTable* takePropertyTableOrCloneIfPinned(VM&);
+ PropertyTable* copyPropertyTable(VM&);
+ PropertyTable* copyPropertyTableForPinning(VM&);
JS_EXPORT_PRIVATE void materializePropertyMap(VM&);
- void materializePropertyMapIfNecessary(VM& vm, DeferGC&)
+ ALWAYS_INLINE void materializePropertyMapIfNecessary(VM& vm, DeferGC&)
{
ASSERT(!isCompilationThread());
ASSERT(structure()->classInfo() == info());
@@ -421,6 +627,18 @@ private:
if (!propertyTable() && previousID())
materializePropertyMap(vm);
}
+ ALWAYS_INLINE void materializePropertyMapIfNecessary(VM& vm, PropertyTable*& table)
+ {
+ ASSERT(!isCompilationThread());
+ ASSERT(structure()->classInfo() == info());
+ ASSERT(checkOffsetConsistency());
+ table = propertyTable().get();
+ if (!table && previousID()) {
+ DeferGC deferGC(vm.heap);
+ materializePropertyMap(vm);
+ table = propertyTable().get();
+ }
+ }
void materializePropertyMapIfNecessaryForPinning(VM& vm, DeferGC&)
{
ASSERT(structure()->classInfo() == info());
@@ -429,17 +647,17 @@ private:
materializePropertyMap(vm);
}
- void setPreviousID(VM& vm, Structure* transition, Structure* structure)
+ void setPreviousID(VM& vm, Structure* structure)
{
- if (typeInfo().structureHasRareData())
- rareData()->setPreviousID(vm, transition, structure);
+ if (hasRareData())
+ rareData()->setPreviousID(vm, structure);
else
- m_previousOrRareData.set(vm, transition, structure);
+ m_previousOrRareData.set(vm, this, structure);
}
void clearPreviousID()
{
- if (typeInfo().structureHasRareData())
+ if (hasRareData())
rareData()->clearPreviousID();
else
m_previousOrRareData.clear();
@@ -458,34 +676,40 @@ private:
Structure* previous() const
{
- ASSERT(!typeInfo().structureHasRareData());
+ ASSERT(!hasRareData());
return static_cast<Structure*>(m_previousOrRareData.get());
}
StructureRareData* rareData() const
{
- ASSERT(typeInfo().structureHasRareData());
+ ASSERT(hasRareData());
return static_cast<StructureRareData*>(m_previousOrRareData.get());
}
bool checkOffsetConsistency() const;
- void allocateRareData(VM&);
- void cloneRareDataFrom(VM&, const Structure*);
+ JS_EXPORT_PRIVATE void allocateRareData(VM&);
+
+ void startWatchingInternalProperties(VM&);
+
+ JS_EXPORT_PRIVATE void willStoreValueSlow(
+ VM&, PropertyName, JSValue, bool, InferredTypeTable::StoredPropertyAge);
static const int s_maxTransitionLength = 64;
static const int s_maxTransitionLengthForNonEvalPutById = 512;
- static const unsigned maxSpecificFunctionThrashCount = 3;
-
+ // These need to be properly aligned at the beginning of the 'Structure'
+ // part of the object.
+ StructureIDBlob m_blob;
+ TypeInfo::OutOfLineTypeFlags m_outOfLineTypeFlags;
+
WriteBarrier<JSGlobalObject> m_globalObject;
WriteBarrier<Unknown> m_prototype;
mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
WriteBarrier<JSCell> m_previousOrRareData;
- RefPtr<StringImpl> m_nameInPrevious;
- WriteBarrier<JSCell> m_specificValueInPrevious;
+ RefPtr<UniquedStringImpl> m_nameInPrevious;
const ClassInfo* m_classInfo;
@@ -494,6 +718,8 @@ private:
// Should be accessed through propertyTable(). During GC, it may be set to 0 by another thread.
WriteBarrier<PropertyTable> m_propertyTableUnsafe;
+ WriteBarrier<InferredTypeTable> m_inferredTypeTable;
+
mutable InlineWatchpointSet m_transitionWatchpointSet;
COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits);
@@ -501,22 +727,11 @@ private:
// m_offset does not account for anonymous slots
PropertyOffset m_offset;
- TypeInfo m_typeInfo;
- IndexingType m_indexingType;
uint8_t m_inlineCapacity;
ConcurrentJITLock m_lock;
- unsigned m_dictionaryKind : 2;
- bool m_isPinnedPropertyTable : 1;
- bool m_hasGetterSetterProperties : 1;
- bool m_hasReadOnlyOrGetterSetterPropertiesExcludingProto : 1;
- bool m_hasNonEnumerableProperties : 1;
- unsigned m_attributesInPrevious : 14;
- unsigned m_specificFunctionThrashCount : 2;
- unsigned m_preventExtensions : 1;
- unsigned m_didTransition : 1;
- unsigned m_staticFunctionReified : 1;
+ uint32_t m_bitField;
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StructureChain.cpp b/Source/JavaScriptCore/runtime/StructureChain.cpp
index d18a715c3..9a8568b69 100644
--- a/Source/JavaScriptCore/runtime/StructureChain.cpp
+++ b/Source/JavaScriptCore/runtime/StructureChain.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
@@ -27,13 +27,13 @@
#include "StructureChain.h"
#include "JSObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "Structure.h"
#include <wtf/RefPtr.h>
namespace JSC {
-const ClassInfo StructureChain::s_info = { "StructureChain", 0, 0, 0, CREATE_METHOD_TABLE(StructureChain) };
+const ClassInfo StructureChain::s_info = { "StructureChain", 0, 0, CREATE_METHOD_TABLE(StructureChain) };
StructureChain::StructureChain(VM& vm, Structure* structure)
: JSCell(vm, structure)
@@ -49,7 +49,6 @@ void StructureChain::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
StructureChain* thisObject = jsCast<StructureChain*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
size_t i = 0;
while (thisObject->m_vector[i])
visitor.append(&thisObject->m_vector[i++]);
diff --git a/Source/JavaScriptCore/runtime/StructureChain.h b/Source/JavaScriptCore/runtime/StructureChain.h
index a992d89fe..0fbd1e207 100644
--- a/Source/JavaScriptCore/runtime/StructureChain.h
+++ b/Source/JavaScriptCore/runtime/StructureChain.h
@@ -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
@@ -37,53 +37,56 @@
namespace JSC {
- class LLIntOffsetsExtractor;
- class Structure;
-
- class StructureChain : public JSCell {
- friend class JIT;
-
- public:
- typedef JSCell Base;
-
- static StructureChain* create(VM& vm, Structure* head)
- {
- StructureChain* chain = new (NotNull, allocateCell<StructureChain>(vm.heap)) StructureChain(vm, vm.structureChainStructure.get());
- chain->finishCreation(vm, head);
- return chain;
- }
- WriteBarrier<Structure>* head() { return m_vector.get(); }
- static void visitChildren(JSCell*, SlotVisitor&);
-
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), info()); }
-
- DECLARE_INFO;
-
- static const bool needsDestruction = true;
- static const bool hasImmortalStructure = true;
- static void destroy(JSCell*);
-
- protected:
- void finishCreation(VM& vm, Structure* head)
- {
- Base::finishCreation(vm);
- size_t size = 0;
- for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure())
- ++size;
-
- m_vector = std::make_unique<WriteBarrier<Structure>[]>(size + 1);
-
- size_t i = 0;
- for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure())
- m_vector[i++].set(vm, this, current);
- }
-
- private:
- friend class LLIntOffsetsExtractor;
-
- StructureChain(VM&, Structure*);
- std::unique_ptr<WriteBarrier<Structure>[]> m_vector;
- };
+class LLIntOffsetsExtractor;
+class Structure;
+
+class StructureChain final : public JSCell {
+ friend class JIT;
+
+public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+ static StructureChain* create(VM& vm, Structure* head)
+ {
+ StructureChain* chain = new (NotNull, allocateCell<StructureChain>(vm.heap)) StructureChain(vm, vm.structureChainStructure.get());
+ chain->finishCreation(vm, head);
+ return chain;
+ }
+ WriteBarrier<Structure>* head() { return m_vector.get(); }
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+ }
+
+ DECLARE_INFO;
+
+ static const bool needsDestruction = true;
+ static void destroy(JSCell*);
+
+protected:
+ void finishCreation(VM& vm, Structure* head)
+ {
+ Base::finishCreation(vm);
+ size_t size = 0;
+ for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure())
+ ++size;
+
+ m_vector = std::make_unique<WriteBarrier<Structure>[]>(size + 1);
+
+ size_t i = 0;
+ for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure())
+ m_vector[i++].set(vm, this, current);
+ }
+
+private:
+ friend class LLIntOffsetsExtractor;
+
+ StructureChain(VM&, Structure*);
+ std::unique_ptr<WriteBarrier<Structure>[]> m_vector;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StructureIDBlob.h b/Source/JavaScriptCore/runtime/StructureIDBlob.h
new file mode 100644
index 000000000..0e68c9989
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StructureIDBlob.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014, 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. 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.
+ */
+
+#ifndef StructureIDBlob_h
+#define StructureIDBlob_h
+
+#include "CellState.h"
+#include "IndexingType.h"
+#include "JSTypeInfo.h"
+#include "StructureIDTable.h"
+
+namespace JSC {
+
+class StructureIDBlob {
+ friend class LLIntOffsetsExtractor;
+public:
+ StructureIDBlob()
+ {
+ u.doubleWord = 0xbbadbeef;
+ }
+
+ StructureIDBlob(StructureID structureID, IndexingType indexingType, const TypeInfo& typeInfo)
+ {
+ u.fields.structureID = structureID;
+ u.fields.indexingType = indexingType;
+ u.fields.type = typeInfo.type();
+ u.fields.inlineTypeFlags = typeInfo.inlineTypeFlags();
+ u.fields.defaultCellState = CellState::NewWhite;
+ }
+
+ void operator=(const StructureIDBlob& other) { u.doubleWord = other.u.doubleWord; }
+
+ StructureID structureID() const { return u.fields.structureID; }
+ IndexingType indexingType() const { return u.fields.indexingType; }
+ void setIndexingType(IndexingType indexingType) { u.fields.indexingType = indexingType; }
+ JSType type() const { return u.fields.type; }
+ TypeInfo::InlineTypeFlags inlineTypeFlags() const { return u.fields.inlineTypeFlags; }
+
+ TypeInfo typeInfo(TypeInfo::OutOfLineTypeFlags outOfLineTypeFlags) const { return TypeInfo(type(), inlineTypeFlags(), outOfLineTypeFlags); }
+
+ int32_t blobExcludingStructureID() const { return u.words.word2; }
+ int64_t blob() const { return u.doubleWord; }
+
+ static ptrdiff_t structureIDOffset()
+ {
+ return OBJECT_OFFSETOF(StructureIDBlob, u.fields.structureID);
+ }
+
+ static ptrdiff_t indexingTypeOffset()
+ {
+ return OBJECT_OFFSETOF(StructureIDBlob, u.fields.indexingType);
+ }
+
+private:
+ union {
+ struct {
+ StructureID structureID;
+ IndexingType indexingType;
+ JSType type;
+ TypeInfo::InlineTypeFlags inlineTypeFlags;
+ CellState defaultCellState;
+ } fields;
+ struct {
+ int32_t word1;
+ int32_t word2;
+ } words;
+ int64_t doubleWord;
+ } u;
+};
+
+} // namespace JSC
+
+#endif // StructureIDBlob_h
diff --git a/Source/JavaScriptCore/runtime/StructureIDTable.cpp b/Source/JavaScriptCore/runtime/StructureIDTable.cpp
new file mode 100644
index 000000000..631fc6f62
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StructureIDTable.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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. 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 "StructureIDTable.h"
+
+#include <limits.h>
+#include <wtf/Atomics.h>
+#include <wtf/DataLog.h>
+
+namespace JSC {
+
+StructureIDTable::StructureIDTable()
+ : m_firstFreeOffset(0)
+ , m_table(std::make_unique<StructureOrOffset[]>(s_initialSize))
+ , m_size(0)
+ , m_capacity(s_initialSize)
+{
+ // We pre-allocate the first offset so that the null Structure
+ // can still be represented as the StructureID '0'.
+ allocateID(0);
+}
+
+void StructureIDTable::resize(size_t newCapacity)
+{
+ // Create the new table.
+ auto newTable = std::make_unique<StructureOrOffset[]>(newCapacity);
+
+ // Copy the contents of the old table to the new table.
+ memcpy(newTable.get(), table(), m_capacity * sizeof(StructureOrOffset));
+
+ // Store fence to make sure we've copied everything before doing the swap.
+ WTF::storeStoreFence();
+
+ // Swap the old and new tables.
+ swap(m_table, newTable);
+
+ // Put the old table (now labeled as new) into the list of old tables.
+ m_oldTables.append(WTFMove(newTable));
+
+ // Update the capacity.
+ m_capacity = newCapacity;
+}
+
+void StructureIDTable::flushOldTables()
+{
+ m_oldTables.clear();
+}
+
+StructureID StructureIDTable::allocateID(Structure* structure)
+{
+#if USE(JSVALUE64)
+ if (!m_firstFreeOffset) {
+ RELEASE_ASSERT(m_capacity <= UINT_MAX);
+ if (m_size == m_capacity)
+ resize(m_capacity * 2);
+ ASSERT(m_size < m_capacity);
+
+ StructureOrOffset newEntry;
+ newEntry.structure = structure;
+
+ if (m_size == s_unusedID) {
+ m_size++;
+ return allocateID(structure);
+ }
+
+ StructureID result = m_size;
+ table()[result] = newEntry;
+ m_size++;
+ return result;
+ }
+
+ ASSERT(m_firstFreeOffset != s_unusedID);
+
+ StructureID result = m_firstFreeOffset;
+ m_firstFreeOffset = table()[m_firstFreeOffset].offset;
+ table()[result].structure = structure;
+ return result;
+#else
+ return structure;
+#endif
+}
+
+void StructureIDTable::deallocateID(Structure* structure, StructureID structureID)
+{
+#if USE(JSVALUE64)
+ ASSERT(structureID != s_unusedID);
+ RELEASE_ASSERT(table()[structureID].structure == structure);
+ table()[structureID].offset = m_firstFreeOffset;
+ m_firstFreeOffset = structureID;
+#else
+ UNUSED_PARAM(structure);
+ UNUSED_PARAM(structureID);
+#endif
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StructureIDTable.h b/Source/JavaScriptCore/runtime/StructureIDTable.h
new file mode 100644
index 000000000..630333f0c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StructureIDTable.h
@@ -0,0 +1,94 @@
+/*
+ * 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. 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.
+ */
+
+#ifndef StructureIDTable_h
+#define StructureIDTable_h
+
+#include "UnusedPointer.h"
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+class Structure;
+
+#if USE(JSVALUE64)
+typedef uint32_t StructureID;
+#else
+typedef Structure* StructureID;
+#endif
+
+class StructureIDTable {
+ friend class LLIntOffsetsExtractor;
+public:
+ StructureIDTable();
+
+ void** base() { return reinterpret_cast<void**>(&m_table); }
+
+ Structure* get(StructureID);
+ void deallocateID(Structure*, StructureID);
+ StructureID allocateID(Structure*);
+
+ void flushOldTables();
+
+private:
+ void resize(size_t newCapacity);
+
+ union StructureOrOffset {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ Structure* structure;
+ StructureID offset;
+ };
+
+ StructureOrOffset* table() const { return m_table.get(); }
+
+ static const size_t s_initialSize = 256;
+
+ Vector<std::unique_ptr<StructureOrOffset[]>> m_oldTables;
+
+ uint32_t m_firstFreeOffset;
+ std::unique_ptr<StructureOrOffset[]> m_table;
+
+ size_t m_size;
+ size_t m_capacity;
+
+#if USE(JSVALUE64)
+ static const StructureID s_unusedID = unusedPointer;
+#endif
+};
+
+inline Structure* StructureIDTable::get(StructureID structureID)
+{
+#if USE(JSVALUE64)
+ ASSERT_WITH_SECURITY_IMPLICATION(structureID && structureID < m_capacity);
+ return table()[structureID].structure;
+#else
+ return structureID;
+#endif
+}
+
+} // namespace JSC
+
+#endif // StructureIDTable_h
diff --git a/Source/JavaScriptCore/runtime/StructureInlines.h b/Source/JavaScriptCore/runtime/StructureInlines.h
index 5895ecb20..21bcaa517 100644
--- a/Source/JavaScriptCore/runtime/StructureInlines.h
+++ b/Source/JavaScriptCore/runtime/StructureInlines.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-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
@@ -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
@@ -27,8 +27,11 @@
#define StructureInlines_h
#include "JSArrayBufferView.h"
+#include "JSCJSValueInlines.h"
+#include "JSGlobalObject.h"
#include "PropertyMapHashTable.h"
#include "Structure.h"
+#include "StructureChain.h"
namespace JSC {
@@ -49,10 +52,10 @@ inline Structure* Structure::createStructure(VM& vm)
return structure;
}
-inline Structure* Structure::create(VM& vm, const Structure* structure)
+inline Structure* Structure::create(VM& vm, Structure* structure, DeferredStructureTransitionWatchpointFire* deferred)
{
ASSERT(vm.structureStructure);
- Structure* newStructure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, structure);
+ Structure* newStructure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, structure, deferred);
newStructure->finishCreation(vm);
return newStructure;
}
@@ -61,7 +64,7 @@ inline JSObject* Structure::storedPrototypeObject() const
{
JSValue value = m_prototype.get();
if (value.isNull())
- return 0;
+ return nullptr;
return asObject(value);
}
@@ -69,42 +72,75 @@ inline Structure* Structure::storedPrototypeStructure() const
{
JSObject* object = storedPrototypeObject();
if (!object)
- return 0;
+ return nullptr;
return object->structure();
}
-inline PropertyOffset Structure::get(VM& vm, PropertyName propertyName)
+ALWAYS_INLINE PropertyOffset Structure::get(VM& vm, PropertyName propertyName)
{
- ASSERT(!isCompilationThread());
- ASSERT(structure()->classInfo() == info());
- DeferGC deferGC(vm.heap);
- materializePropertyMapIfNecessary(vm, deferGC);
- if (!propertyTable())
- return invalidOffset;
-
- PropertyMapEntry* entry = propertyTable()->find(propertyName.uid()).first;
- return entry ? entry->offset : invalidOffset;
+ unsigned attributes;
+ bool hasInferredType;
+ return get(vm, propertyName, attributes, hasInferredType);
+}
+
+ALWAYS_INLINE PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attributes)
+{
+ bool hasInferredType;
+ return get(vm, propertyName, attributes, hasInferredType);
}
-inline PropertyOffset Structure::get(VM& vm, const WTF::String& name)
+ALWAYS_INLINE PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attributes, bool& hasInferredType)
{
ASSERT(!isCompilationThread());
ASSERT(structure()->classInfo() == info());
- DeferGC deferGC(vm.heap);
- materializePropertyMapIfNecessary(vm, deferGC);
- if (!propertyTable())
+
+ PropertyTable* propertyTable;
+ materializePropertyMapIfNecessary(vm, propertyTable);
+ if (!propertyTable)
return invalidOffset;
- PropertyMapEntry* entry = propertyTable()->findWithString(name.impl()).first;
- return entry ? entry->offset : invalidOffset;
+ PropertyMapEntry* entry = propertyTable->get(propertyName.uid());
+ if (!entry)
+ return invalidOffset;
+
+ attributes = entry->attributes;
+ hasInferredType = entry->hasInferredType;
+ return entry->offset;
}
+
+template<typename Functor>
+void Structure::forEachPropertyConcurrently(const Functor& functor)
+{
+ Vector<Structure*, 8> structures;
+ Structure* structure;
+ PropertyTable* table;
+
+ findStructuresAndMapForMaterialization(structures, structure, table);
-inline PropertyOffset Structure::getConcurrently(VM& vm, StringImpl* uid)
+ if (table) {
+ for (auto& entry : *table) {
+ if (!functor(entry)) {
+ structure->m_lock.unlock();
+ return;
+ }
+ }
+ structure->m_lock.unlock();
+ }
+
+ for (unsigned i = structures.size(); i--;) {
+ structure = structures[i];
+ if (!structure->m_nameInPrevious)
+ continue;
+
+ if (!functor(PropertyMapEntry(structure->m_nameInPrevious.get(), structure->m_offset, structure->attributesInPrevious())))
+ return;
+ }
+}
+
+inline PropertyOffset Structure::getConcurrently(UniquedStringImpl* uid)
{
unsigned attributesIgnored;
- JSCell* specificValueIgnored;
- return getConcurrently(
- vm, uid, attributesIgnored, specificValueIgnored);
+ return getConcurrently(uid, attributesIgnored);
}
inline bool Structure::hasIndexingHeader(const JSCell* cell) const
@@ -132,25 +168,12 @@ inline bool Structure::transitivelyTransitionedFrom(Structure* structureToFind)
return false;
}
-inline void Structure::setEnumerationCache(VM& vm, JSPropertyNameIterator* enumerationCache)
-{
- ASSERT(!isDictionary());
- if (!typeInfo().structureHasRareData())
- allocateRareData(vm);
- rareData()->setEnumerationCache(vm, this, enumerationCache);
-}
-
-inline JSPropertyNameIterator* Structure::enumerationCache()
-{
- if (!typeInfo().structureHasRareData())
- return 0;
- return rareData()->enumerationCache();
-}
-
inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject) const
{
if (isObject())
return m_prototype.get();
+ if (typeInfo().type() == SymbolType)
+ return globalObject->symbolPrototype();
ASSERT(typeInfo().type() == StringType);
return globalObject->stringPrototype();
@@ -223,12 +246,37 @@ ALWAYS_INLINE WriteBarrier<PropertyTable>& Structure::propertyTable()
return m_propertyTableUnsafe;
}
+inline void Structure::didReplaceProperty(PropertyOffset offset)
+{
+ if (LIKELY(!hasRareData()))
+ return;
+ StructureRareData::PropertyWatchpointMap* map = rareData()->m_replacementWatchpointSets.get();
+ if (LIKELY(!map))
+ return;
+ WatchpointSet* set = map->get(offset);
+ if (LIKELY(!set))
+ return;
+ set->fireAll("Property did get replaced");
+}
+
+inline WatchpointSet* Structure::propertyReplacementWatchpointSet(PropertyOffset offset)
+{
+ ConcurrentJITLocker locker(m_lock);
+ if (!hasRareData())
+ return nullptr;
+ WTF::loadLoadFence();
+ StructureRareData::PropertyWatchpointMap* map = rareData()->m_replacementWatchpointSets.get();
+ if (!map)
+ return nullptr;
+ return map->get(offset);
+}
+
ALWAYS_INLINE bool Structure::checkOffsetConsistency() const
{
PropertyTable* propertyTable = m_propertyTableUnsafe.get();
if (!propertyTable) {
- ASSERT(!m_isPinnedPropertyTable);
+ ASSERT(!isPinnedPropertyTable());
return true;
}
@@ -246,6 +294,25 @@ ALWAYS_INLINE bool Structure::checkOffsetConsistency() const
return true;
}
+inline size_t nextOutOfLineStorageCapacity(size_t currentCapacity)
+{
+ if (!currentCapacity)
+ return initialOutOfLineCapacity;
+ return currentCapacity * outOfLineGrowthFactor;
+}
+
+inline size_t Structure::suggestedNewOutOfLineStorageCapacity()
+{
+ return nextOutOfLineStorageCapacity(outOfLineCapacity());
+}
+
+inline void Structure::setObjectToStringValue(ExecState* exec, VM& vm, JSString* value, PropertySlot toStringTagSymbolSlot)
+{
+ if (!hasRareData())
+ allocateRareData(vm);
+ rareData()->setObjectToStringValue(exec, vm, this, value, toStringTagSymbolSlot);
+}
+
} // namespace JSC
#endif // StructureInlines_h
diff --git a/Source/JavaScriptCore/runtime/StructureRareData.cpp b/Source/JavaScriptCore/runtime/StructureRareData.cpp
index 9e7265178..add963ce4 100644
--- a/Source/JavaScriptCore/runtime/StructureRareData.cpp
+++ b/Source/JavaScriptCore/runtime/StructureRareData.cpp
@@ -26,17 +26,19 @@
#include "config.h"
#include "StructureRareData.h"
-#include "JSPropertyNameIterator.h"
+#include "AdaptiveInferredPropertyValueWatchpointBase.h"
+#include "JSPropertyNameEnumerator.h"
#include "JSString.h"
-#include "Operations.h"
+#include "JSCInlines.h"
+#include "ObjectPropertyConditionSet.h"
namespace JSC {
-const ClassInfo StructureRareData::s_info = { "StructureRareData", 0, 0, 0, CREATE_METHOD_TABLE(StructureRareData) };
+const ClassInfo StructureRareData::s_info = { "StructureRareData", 0, 0, CREATE_METHOD_TABLE(StructureRareData) };
Structure* StructureRareData::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), info());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
}
StructureRareData* StructureRareData::create(VM& vm, Structure* previous)
@@ -46,39 +48,178 @@ StructureRareData* StructureRareData::create(VM& vm, Structure* previous)
return rareData;
}
-StructureRareData* StructureRareData::clone(VM& vm, const StructureRareData* other)
+void StructureRareData::destroy(JSCell* cell)
{
- StructureRareData* newRareData = new (NotNull, allocateCell<StructureRareData>(vm.heap)) StructureRareData(vm, other);
- newRareData->finishCreation(vm);
- return newRareData;
+ static_cast<StructureRareData*>(cell)->StructureRareData::~StructureRareData();
}
StructureRareData::StructureRareData(VM& vm, Structure* previous)
: JSCell(vm, vm.structureRareDataStructure.get())
+ , m_giveUpOnObjectToStringValueCache(false)
{
if (previous)
m_previous.set(vm, this, previous);
}
-StructureRareData::StructureRareData(VM& vm, const StructureRareData* other)
- : JSCell(vm, other->structure())
-{
- if (other->previousID())
- m_previous.set(vm, this, other->previousID());
- if (other->objectToStringValue())
- m_objectToStringValue.set(vm, this, other->objectToStringValue());
-}
-
void StructureRareData::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
StructureRareData* thisObject = jsCast<StructureRareData*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
JSCell::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_previous);
visitor.append(&thisObject->m_objectToStringValue);
- visitor.append(&thisObject->m_enumerationCache);
+ visitor.append(&thisObject->m_cachedPropertyNameEnumerator);
+}
+
+JSPropertyNameEnumerator* StructureRareData::cachedPropertyNameEnumerator() const
+{
+ return m_cachedPropertyNameEnumerator.get();
+}
+
+void StructureRareData::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
+{
+ m_cachedPropertyNameEnumerator.set(vm, this, enumerator);
+}
+
+// ----------- Object.prototype.toString() helper watchpoint classes -----------
+
+class ObjectToStringAdaptiveInferredPropertyValueWatchpoint : public AdaptiveInferredPropertyValueWatchpointBase {
+public:
+ typedef AdaptiveInferredPropertyValueWatchpointBase Base;
+ ObjectToStringAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition&, StructureRareData*);
+
+private:
+ virtual void handleFire(const FireDetail&) override;
+
+ StructureRareData* m_structureRareData;
+};
+
+class ObjectToStringAdaptiveStructureWatchpoint : public Watchpoint {
+public:
+ ObjectToStringAdaptiveStructureWatchpoint(const ObjectPropertyCondition&, StructureRareData*);
+
+ void install();
+
+protected:
+ virtual void fireInternal(const FireDetail&) override;
+
+private:
+ ObjectPropertyCondition m_key;
+ StructureRareData* m_structureRareData;
+};
+
+void StructureRareData::setObjectToStringValue(ExecState* exec, VM& vm, Structure* ownStructure, JSString* value, PropertySlot toStringTagSymbolSlot)
+{
+ if (m_giveUpOnObjectToStringValueCache)
+ return;
+
+ ObjectPropertyConditionSet conditionSet;
+ if (toStringTagSymbolSlot.isValue()) {
+ // We don't handle the own property case of Symbol.toStringTag because we would never know if a new
+ // object transitioning to the same structure had the same value stored in Symbol.toStringTag.
+ // Additionally, this is a super unlikely case anyway.
+ if (!toStringTagSymbolSlot.isCacheable() || toStringTagSymbolSlot.slotBase()->structure(vm) == ownStructure)
+ return;
+
+
+ // This will not create a condition for the current structure but that is good because we know the Symbol.toStringTag
+ // is not on the ownStructure so we will transisition if one is added and this cache will no longer be used.
+ conditionSet = generateConditionsForPrototypePropertyHit(vm, this, exec, ownStructure, toStringTagSymbolSlot.slotBase(), vm.propertyNames->toStringTagSymbol.impl());
+ ASSERT(conditionSet.hasOneSlotBaseCondition());
+ } else if (toStringTagSymbolSlot.isUnset())
+ conditionSet = generateConditionsForPropertyMiss(vm, this, exec, ownStructure, vm.propertyNames->toStringTagSymbol.impl());
+ else
+ return;
+
+ if (!conditionSet.isValid()) {
+ m_giveUpOnObjectToStringValueCache = true;
+ return;
+ }
+
+ ObjectPropertyCondition equivCondition;
+ for (const ObjectPropertyCondition& condition : conditionSet) {
+ if (condition.condition().kind() == PropertyCondition::Presence) {
+ ASSERT(isValidOffset(condition.offset()));
+ condition.object()->structure(vm)->startWatchingPropertyForReplacements(vm, condition.offset());
+ equivCondition = condition.attemptToMakeEquivalenceWithoutBarrier();
+
+ // The equivalence condition won't be watchable if we have already seen a replacement.
+ if (!equivCondition.isWatchable()) {
+ m_giveUpOnObjectToStringValueCache = true;
+ return;
+ }
+ } else if (!condition.isWatchable()) {
+ m_giveUpOnObjectToStringValueCache = true;
+ return;
+ }
+ }
+
+ ASSERT(conditionSet.structuresEnsureValidity());
+ for (ObjectPropertyCondition condition : conditionSet) {
+ if (condition.condition().kind() == PropertyCondition::Presence) {
+ m_objectToStringAdaptiveInferredValueWatchpoint = std::make_unique<ObjectToStringAdaptiveInferredPropertyValueWatchpoint>(equivCondition, this);
+ m_objectToStringAdaptiveInferredValueWatchpoint->install();
+ } else
+ m_objectToStringAdaptiveWatchpointSet.add(condition, this)->install();
+ }
+
+ m_objectToStringValue.set(vm, this, value);
+}
+
+inline void StructureRareData::clearObjectToStringValue()
+{
+ m_objectToStringAdaptiveWatchpointSet.clear();
+ m_objectToStringAdaptiveInferredValueWatchpoint.reset();
+ m_objectToStringValue.clear();
+}
+
+// ------------- Methods for Object.prototype.toString() helper watchpoint classes --------------
+
+ObjectToStringAdaptiveStructureWatchpoint::ObjectToStringAdaptiveStructureWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData)
+ : m_key(key)
+ , m_structureRareData(structureRareData)
+{
+ RELEASE_ASSERT(key.watchingRequiresStructureTransitionWatchpoint());
+ RELEASE_ASSERT(!key.watchingRequiresReplacementWatchpoint());
+}
+
+void ObjectToStringAdaptiveStructureWatchpoint::install()
+{
+ RELEASE_ASSERT(m_key.isWatchable());
+
+ m_key.object()->structure()->addTransitionWatchpoint(this);
+}
+
+void ObjectToStringAdaptiveStructureWatchpoint::fireInternal(const FireDetail& detail)
+{
+ if (m_key.isWatchable(PropertyCondition::EnsureWatchability)) {
+ install();
+ return;
+ }
+
+ StringPrintStream out;
+ out.print("ObjectToStringValue Adaptation of ", m_key, " failed: ", detail);
+
+ StringFireDetail stringDetail(out.toCString().data());
+
+ m_structureRareData->clearObjectToStringValue();
+}
+
+ObjectToStringAdaptiveInferredPropertyValueWatchpoint::ObjectToStringAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData)
+ : Base(key)
+ , m_structureRareData(structureRareData)
+{
+}
+
+void ObjectToStringAdaptiveInferredPropertyValueWatchpoint::handleFire(const FireDetail& detail)
+{
+ StringPrintStream out;
+ out.print("Adaptation of ", key(), " failed: ", detail);
+
+ StringFireDetail stringDetail(out.toCString().data());
+
+ m_structureRareData->clearObjectToStringValue();
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StructureRareData.h b/Source/JavaScriptCore/runtime/StructureRareData.h
index c6798823d..0310b18c3 100644
--- a/Source/JavaScriptCore/runtime/StructureRareData.h
+++ b/Source/JavaScriptCore/runtime/StructureRareData.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * 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
@@ -29,46 +29,60 @@
#include "ClassInfo.h"
#include "JSCell.h"
#include "JSTypeInfo.h"
+#include "PropertyOffset.h"
+#include "PropertySlot.h"
namespace JSC {
-class JSPropertyNameIterator;
+class JSPropertyNameEnumerator;
class Structure;
+class ObjectToStringAdaptiveStructureWatchpoint;
+class ObjectToStringAdaptiveInferredPropertyValueWatchpoint;
-class StructureRareData : public JSCell {
- friend class Structure;
+class StructureRareData final : public JSCell {
public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
static StructureRareData* create(VM&, Structure*);
- static StructureRareData* clone(VM&, const StructureRareData* other);
+
+ static const bool needsDestruction = true;
+ static void destroy(JSCell*);
static void visitChildren(JSCell*, SlotVisitor&);
static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
- // Returns true if this StructureRareData should also be cloned when cloning the owner Structure.
- bool needsCloning() const { return false; }
-
Structure* previousID() const;
- void setPreviousID(VM&, Structure* transition, Structure*);
+ void setPreviousID(VM&, Structure*);
void clearPreviousID();
JSString* objectToStringValue() const;
- void setObjectToStringValue(VM&, const JSCell* owner, JSString* value);
+ void setObjectToStringValue(ExecState*, VM&, Structure* baseStructure, JSString* value, PropertySlot toStringTagSymbolSlot);
- JSPropertyNameIterator* enumerationCache();
- void setEnumerationCache(VM&, const Structure* owner, JSPropertyNameIterator* value);
+ JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
+ void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
DECLARE_EXPORT_INFO;
private:
- StructureRareData(VM&, Structure*);
- StructureRareData(VM&, const StructureRareData*);
+ friend class Structure;
+ friend class ObjectToStringAdaptiveStructureWatchpoint;
+ friend class ObjectToStringAdaptiveInferredPropertyValueWatchpoint;
- static const unsigned StructureFlags = OverridesVisitChildren | JSCell::StructureFlags;
+ void clearObjectToStringValue();
+
+ StructureRareData(VM&, Structure*);
WriteBarrier<Structure> m_previous;
WriteBarrier<JSString> m_objectToStringValue;
- WriteBarrier<JSPropertyNameIterator> m_enumerationCache;
+ WriteBarrier<JSPropertyNameEnumerator> m_cachedPropertyNameEnumerator;
+
+ typedef HashMap<PropertyOffset, RefPtr<WatchpointSet>, WTF::IntHash<PropertyOffset>, WTF::UnsignedWithZeroKeyHashTraits<PropertyOffset>> PropertyWatchpointMap;
+ std::unique_ptr<PropertyWatchpointMap> m_replacementWatchpointSets;
+ Bag<ObjectToStringAdaptiveStructureWatchpoint> m_objectToStringAdaptiveWatchpointSet;
+ std::unique_ptr<ObjectToStringAdaptiveInferredPropertyValueWatchpoint> m_objectToStringAdaptiveInferredValueWatchpoint;
+ bool m_giveUpOnObjectToStringValueCache;
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StructureRareDataInlines.h b/Source/JavaScriptCore/runtime/StructureRareDataInlines.h
index 5b39bad1f..b2ed53dcf 100644
--- a/Source/JavaScriptCore/runtime/StructureRareDataInlines.h
+++ b/Source/JavaScriptCore/runtime/StructureRareDataInlines.h
@@ -26,6 +26,7 @@
#ifndef StructureRareDataInlines_h
#define StructureRareDataInlines_h
+#include "JSString.h"
#include "StructureRareData.h"
namespace JSC {
@@ -35,7 +36,7 @@ inline Structure* StructureRareData::previousID() const
return m_previous.get();
}
-inline void StructureRareData::setPreviousID(VM& vm, Structure*, Structure* structure)
+inline void StructureRareData::setPreviousID(VM& vm, Structure* structure)
{
m_previous.set(vm, this, structure);
}
@@ -50,11 +51,6 @@ inline JSString* StructureRareData::objectToStringValue() const
return m_objectToStringValue.get();
}
-inline void StructureRareData::setObjectToStringValue(VM& vm, const JSCell*, JSString* value)
-{
- m_objectToStringValue.set(vm, this, value);
-}
-
} // namespace JSC
#endif // StructureRareDataInlines_h
diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
index d66202364..17690a3da 100644
--- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h
+++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
@@ -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
@@ -29,8 +29,7 @@
#include "IndexingType.h"
#include "WeakGCMap.h"
#include <wtf/HashFunctions.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/text/StringImpl.h>
+#include <wtf/text/UniquedStringImpl.h>
namespace JSC {
@@ -79,7 +78,7 @@ inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition
ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType) || hasContiguous(oldType));
return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape;
case SwitchToSlowPutArrayStorage:
- ASSERT(hasFastArrayStorage(oldType));
+ ASSERT(hasArrayStorage(oldType));
return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape;
case AddIndexedAccessors:
return oldType | MayHaveIndexedAccessors;
@@ -94,11 +93,11 @@ class StructureTransitionTable {
struct Hash {
- typedef std::pair<StringImpl*, unsigned> Key;
+ typedef std::pair<UniquedStringImpl*, unsigned> Key;
static unsigned hash(const Key& p)
{
- return PtrHash<StringImpl*>::hash(p.first) + p.second;
+ return PtrHash<UniquedStringImpl*>::hash(p.first) + p.second;
}
static bool equal(const Key& a, const Key& b)
@@ -130,11 +129,13 @@ public:
WeakSet::deallocate(impl);
}
- inline void add(VM&, Structure*);
- inline bool contains(StringImpl* rep, unsigned attributes) const;
- inline Structure* get(StringImpl* rep, unsigned attributes) const;
+ void add(VM&, Structure*);
+ bool contains(UniquedStringImpl*, unsigned attributes) const;
+ Structure* get(UniquedStringImpl*, unsigned attributes) const;
private:
+ friend class SingleSlotTransitionWeakOwner;
+
bool isUsingSingleSlot() const
{
return m_data & UsingSingleSlotFlag;
@@ -165,24 +166,8 @@ private:
ASSERT(!isUsingSingleSlot());
}
- Structure* singleTransition() const
- {
- ASSERT(isUsingSingleSlot());
- if (WeakImpl* impl = this->weakImpl()) {
- if (impl->state() == WeakImpl::Live)
- return reinterpret_cast<Structure*>(impl->jsValue().asCell());
- }
- return 0;
- }
-
- void setSingleTransition(VM&, Structure* structure)
- {
- ASSERT(isUsingSingleSlot());
- if (WeakImpl* impl = this->weakImpl())
- WeakSet::deallocate(impl);
- WeakImpl* impl = WeakSet::allocate(reinterpret_cast<JSCell*>(structure));
- m_data = reinterpret_cast<intptr_t>(impl) | UsingSingleSlotFlag;
- }
+ Structure* singleTransition() const;
+ void setSingleTransition(Structure*);
intptr_t m_data;
};
diff --git a/Source/JavaScriptCore/runtime/Symbol.cpp b/Source/JavaScriptCore/runtime/Symbol.cpp
new file mode 100644
index 000000000..a765609ea
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Symbol.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 "Symbol.h"
+
+#include "Error.h"
+#include "JSCInlines.h"
+#include "SymbolObject.h"
+
+namespace JSC {
+
+const ClassInfo Symbol::s_info = { "symbol", nullptr, nullptr, CREATE_METHOD_TABLE(Symbol) };
+
+Symbol::Symbol(VM& vm)
+ : Base(vm, vm.symbolStructure.get())
+ , m_privateName()
+{
+}
+
+Symbol::Symbol(VM& vm, const String& string)
+ : Base(vm, vm.symbolStructure.get())
+ , m_privateName(PrivateName::Description, string)
+{
+}
+
+Symbol::Symbol(VM& vm, SymbolImpl& uid)
+ : Base(vm, vm.symbolStructure.get())
+ , m_privateName(uid)
+{
+}
+
+inline SymbolObject* SymbolObject::create(VM& vm, JSGlobalObject* globalObject, Symbol* symbol)
+{
+ SymbolObject* object = new (NotNull, allocateCell<SymbolObject>(vm.heap)) SymbolObject(vm, globalObject->symbolObjectStructure());
+ object->finishCreation(vm, symbol);
+ return object;
+}
+
+JSValue Symbol::toPrimitive(ExecState*, PreferredPrimitiveType) const
+{
+ return const_cast<Symbol*>(this);
+}
+
+bool Symbol::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const
+{
+ result = this;
+ number = toNumber(exec);
+ return true;
+}
+
+JSObject* Symbol::toObject(ExecState* exec, JSGlobalObject* globalObject) const
+{
+ return SymbolObject::create(exec->vm(), globalObject, const_cast<Symbol*>(this));
+}
+
+double Symbol::toNumber(ExecState* exec) const
+{
+ throwTypeError(exec);
+ return 0.0;
+}
+
+void Symbol::destroy(JSCell* cell)
+{
+ static_cast<Symbol*>(cell)->Symbol::~Symbol();
+}
+
+String Symbol::descriptiveString() const
+{
+ return makeString("Symbol(", String(privateName().uid()), ')');
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Symbol.h b/Source/JavaScriptCore/runtime/Symbol.h
new file mode 100644
index 000000000..cfdabe694
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Symbol.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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.
+ */
+
+#ifndef Symbol_h
+#define Symbol_h
+
+#include "JSCell.h"
+#include "JSString.h"
+#include "PrivateName.h"
+
+namespace JSC {
+
+class Symbol final : public JSCell {
+public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+ DECLARE_EXPORT_INFO;
+
+ static const bool needsDestruction = true;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(SymbolType, StructureFlags), info());
+ }
+
+ static Symbol* create(VM& vm)
+ {
+ Symbol* symbol = new (NotNull, allocateCell<Symbol>(vm.heap)) Symbol(vm);
+ symbol->finishCreation(vm);
+ return symbol;
+ }
+
+ static Symbol* create(ExecState* exec, JSString* description)
+ {
+ VM& vm = exec->vm();
+ String desc = description->value(exec);
+ Symbol* symbol = new (NotNull, allocateCell<Symbol>(vm.heap)) Symbol(vm, desc);
+ symbol->finishCreation(vm);
+ return symbol;
+ }
+
+ static Symbol* create(VM& vm, SymbolImpl& uid)
+ {
+ Symbol* symbol = new (NotNull, allocateCell<Symbol>(vm.heap)) Symbol(vm, uid);
+ symbol->finishCreation(vm);
+ return symbol;
+ }
+
+ const PrivateName& privateName() const { return m_privateName; }
+ String descriptiveString() const;
+
+ JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
+ bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
+ JSObject* toObject(ExecState*, JSGlobalObject*) const;
+ double toNumber(ExecState*) const;
+
+ static size_t offsetOfPrivateName() { return OBJECT_OFFSETOF(Symbol, m_privateName); }
+
+protected:
+ static void destroy(JSCell*);
+
+ Symbol(VM&);
+ Symbol(VM&, const String&);
+ Symbol(VM&, SymbolImpl& uid);
+
+ void finishCreation(VM& vm)
+ {
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+ }
+
+ PrivateName m_privateName;
+};
+
+Symbol* asSymbol(JSValue);
+
+inline Symbol* asSymbol(JSValue value)
+{
+ ASSERT(value.asCell()->isSymbol());
+ return jsCast<Symbol*>(value.asCell());
+}
+
+} // namespace JSC
+
+#endif // Symbol_h
diff --git a/Source/JavaScriptCore/runtime/SymbolConstructor.cpp b/Source/JavaScriptCore/runtime/SymbolConstructor.cpp
new file mode 100644
index 000000000..753ce60ee
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/SymbolConstructor.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 "SymbolConstructor.h"
+
+#include "Error.h"
+#include "JSCInlines.h"
+#include "JSGlobalObject.h"
+#include "Symbol.h"
+#include "SymbolPrototype.h"
+#include <wtf/text/SymbolRegistry.h>
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL symbolConstructorFor(ExecState*);
+static EncodedJSValue JSC_HOST_CALL symbolConstructorKeyFor(ExecState*);
+
+}
+
+#include "SymbolConstructor.lut.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(SymbolConstructor);
+
+const ClassInfo SymbolConstructor::s_info = { "Function", &Base::s_info, &symbolConstructorTable, CREATE_METHOD_TABLE(SymbolConstructor) };
+
+/* Source for SymbolConstructor.lut.h
+@begin symbolConstructorTable
+ for symbolConstructorFor DontEnum|Function 1
+ keyFor symbolConstructorKeyFor DontEnum|Function 1
+@end
+*/
+
+SymbolConstructor::SymbolConstructor(VM& vm, Structure* structure)
+ : InternalFunction(vm, structure)
+{
+}
+
+#define INITIALIZE_WELL_KNOWN_SYMBOLS(name) \
+ putDirectWithoutTransition(vm, Identifier::fromString(&vm, #name), Symbol::create(vm, static_cast<SymbolImpl&>(*vm.propertyNames->name##Symbol.impl())), DontEnum | DontDelete | ReadOnly);
+
+void SymbolConstructor::finishCreation(VM& vm, SymbolPrototype* prototype)
+{
+ Base::finishCreation(vm, prototype->classInfo()->className);
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
+
+ JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALIZE_WELL_KNOWN_SYMBOLS)
+}
+
+bool SymbolConstructor::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<Base>(exec, symbolConstructorTable, jsCast<SymbolConstructor*>(object), propertyName, slot);
+}
+
+// ------------------------------ Functions ---------------------------
+
+static EncodedJSValue JSC_HOST_CALL callSymbol(ExecState* exec)
+{
+ JSValue description = exec->argument(0);
+ if (description.isUndefined())
+ return JSValue::encode(Symbol::create(exec->vm()));
+ return JSValue::encode(Symbol::create(exec, description.toString(exec)));
+}
+
+ConstructType SymbolConstructor::getConstructData(JSCell*, ConstructData&)
+{
+ return ConstructTypeNone;
+}
+
+CallType SymbolConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callSymbol;
+ return CallTypeHost;
+}
+
+EncodedJSValue JSC_HOST_CALL symbolConstructorFor(ExecState* exec)
+{
+ JSString* stringKey = exec->argument(0).toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ String string = stringKey->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ return JSValue::encode(Symbol::create(exec->vm(), exec->vm().symbolRegistry().symbolForKey(string)));
+}
+
+EncodedJSValue JSC_HOST_CALL symbolConstructorKeyFor(ExecState* exec)
+{
+ JSValue symbolValue = exec->argument(0);
+ if (!symbolValue.isSymbol())
+ return JSValue::encode(throwTypeError(exec));
+
+ SymbolImpl* uid = asSymbol(symbolValue)->privateName().uid();
+ if (!uid->symbolRegistry())
+ return JSValue::encode(jsUndefined());
+
+ ASSERT(uid->symbolRegistry() == &exec->vm().symbolRegistry());
+ return JSValue::encode(jsString(exec, exec->vm().symbolRegistry().keyForSymbol(*uid)));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NameConstructor.h b/Source/JavaScriptCore/runtime/SymbolConstructor.h
index 8e20f28fc..73aec085c 100644
--- a/Source/JavaScriptCore/runtime/NameConstructor.h
+++ b/Source/JavaScriptCore/runtime/SymbolConstructor.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,43 +24,46 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef NameConstructor_h
-#define NameConstructor_h
+#ifndef SymbolConstructor_h
+#define SymbolConstructor_h
#include "InternalFunction.h"
-#include "NameInstance.h"
+#include "Symbol.h"
namespace JSC {
-class NamePrototype;
+class SymbolPrototype;
+class GetterSetter;
-class NameConstructor : public InternalFunction {
+class SymbolConstructor : public InternalFunction {
public:
typedef InternalFunction Base;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | Base::StructureFlags;
- static NameConstructor* create(VM& vm, Structure* structure, NamePrototype* prototype)
+ static SymbolConstructor* create(VM& vm, Structure* structure, SymbolPrototype* prototype, GetterSetter*)
{
- NameConstructor* constructor = new (NotNull, allocateCell<NameConstructor>(vm.heap)) NameConstructor(vm, structure);
+ SymbolConstructor* constructor = new (NotNull, allocateCell<SymbolConstructor>(vm.heap)) SymbolConstructor(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());
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}
protected:
- void finishCreation(VM&, NamePrototype*);
-
+ void finishCreation(VM&, SymbolPrototype*);
+
private:
- NameConstructor(VM&, Structure*);
+ SymbolConstructor(VM&, Structure*);
static ConstructType getConstructData(JSCell*, ConstructData&);
static CallType getCallData(JSCell*, CallData&);
+ static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
};
} // namespace JSC
-#endif // NameConstructor_h
+#endif // SymbolConstructor_h
diff --git a/Source/JavaScriptCore/runtime/SymbolObject.cpp b/Source/JavaScriptCore/runtime/SymbolObject.cpp
new file mode 100644
index 000000000..9ab7a7ecb
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/SymbolObject.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 "SymbolObject.h"
+
+#include "JSCInlines.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(SymbolObject);
+
+const ClassInfo SymbolObject::s_info = { "Symbol", &JSWrapperObject::s_info, nullptr, CREATE_METHOD_TABLE(SymbolObject) };
+
+SymbolObject::SymbolObject(VM& vm, Structure* structure)
+ : JSWrapperObject(vm, structure)
+{
+}
+
+void SymbolObject::finishCreation(VM& vm, Symbol* symbol)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+ setInternalValue(vm, symbol);
+}
+
+JSValue SymbolObject::defaultValue(const JSObject* object, ExecState*, PreferredPrimitiveType)
+{
+ const SymbolObject* symbolObject = jsCast<const SymbolObject*>(object);
+ return symbolObject->internalValue();
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/SymbolObject.h b/Source/JavaScriptCore/runtime/SymbolObject.h
new file mode 100644
index 000000000..46a049170
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/SymbolObject.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef SymbolObject_h
+#define SymbolObject_h
+
+#include "JSWrapperObject.h"
+#include "Symbol.h"
+
+namespace JSC {
+
+class SymbolObject : public JSWrapperObject {
+public:
+ typedef JSWrapperObject Base;
+
+ static SymbolObject* create(VM& vm, Structure* structure)
+ {
+ Symbol* symbol = Symbol::create(vm);
+ SymbolObject* object = new (NotNull, allocateCell<SymbolObject>(vm.heap)) SymbolObject(vm, structure);
+ object->finishCreation(vm, symbol);
+ return object;
+ }
+ static SymbolObject* create(VM& vm, Structure* structure, Symbol* symbol)
+ {
+ SymbolObject* object = new (NotNull, allocateCell<SymbolObject>(vm.heap)) SymbolObject(vm, structure);
+ object->finishCreation(vm, symbol);
+ return object;
+ }
+ static SymbolObject* create(VM&, JSGlobalObject*, Symbol*);
+
+ DECLARE_EXPORT_INFO;
+
+ Symbol* internalValue() const { return asSymbol(JSWrapperObject::internalValue());}
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
+
+protected:
+ JS_EXPORT_PRIVATE void finishCreation(VM&, Symbol*);
+ JS_EXPORT_PRIVATE SymbolObject(VM&, Structure*);
+};
+
+} // namespace JSC
+
+#endif // SymbolObject_h
diff --git a/Source/JavaScriptCore/runtime/SymbolPrototype.cpp b/Source/JavaScriptCore/runtime/SymbolPrototype.cpp
new file mode 100644
index 000000000..c15725f07
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/SymbolPrototype.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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 "SymbolPrototype.h"
+
+#include "Error.h"
+#include "JSCInlines.h"
+#include "JSString.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL symbolProtoFuncToString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL symbolProtoFuncValueOf(ExecState*);
+
+}
+
+#include "SymbolPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo SymbolPrototype::s_info = { "Symbol", &Base::s_info, &symbolPrototypeTable, CREATE_METHOD_TABLE(SymbolPrototype) };
+
+/* Source for SymbolPrototype.lut.h
+@begin symbolPrototypeTable
+ toString symbolProtoFuncToString DontEnum|Function 0
+ valueOf symbolProtoFuncValueOf DontEnum|Function 0
+@end
+*/
+
+SymbolPrototype::SymbolPrototype(VM& vm, Structure* structure)
+ : Base(vm, structure)
+{
+}
+
+void SymbolPrototype::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Symbol"), DontEnum | ReadOnly);
+ ASSERT(inherits(info()));
+}
+
+bool SymbolPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<Base>(exec, symbolPrototypeTable, jsCast<SymbolPrototype*>(object), propertyName, slot);
+}
+
+// ------------------------------ Functions ---------------------------
+
+EncodedJSValue JSC_HOST_CALL symbolProtoFuncToString(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ Symbol* symbol = nullptr;
+ if (thisValue.isSymbol())
+ symbol = asSymbol(thisValue);
+ else if (!thisValue.isObject())
+ return throwVMTypeError(exec);
+ else {
+ JSObject* thisObject = asObject(thisValue);
+ if (!thisObject->inherits(SymbolObject::info()))
+ return throwVMTypeError(exec);
+ symbol = asSymbol(jsCast<SymbolObject*>(thisObject)->internalValue());
+ }
+
+ return JSValue::encode(jsNontrivialString(exec, symbol->descriptiveString()));
+}
+
+EncodedJSValue JSC_HOST_CALL symbolProtoFuncValueOf(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (thisValue.isSymbol())
+ return JSValue::encode(thisValue);
+
+ if (!thisValue.isObject())
+ return throwVMTypeError(exec);
+
+ JSObject* thisObject = asObject(thisValue);
+ if (!thisObject->inherits(SymbolObject::info()))
+ return throwVMTypeError(exec);
+
+ return JSValue::encode(jsCast<SymbolObject*>(thisObject)->internalValue());
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NamePrototype.h b/Source/JavaScriptCore/runtime/SymbolPrototype.h
index d4b947f72..9613787ba 100644
--- a/Source/JavaScriptCore/runtime/NamePrototype.h
+++ b/Source/JavaScriptCore/runtime/SymbolPrototype.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,42 +24,43 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef NamePrototype_h
-#define NamePrototype_h
+#ifndef SymbolPrototype_h
+#define SymbolPrototype_h
-#include "NameInstance.h"
+#include "Symbol.h"
+#include "SymbolObject.h"
namespace JSC {
-class NamePrototype : public NameInstance {
+// In the ES6 spec, Symbol.prototype object is an ordinary JS object, not one of the symbol wrapper object instance.
+class SymbolPrototype : public JSNonFinalObject {
public:
- typedef NameInstance Base;
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
- static NamePrototype* create(ExecState* exec, Structure* structure)
+ static SymbolPrototype* create(VM& vm, JSGlobalObject*, Structure* structure)
{
- VM& vm = exec->vm();
- NamePrototype* prototype = new (NotNull, allocateCell<NamePrototype>(vm.heap)) NamePrototype(exec, structure);
+ SymbolPrototype* prototype = new (NotNull, allocateCell<SymbolPrototype>(vm.heap)) SymbolPrototype(vm, structure);
prototype->finishCreation(vm);
return prototype;
}
-
+
DECLARE_INFO;
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(NameInstanceType, StructureFlags), info());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}
protected:
- NamePrototype(ExecState*, Structure*);
+ SymbolPrototype(VM&, Structure*);
void finishCreation(VM&);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NameInstance::StructureFlags;
-
private:
static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
};
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(SymbolPrototype);
} // namespace JSC
-#endif // NamePrototype_h
+#endif // SymbolPrototype_h
diff --git a/Source/JavaScriptCore/runtime/SymbolTable.cpp b/Source/JavaScriptCore/runtime/SymbolTable.cpp
index 556dbf7af..f40e14e9e 100644
--- a/Source/JavaScriptCore/runtime/SymbolTable.cpp
+++ b/Source/JavaScriptCore/runtime/SymbolTable.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2014, 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
@@ -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.
*
@@ -30,12 +30,13 @@
#include "SymbolTable.h"
#include "JSDestructibleObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "SlotVisitorInlines.h"
+#include "TypeProfiler.h"
namespace JSC {
-const ClassInfo SymbolTable::s_info = { "SymbolTable", 0, 0, 0, CREATE_METHOD_TABLE(SymbolTable) };
+const ClassInfo SymbolTable::s_info = { "SymbolTable", 0, 0, CREATE_METHOD_TABLE(SymbolTable) };
SymbolTableEntry& SymbolTableEntry::copySlow(const SymbolTableEntry& other)
{
@@ -58,19 +59,14 @@ void SymbolTableEntry::freeFatEntrySlow()
delete fatEntry();
}
-JSValue SymbolTableEntry::inferredValue()
-{
- if (!isFat())
- return JSValue();
- return fatEntry()->m_watchpoints->inferredValue();
-}
-
void SymbolTableEntry::prepareToWatch()
{
+ if (!isWatchable())
+ return;
FatEntry* entry = inflate();
if (entry->m_watchpoints)
return;
- entry->m_watchpoints = adoptRef(new VariableWatchpointSet());
+ entry->m_watchpoints = adoptRef(new WatchpointSet(ClearWatchpoint));
}
void SymbolTableEntry::addWatchpoint(Watchpoint* watchpoint)
@@ -78,15 +74,6 @@ void SymbolTableEntry::addWatchpoint(Watchpoint* watchpoint)
fatEntry()->m_watchpoints->add(watchpoint);
}
-void SymbolTableEntry::notifyWriteSlow(JSValue value)
-{
- VariableWatchpointSet* watchpoints = fatEntry()->m_watchpoints.get();
- if (!watchpoints)
- return;
-
- watchpoints->notifyWrite(value);
-}
-
SymbolTableEntry::FatEntry* SymbolTableEntry::inflateSlow()
{
FatEntry* entry = new FatEntry(m_bits);
@@ -96,69 +83,181 @@ SymbolTableEntry::FatEntry* SymbolTableEntry::inflateSlow()
SymbolTable::SymbolTable(VM& vm)
: JSCell(vm, vm.symbolTableStructure.get())
- , m_parameterCountIncludingThis(0)
, m_usesNonStrictEval(false)
- , m_captureStart(0)
- , m_captureEnd(0)
- , m_functionEnteredOnce(ClearWatchpoint)
+ , m_nestedLexicalScope(false)
+ , m_scopeType(VarScope)
{
}
SymbolTable::~SymbolTable() { }
+void SymbolTable::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ m_singletonScope.set(vm, this, InferredValue::create(vm));
+}
+
void SymbolTable::visitChildren(JSCell* thisCell, SlotVisitor& visitor)
{
SymbolTable* thisSymbolTable = jsCast<SymbolTable*>(thisCell);
- if (!thisSymbolTable->m_watchpointCleanup) {
- thisSymbolTable->m_watchpointCleanup =
- std::make_unique<WatchpointCleanup>(thisSymbolTable);
- }
- visitor.addUnconditionalFinalizer(thisSymbolTable->m_watchpointCleanup.get());
+ visitor.append(&thisSymbolTable->m_arguments);
+ visitor.append(&thisSymbolTable->m_singletonScope);
+
+ // Save some memory. This is O(n) to rebuild and we do so on the fly.
+ ConcurrentJITLocker locker(thisSymbolTable->m_lock);
+ thisSymbolTable->m_localToEntry = nullptr;
}
-SymbolTable::WatchpointCleanup::WatchpointCleanup(SymbolTable* symbolTable)
- : m_symbolTable(symbolTable)
+const SymbolTable::LocalToEntryVec& SymbolTable::localToEntry(const ConcurrentJITLocker&)
{
+ if (UNLIKELY(!m_localToEntry)) {
+ unsigned size = 0;
+ for (auto& entry : m_map) {
+ VarOffset offset = entry.value.varOffset();
+ if (offset.isScope())
+ size = std::max(size, offset.scopeOffset().offset() + 1);
+ }
+
+ m_localToEntry = std::make_unique<LocalToEntryVec>(size, nullptr);
+ for (auto& entry : m_map) {
+ VarOffset offset = entry.value.varOffset();
+ if (offset.isScope())
+ m_localToEntry->at(offset.scopeOffset().offset()) = &entry.value;
+ }
+ }
+
+ return *m_localToEntry;
}
-SymbolTable::WatchpointCleanup::~WatchpointCleanup() { }
-
-void SymbolTable::WatchpointCleanup::finalizeUnconditionally()
+SymbolTableEntry* SymbolTable::entryFor(const ConcurrentJITLocker& locker, ScopeOffset offset)
{
- Map::iterator iter = m_symbolTable->m_map.begin();
- Map::iterator end = m_symbolTable->m_map.end();
- for (; iter != end; ++iter) {
- if (VariableWatchpointSet* set = iter->value.watchpointSet())
- set->finalizeUnconditionally();
- }
+ auto& toEntryVector = localToEntry(locker);
+ if (offset.offset() >= toEntryVector.size())
+ return nullptr;
+ return toEntryVector[offset.offset()];
}
-SymbolTable* SymbolTable::clone(VM& vm)
+SymbolTable* SymbolTable::cloneScopePart(VM& vm)
{
SymbolTable* result = SymbolTable::create(vm);
- result->m_parameterCountIncludingThis = m_parameterCountIncludingThis;
result->m_usesNonStrictEval = m_usesNonStrictEval;
- result->m_captureStart = m_captureStart;
- result->m_captureEnd = m_captureEnd;
-
- Map::iterator iter = m_map.begin();
- Map::iterator end = m_map.end();
- for (; iter != end; ++iter) {
+ result->m_nestedLexicalScope = m_nestedLexicalScope;
+ result->m_scopeType = m_scopeType;
+
+ for (auto iter = m_map.begin(), end = m_map.end(); iter != end; ++iter) {
+ if (!iter->value.varOffset().isScope())
+ continue;
result->m_map.add(
iter->key,
- SymbolTableEntry(iter->value.getIndex(), iter->value.getAttributes()));
+ SymbolTableEntry(iter->value.varOffset(), iter->value.getAttributes()));
}
- if (m_slowArguments) {
- result->m_slowArguments = std::make_unique<SlowArgument[]>(parameterCount());
- for (unsigned i = parameterCount(); i--;)
- result->m_slowArguments[i] = m_slowArguments[i];
+ result->m_maxScopeOffset = m_maxScopeOffset;
+
+ if (ScopedArgumentsTable* arguments = this->arguments())
+ result->m_arguments.set(vm, result, arguments);
+
+ if (m_typeProfilingRareData) {
+ result->m_typeProfilingRareData = std::make_unique<TypeProfilingRareData>();
+
+ {
+ auto iter = m_typeProfilingRareData->m_uniqueIDMap.begin();
+ auto end = m_typeProfilingRareData->m_uniqueIDMap.end();
+ for (; iter != end; ++iter)
+ result->m_typeProfilingRareData->m_uniqueIDMap.set(iter->key, iter->value);
+ }
+
+ {
+ auto iter = m_typeProfilingRareData->m_offsetToVariableMap.begin();
+ auto end = m_typeProfilingRareData->m_offsetToVariableMap.end();
+ for (; iter != end; ++iter)
+ result->m_typeProfilingRareData->m_offsetToVariableMap.set(iter->key, iter->value);
+ }
+
+ {
+ auto iter = m_typeProfilingRareData->m_uniqueTypeSetMap.begin();
+ auto end = m_typeProfilingRareData->m_uniqueTypeSetMap.end();
+ for (; iter != end; ++iter)
+ result->m_typeProfilingRareData->m_uniqueTypeSetMap.set(iter->key, iter->value);
+ }
}
return result;
}
+void SymbolTable::prepareForTypeProfiling(const ConcurrentJITLocker&)
+{
+ if (m_typeProfilingRareData)
+ return;
+
+ m_typeProfilingRareData = std::make_unique<TypeProfilingRareData>();
+
+ for (auto iter = m_map.begin(), end = m_map.end(); iter != end; ++iter) {
+ m_typeProfilingRareData->m_uniqueIDMap.set(iter->key, TypeProfilerNeedsUniqueIDGeneration);
+ m_typeProfilingRareData->m_offsetToVariableMap.set(iter->value.varOffset(), iter->key);
+ }
+}
+
+GlobalVariableID SymbolTable::uniqueIDForVariable(const ConcurrentJITLocker&, UniquedStringImpl* key, VM& vm)
+{
+ RELEASE_ASSERT(m_typeProfilingRareData);
+
+ auto iter = m_typeProfilingRareData->m_uniqueIDMap.find(key);
+ auto end = m_typeProfilingRareData->m_uniqueIDMap.end();
+ if (iter == end)
+ return TypeProfilerNoGlobalIDExists;
+
+ GlobalVariableID id = iter->value;
+ if (id == TypeProfilerNeedsUniqueIDGeneration) {
+ id = vm.typeProfiler()->getNextUniqueVariableID();
+ m_typeProfilingRareData->m_uniqueIDMap.set(key, id);
+ m_typeProfilingRareData->m_uniqueTypeSetMap.set(key, TypeSet::create()); // Make a new global typeset for this corresponding ID.
+ }
+
+ return id;
+}
+
+GlobalVariableID SymbolTable::uniqueIDForOffset(const ConcurrentJITLocker& locker, VarOffset offset, VM& vm)
+{
+ RELEASE_ASSERT(m_typeProfilingRareData);
+
+ auto iter = m_typeProfilingRareData->m_offsetToVariableMap.find(offset);
+ auto end = m_typeProfilingRareData->m_offsetToVariableMap.end();
+ if (iter == end)
+ return TypeProfilerNoGlobalIDExists;
+
+ return uniqueIDForVariable(locker, iter->value.get(), vm);
+}
+
+RefPtr<TypeSet> SymbolTable::globalTypeSetForOffset(const ConcurrentJITLocker& locker, VarOffset offset, VM& vm)
+{
+ RELEASE_ASSERT(m_typeProfilingRareData);
+
+ uniqueIDForOffset(locker, offset, vm); // Lazily create the TypeSet if necessary.
+
+ auto iter = m_typeProfilingRareData->m_offsetToVariableMap.find(offset);
+ auto end = m_typeProfilingRareData->m_offsetToVariableMap.end();
+ if (iter == end)
+ return nullptr;
+
+ return globalTypeSetForVariable(locker, iter->value.get(), vm);
+}
+
+RefPtr<TypeSet> SymbolTable::globalTypeSetForVariable(const ConcurrentJITLocker& locker, UniquedStringImpl* key, VM& vm)
+{
+ RELEASE_ASSERT(m_typeProfilingRareData);
+
+ uniqueIDForVariable(locker, key, vm); // Lazily create the TypeSet if necessary.
+
+ auto iter = m_typeProfilingRareData->m_uniqueTypeSetMap.find(key);
+ auto end = m_typeProfilingRareData->m_uniqueTypeSetMap.end();
+ if (iter == end)
+ return nullptr;
+
+ return iter->value;
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h
index 6e2c26d68..fa3742af9 100644
--- a/Source/JavaScriptCore/runtime/SymbolTable.h
+++ b/Source/JavaScriptCore/runtime/SymbolTable.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2012-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
@@ -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.
*
@@ -30,30 +30,20 @@
#define SymbolTable_h
#include "ConcurrentJITLock.h"
+#include "ConstantMode.h"
+#include "InferredValue.h"
#include "JSObject.h"
-#include "VariableWatchpointSet.h"
+#include "ScopedArgumentsTable.h"
+#include "TypeLocation.h"
+#include "VarOffset.h"
+#include "Watchpoint.h"
#include <memory>
#include <wtf/HashTraits.h>
-#include <wtf/text/StringImpl.h>
+#include <wtf/text/UniquedStringImpl.h>
namespace JSC {
-struct SlowArgument {
- enum Status {
- Normal = 0,
- Captured = 1,
- Deleted = 2
- };
-
- SlowArgument()
- : status(Normal)
- , index(0)
- {
- }
-
- Status status;
- int index; // If status is 'Deleted', index is bogus.
-};
+class SymbolTable;
static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); }
@@ -76,14 +66,36 @@ static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>
// counted pointer to a shared WatchpointSet. Thus, in-place edits of the
// WatchpointSet will manifest in all copies. Here's a picture:
//
-// SymbolTableEntry --> FatEntry --> VariableWatchpointSet
+// SymbolTableEntry --> FatEntry --> WatchpointSet
//
// If you make a copy of a SymbolTableEntry, you will have:
//
-// original: SymbolTableEntry --> FatEntry --> VariableWatchpointSet
+// original: SymbolTableEntry --> FatEntry --> WatchpointSet
// copy: SymbolTableEntry --> FatEntry -----^
struct SymbolTableEntry {
+private:
+ static VarOffset varOffsetFromBits(intptr_t bits)
+ {
+ VarKind kind;
+ intptr_t kindBits = bits & KindBitsMask;
+ if (kindBits <= UnwatchableScopeKindBits)
+ kind = VarKind::Scope;
+ else if (kindBits == StackKindBits)
+ kind = VarKind::Stack;
+ else
+ kind = VarKind::DirectArgument;
+ return VarOffset::assemble(kind, static_cast<int>(bits >> FlagBits));
+ }
+
+ static ScopeOffset scopeOffsetFromBits(intptr_t bits)
+ {
+ ASSERT((bits & KindBitsMask) <= UnwatchableScopeKindBits);
+ return ScopeOffset(static_cast<int>(bits >> FlagBits));
+ }
+
+public:
+
// Use the SymbolTableEntry::Fast class, either via implicit cast or by calling
// getFast(), when you (1) only care about isNull(), getIndex(), and isReadOnly(),
// and (2) you are in a hot path where you need to minimize the number of times
@@ -105,22 +117,35 @@ struct SymbolTableEntry {
return !(m_bits & ~SlimFlag);
}
- int getIndex() const
+ VarOffset varOffset() const
{
- return static_cast<int>(m_bits >> FlagBits);
+ return varOffsetFromBits(m_bits);
}
-
+
+ // Asserts if the offset is anything but a scope offset. This structures the assertions
+ // in a way that may result in better code, even in release, than doing
+ // varOffset().scopeOffset().
+ ScopeOffset scopeOffset() const
+ {
+ return scopeOffsetFromBits(m_bits);
+ }
+
bool isReadOnly() const
{
return m_bits & ReadOnlyFlag;
}
+ bool isDontEnum() const
+ {
+ return m_bits & DontEnumFlag;
+ }
+
unsigned getAttributes() const
{
unsigned attributes = 0;
- if (m_bits & ReadOnlyFlag)
+ if (isReadOnly())
attributes |= ReadOnly;
- if (m_bits & DontEnumFlag)
+ if (isDontEnum())
attributes |= DontEnum;
return attributes;
}
@@ -140,18 +165,18 @@ struct SymbolTableEntry {
{
}
- SymbolTableEntry(int index)
+ SymbolTableEntry(VarOffset offset)
: m_bits(SlimFlag)
{
- ASSERT(isValidIndex(index));
- pack(index, false, false);
+ ASSERT(isValidVarOffset(offset));
+ pack(offset, true, false, false);
}
- SymbolTableEntry(int index, unsigned attributes)
+ SymbolTableEntry(VarOffset offset, unsigned attributes)
: m_bits(SlimFlag)
{
- ASSERT(isValidIndex(index));
- pack(index, attributes & ReadOnly, attributes & DontEnum);
+ ASSERT(isValidVarOffset(offset));
+ pack(offset, true, attributes & ReadOnly, attributes & DontEnum);
}
~SymbolTableEntry()
@@ -179,9 +204,22 @@ struct SymbolTableEntry {
return !(bits() & ~SlimFlag);
}
- int getIndex() const
+ VarOffset varOffset() const
+ {
+ return varOffsetFromBits(bits());
+ }
+
+ bool isWatchable() const
+ {
+ return (m_bits & KindBitsMask) == ScopeKindBits;
+ }
+
+ // Asserts if the offset is anything but a scope offset. This structures the assertions
+ // in a way that may result in better code, even in release, than doing
+ // varOffset().scopeOffset().
+ ScopeOffset scopeOffset() const
{
- return static_cast<int>(bits() >> FlagBits);
+ return scopeOffsetFromBits(bits());
}
ALWAYS_INLINE Fast getFast() const
@@ -204,10 +242,10 @@ struct SymbolTableEntry {
{
return getFast().getAttributes();
}
-
+
void setAttributes(unsigned attributes)
{
- pack(getIndex(), attributes & ReadOnly, attributes & DontEnum);
+ pack(varOffset(), isWatchable(), attributes & ReadOnly, attributes & DontEnum);
}
bool isReadOnly() const
@@ -215,32 +253,65 @@ struct SymbolTableEntry {
return bits() & ReadOnlyFlag;
}
- JSValue inferredValue();
+ ConstantMode constantMode() const
+ {
+ return modeForIsConstant(isReadOnly());
+ }
+
+ bool isDontEnum() const
+ {
+ return bits() & DontEnumFlag;
+ }
+
+ void disableWatching()
+ {
+ if (WatchpointSet* set = watchpointSet())
+ set->invalidate("Disabling watching in symbol table");
+ if (varOffset().isScope())
+ pack(varOffset(), false, isReadOnly(), isDontEnum());
+ }
void prepareToWatch();
void addWatchpoint(Watchpoint*);
- VariableWatchpointSet* watchpointSet()
+ // This watchpoint set is initialized clear, and goes through the following state transitions:
+ //
+ // First write to this var, in any scope that has this symbol table: Clear->IsWatched.
+ //
+ // Second write to this var, in any scope that has this symbol table: IsWatched->IsInvalidated.
+ //
+ // We ensure that we touch the set (i.e. trigger its state transition) after we do the write. This
+ // means that if you're in the compiler thread, and you:
+ //
+ // 1) Observe that the set IsWatched and commit to adding your watchpoint.
+ // 2) Load a value from any scope that has this watchpoint set.
+ //
+ // Then you can be sure that that value is either going to be the correct value for that var forever,
+ // or the watchpoint set will invalidate and you'll get fired.
+ //
+ // It's possible to write a program that first creates multiple scopes with the same var, and then
+ // initializes that var in just one of them. This means that a compilation could constant-fold to one
+ // of the scopes that still has an undefined value for this variable. That's fine, because at that
+ // point any write to any of the instances of that variable would fire the watchpoint.
+ WatchpointSet* watchpointSet()
{
if (!isFat())
return 0;
return fatEntry()->m_watchpoints.get();
}
- ALWAYS_INLINE void notifyWrite(JSValue value)
- {
- if (LIKELY(!isFat()))
- return;
- notifyWriteSlow(value);
- }
-
private:
static const intptr_t SlimFlag = 0x1;
static const intptr_t ReadOnlyFlag = 0x2;
static const intptr_t DontEnumFlag = 0x4;
static const intptr_t NotNullFlag = 0x8;
- static const intptr_t FlagBits = 4;
+ static const intptr_t KindBitsMask = 0x30;
+ static const intptr_t ScopeKindBits = 0x00;
+ static const intptr_t UnwatchableScopeKindBits = 0x10;
+ static const intptr_t StackKindBits = 0x20;
+ static const intptr_t DirectArgumentKindBits = 0x30;
+ static const intptr_t FlagBits = 6;
class FatEntry {
WTF_MAKE_FAST_ALLOCATED;
@@ -252,11 +323,11 @@ private:
intptr_t m_bits; // always has FatFlag set and exactly matches what the bits would have been if this wasn't fat.
- RefPtr<VariableWatchpointSet> m_watchpoints;
+ RefPtr<WatchpointSet> m_watchpoints;
};
SymbolTableEntry& copySlow(const SymbolTableEntry&);
- JS_EXPORT_PRIVATE void notifyWriteSlow(JSValue);
+ JS_EXPORT_PRIVATE void notifyWriteSlow(VM&, JSValue, const FireDetail&);
bool isFat() const
{
@@ -307,20 +378,38 @@ private:
JS_EXPORT_PRIVATE void freeFatEntrySlow();
- void pack(int index, bool readOnly, bool dontEnum)
+ void pack(VarOffset offset, bool isWatchable, bool readOnly, bool dontEnum)
{
ASSERT(!isFat());
intptr_t& bitsRef = bits();
- bitsRef = (static_cast<intptr_t>(index) << FlagBits) | NotNullFlag | SlimFlag;
+ bitsRef =
+ (static_cast<intptr_t>(offset.rawOffset()) << FlagBits) | NotNullFlag | SlimFlag;
if (readOnly)
bitsRef |= ReadOnlyFlag;
if (dontEnum)
bitsRef |= DontEnumFlag;
+ switch (offset.kind()) {
+ case VarKind::Scope:
+ if (isWatchable)
+ bitsRef |= ScopeKindBits;
+ else
+ bitsRef |= UnwatchableScopeKindBits;
+ break;
+ case VarKind::Stack:
+ bitsRef |= StackKindBits;
+ break;
+ case VarKind::DirectArgument:
+ bitsRef |= DirectArgumentKindBits;
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
}
- bool isValidIndex(int index)
+ static bool isValidVarOffset(VarOffset offset)
{
- return ((static_cast<intptr_t>(index) << FlagBits) >> FlagBits) == static_cast<intptr_t>(index);
+ return ((static_cast<intptr_t>(offset.rawOffset()) << FlagBits) >> FlagBits) == static_cast<intptr_t>(offset.rawOffset());
}
intptr_t m_bits;
@@ -330,11 +419,16 @@ struct SymbolTableIndexHashTraits : HashTraits<SymbolTableEntry> {
static const bool needsDestruction = true;
};
-class SymbolTable : public JSCell {
+class SymbolTable final : public JSCell {
public:
typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
- typedef HashMap<RefPtr<StringImpl>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<StringImpl>>, SymbolTableIndexHashTraits> Map;
+ typedef HashMap<RefPtr<UniquedStringImpl>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, SymbolTableIndexHashTraits> Map;
+ typedef HashMap<RefPtr<UniquedStringImpl>, GlobalVariableID, IdentifierRepHash> UniqueIDMap;
+ typedef HashMap<RefPtr<UniquedStringImpl>, RefPtr<TypeSet>, IdentifierRepHash> UniqueTypeSetMap;
+ typedef HashMap<VarOffset, RefPtr<UniquedStringImpl>> OffsetToVariableMap;
+ typedef Vector<SymbolTableEntry*> LocalToEntryVec;
static SymbolTable* create(VM& vm)
{
@@ -342,43 +436,50 @@ public:
symbolTable->finishCreation(vm);
return symbolTable;
}
+
+ static SymbolTable* createNameScopeTable(VM& vm, const Identifier& ident, unsigned attributes)
+ {
+ SymbolTable* result = create(vm);
+ result->add(ident.impl(), SymbolTableEntry(VarOffset(ScopeOffset(0)), attributes));
+ return result;
+ }
+
static const bool needsDestruction = true;
- static const bool hasImmortalStructure = true;
static void destroy(JSCell*);
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(LeafType, StructureFlags), info());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
}
// You must hold the lock until after you're done with the iterator.
- Map::iterator find(const ConcurrentJITLocker&, StringImpl* key)
+ Map::iterator find(const ConcurrentJITLocker&, UniquedStringImpl* key)
{
return m_map.find(key);
}
- Map::iterator find(const GCSafeConcurrentJITLocker&, StringImpl* key)
+ Map::iterator find(const GCSafeConcurrentJITLocker&, UniquedStringImpl* key)
{
return m_map.find(key);
}
- SymbolTableEntry get(const ConcurrentJITLocker&, StringImpl* key)
+ SymbolTableEntry get(const ConcurrentJITLocker&, UniquedStringImpl* key)
{
return m_map.get(key);
}
- SymbolTableEntry get(StringImpl* key)
+ SymbolTableEntry get(UniquedStringImpl* key)
{
ConcurrentJITLocker locker(m_lock);
return get(locker, key);
}
- SymbolTableEntry inlineGet(const ConcurrentJITLocker&, StringImpl* key)
+ SymbolTableEntry inlineGet(const ConcurrentJITLocker&, UniquedStringImpl* key)
{
return m_map.inlineGet(key);
}
- SymbolTableEntry inlineGet(StringImpl* key)
+ SymbolTableEntry inlineGet(UniquedStringImpl* key)
{
ConcurrentJITLocker locker(m_lock);
return inlineGet(locker, key);
@@ -410,100 +511,193 @@ public:
return size(locker);
}
- Map::AddResult add(const ConcurrentJITLocker&, StringImpl* key, const SymbolTableEntry& entry)
+ ScopeOffset maxScopeOffset() const
+ {
+ return m_maxScopeOffset;
+ }
+
+ void didUseScopeOffset(ScopeOffset offset)
+ {
+ if (!m_maxScopeOffset || m_maxScopeOffset < offset)
+ m_maxScopeOffset = offset;
+ }
+
+ void didUseVarOffset(VarOffset offset)
{
- return m_map.add(key, entry);
+ if (offset.isScope())
+ didUseScopeOffset(offset.scopeOffset());
}
- void add(StringImpl* key, const SymbolTableEntry& entry)
+ unsigned scopeSize() const
+ {
+ ScopeOffset maxScopeOffset = this->maxScopeOffset();
+
+ // Do some calculation that relies on invalid scope offset plus one being zero.
+ unsigned fastResult = maxScopeOffset.offsetUnchecked() + 1;
+
+ // Assert that this works.
+ ASSERT(fastResult == (!maxScopeOffset ? 0 : maxScopeOffset.offset() + 1));
+
+ return fastResult;
+ }
+
+ ScopeOffset nextScopeOffset() const
+ {
+ return ScopeOffset(scopeSize());
+ }
+
+ ScopeOffset takeNextScopeOffset(const ConcurrentJITLocker&)
+ {
+ ScopeOffset result = nextScopeOffset();
+ m_maxScopeOffset = result;
+ return result;
+ }
+
+ ScopeOffset takeNextScopeOffset()
+ {
+ ConcurrentJITLocker locker(m_lock);
+ return takeNextScopeOffset(locker);
+ }
+
+ void add(const ConcurrentJITLocker&, UniquedStringImpl* key, const SymbolTableEntry& entry)
+ {
+ RELEASE_ASSERT(!m_localToEntry);
+ didUseVarOffset(entry.varOffset());
+ Map::AddResult result = m_map.add(key, entry);
+ ASSERT_UNUSED(result, result.isNewEntry);
+ }
+
+ void add(UniquedStringImpl* key, const SymbolTableEntry& entry)
{
ConcurrentJITLocker locker(m_lock);
add(locker, key, entry);
}
- Map::AddResult set(const ConcurrentJITLocker&, StringImpl* key, const SymbolTableEntry& entry)
+ void set(const ConcurrentJITLocker&, UniquedStringImpl* key, const SymbolTableEntry& entry)
{
- return m_map.set(key, entry);
+ RELEASE_ASSERT(!m_localToEntry);
+ didUseVarOffset(entry.varOffset());
+ m_map.set(key, entry);
}
- void set(StringImpl* key, const SymbolTableEntry& entry)
+ void set(UniquedStringImpl* key, const SymbolTableEntry& entry)
{
ConcurrentJITLocker locker(m_lock);
set(locker, key, entry);
}
- bool contains(const ConcurrentJITLocker&, StringImpl* key)
+ bool contains(const ConcurrentJITLocker&, UniquedStringImpl* key)
{
return m_map.contains(key);
}
- bool contains(StringImpl* key)
+ bool contains(UniquedStringImpl* key)
{
ConcurrentJITLocker locker(m_lock);
return contains(locker, key);
}
- bool usesNonStrictEval() { return m_usesNonStrictEval; }
- void setUsesNonStrictEval(bool usesNonStrictEval) { m_usesNonStrictEval = usesNonStrictEval; }
-
- int captureStart() const { return m_captureStart; }
- void setCaptureStart(int captureStart) { m_captureStart = captureStart; }
-
- int captureEnd() const { return m_captureEnd; }
- void setCaptureEnd(int captureEnd) { m_captureEnd = captureEnd; }
-
- int captureCount() const { return -(m_captureEnd - m_captureStart); }
+ // The principle behind ScopedArgumentsTable modifications is that we will create one and
+ // leave it unlocked - thereby allowing in-place changes - until someone asks for a pointer to
+ // the table. Then, we will lock it. Then both our future changes and their future changes
+ // will first have to make a copy. This discipline means that usually when we create a
+ // ScopedArguments object, we don't have to make a copy of the ScopedArgumentsTable - instead
+ // we just take a reference to one that we already have.
+
+ uint32_t argumentsLength() const
+ {
+ if (!m_arguments)
+ return 0;
+ return m_arguments->length();
+ }
- bool isCaptured(int operand)
+ void setArgumentsLength(VM& vm, uint32_t length)
{
- return operand <= captureStart() && operand > captureEnd();
+ if (UNLIKELY(!m_arguments))
+ m_arguments.set(vm, this, ScopedArgumentsTable::create(vm));
+ m_arguments.set(vm, this, m_arguments->setLength(vm, length));
}
+
+ ScopeOffset argumentOffset(uint32_t i) const
+ {
+ ASSERT_WITH_SECURITY_IMPLICATION(m_arguments);
+ return m_arguments->get(i);
+ }
+
+ void setArgumentOffset(VM& vm, uint32_t i, ScopeOffset offset)
+ {
+ ASSERT_WITH_SECURITY_IMPLICATION(m_arguments);
+ m_arguments.set(vm, this, m_arguments->set(vm, i, offset));
+ }
+
+ ScopedArgumentsTable* arguments() const
+ {
+ if (!m_arguments)
+ return nullptr;
+ m_arguments->lock();
+ return m_arguments.get();
+ }
+
+ const LocalToEntryVec& localToEntry(const ConcurrentJITLocker&);
+ SymbolTableEntry* entryFor(const ConcurrentJITLocker&, ScopeOffset);
+
+ GlobalVariableID uniqueIDForVariable(const ConcurrentJITLocker&, UniquedStringImpl* key, VM&);
+ GlobalVariableID uniqueIDForOffset(const ConcurrentJITLocker&, VarOffset, VM&);
+ RefPtr<TypeSet> globalTypeSetForOffset(const ConcurrentJITLocker&, VarOffset, VM&);
+ RefPtr<TypeSet> globalTypeSetForVariable(const ConcurrentJITLocker&, UniquedStringImpl* key, VM&);
- int parameterCount() { return m_parameterCountIncludingThis - 1; }
- int parameterCountIncludingThis() { return m_parameterCountIncludingThis; }
- void setParameterCountIncludingThis(int parameterCountIncludingThis) { m_parameterCountIncludingThis = parameterCountIncludingThis; }
+ bool usesNonStrictEval() const { return m_usesNonStrictEval; }
+ void setUsesNonStrictEval(bool usesNonStrictEval) { m_usesNonStrictEval = usesNonStrictEval; }
+
+ bool isNestedLexicalScope() const { return m_nestedLexicalScope; }
+ void markIsNestedLexicalScope() { ASSERT(scopeType() == LexicalScope); m_nestedLexicalScope = true; }
- // 0 if we don't capture any arguments; parameterCount() in length if we do.
- const SlowArgument* slowArguments() { return m_slowArguments.get(); }
- void setSlowArguments(std::unique_ptr<SlowArgument[]> slowArguments) { m_slowArguments = std::move(slowArguments); }
+ enum ScopeType {
+ VarScope,
+ GlobalLexicalScope,
+ LexicalScope,
+ CatchScope,
+ FunctionNameScope
+ };
+ void setScopeType(ScopeType type) { m_scopeType = type; }
+ ScopeType scopeType() const { return static_cast<ScopeType>(m_scopeType); }
+
+ SymbolTable* cloneScopePart(VM&);
+
+ void prepareForTypeProfiling(const ConcurrentJITLocker&);
- SymbolTable* clone(VM&);
+ InferredValue* singletonScope() { return m_singletonScope.get(); }
static void visitChildren(JSCell*, SlotVisitor&);
DECLARE_EXPORT_INFO;
private:
- class WatchpointCleanup : public UnconditionalFinalizer {
- public:
- WatchpointCleanup(SymbolTable*);
- virtual ~WatchpointCleanup();
-
- protected:
- virtual void finalizeUnconditionally() override;
-
- private:
- SymbolTable* m_symbolTable;
- };
-
JS_EXPORT_PRIVATE SymbolTable(VM&);
~SymbolTable();
+
+ JS_EXPORT_PRIVATE void finishCreation(VM&);
Map m_map;
+ ScopeOffset m_maxScopeOffset;
- int m_parameterCountIncludingThis;
- bool m_usesNonStrictEval;
-
- int m_captureStart;
- int m_captureEnd;
+ struct TypeProfilingRareData {
+ UniqueIDMap m_uniqueIDMap;
+ OffsetToVariableMap m_offsetToVariableMap;
+ UniqueTypeSetMap m_uniqueTypeSetMap;
+ };
+ std::unique_ptr<TypeProfilingRareData> m_typeProfilingRareData;
- std::unique_ptr<SlowArgument[]> m_slowArguments;
+ bool m_usesNonStrictEval : 1;
+ bool m_nestedLexicalScope : 1; // Non-function LexicalScope.
+ unsigned m_scopeType : 3; // ScopeType
+
+ WriteBarrier<ScopedArgumentsTable> m_arguments;
+ WriteBarrier<InferredValue> m_singletonScope;
- std::unique_ptr<WatchpointCleanup> m_watchpointCleanup;
+ std::unique_ptr<LocalToEntryVec> m_localToEntry;
public:
- InlineWatchpointSet m_functionEnteredOnce;
-
mutable ConcurrentJITLock m_lock;
};
diff --git a/Source/JavaScriptCore/runtime/NameConstructor.cpp b/Source/JavaScriptCore/runtime/TemplateRegistry.cpp
index 77d7c920e..7bdac38e3 100644
--- a/Source/JavaScriptCore/runtime/NameConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/TemplateRegistry.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,46 +24,48 @@
*/
#include "config.h"
-#include "NameConstructor.h"
+#include "TemplateRegistry.h"
+#include "JSCJSValueInlines.h"
#include "JSGlobalObject.h"
-#include "NamePrototype.h"
-#include "Operations.h"
+#include "ObjectConstructor.h"
+#include "StructureInlines.h"
+#include "WeakGCMapInlines.h"
namespace JSC {
-STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(NameConstructor);
-
-const ClassInfo NameConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(NameConstructor) };
-
-NameConstructor::NameConstructor(VM& vm, Structure* structure)
- : InternalFunction(vm, structure)
+TemplateRegistry::TemplateRegistry(VM& vm)
+ : m_templateMap(vm)
{
}
-void NameConstructor::finishCreation(VM& vm, NamePrototype* prototype)
+JSArray* TemplateRegistry::getTemplateObject(ExecState* exec, const TemplateRegistryKey& templateKey)
{
- Base::finishCreation(vm, prototype->classInfo()->className);
- putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly);
- putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), DontDelete | ReadOnly | DontEnum);
-}
+ JSArray* cached = m_templateMap.get(templateKey);
+ if (cached)
+ return cached;
-static EncodedJSValue JSC_HOST_CALL constructPrivateName(ExecState* exec)
-{
- JSValue publicName = exec->argument(0);
- return JSValue::encode(NameInstance::create(exec->vm(), exec->lexicalGlobalObject()->privateNameStructure(), publicName.toString(exec)));
-}
+ unsigned count = templateKey.cookedStrings().size();
+ JSArray* templateObject = constructEmptyArray(exec, nullptr, count);
+ JSArray* rawObject = constructEmptyArray(exec, nullptr, count);
-ConstructType NameConstructor::getConstructData(JSCell*, ConstructData& constructData)
-{
- constructData.native.function = constructPrivateName;
- return ConstructTypeHost;
-}
+ for (unsigned index = 0; index < count; ++index) {
+ templateObject->putDirectIndex(exec, index, jsString(exec, templateKey.cookedStrings()[index]), ReadOnly | DontDelete, PutDirectIndexLikePutDirect);
+ rawObject->putDirectIndex(exec, index, jsString(exec, templateKey.rawStrings()[index]), ReadOnly | DontDelete, PutDirectIndexLikePutDirect);
+ }
-CallType NameConstructor::getCallData(JSCell*, CallData& callData)
-{
- callData.native.function = constructPrivateName;
- return CallTypeHost;
+ objectConstructorFreeze(exec, rawObject);
+ ASSERT(!exec->hadException());
+
+ templateObject->putDirect(exec->vm(), exec->propertyNames().raw, rawObject, ReadOnly | DontEnum | DontDelete);
+
+ objectConstructorFreeze(exec, templateObject);
+ ASSERT(!exec->hadException());
+
+ m_templateMap.set(templateKey, templateObject);
+
+ return templateObject;
}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/TemplateRegistry.h b/Source/JavaScriptCore/runtime/TemplateRegistry.h
new file mode 100644
index 000000000..9cb62ddfd
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TemplateRegistry.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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.
+ */
+
+#ifndef TemplateRegistry_h
+#define TemplateRegistry_h
+
+#include "JSArray.h"
+#include "TemplateRegistryKey.h"
+#include "WeakGCMap.h"
+#include <limits>
+
+namespace JSC {
+
+class TemplateRegistry {
+public:
+ TemplateRegistry(VM&);
+
+ JSArray* getTemplateObject(ExecState*, const TemplateRegistryKey&);
+
+private:
+ WeakGCMap<TemplateRegistryKey, JSArray> m_templateMap;
+};
+
+} // namespace JSC
+
+#endif // TemplateRegistry_h
diff --git a/Source/JavaScriptCore/runtime/TemplateRegistryKey.h b/Source/JavaScriptCore/runtime/TemplateRegistryKey.h
new file mode 100644
index 000000000..17d882884
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TemplateRegistryKey.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ *
+ * 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.
+ */
+
+#ifndef TemplateRegistryKey_h
+#define TemplateRegistryKey_h
+
+#include <limits>
+#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+
+class TemplateRegistryKey {
+public:
+ typedef Vector<String, 4> StringVector;
+
+ TemplateRegistryKey(const StringVector& rawStrings, const StringVector& cookedStrings);
+ enum DeletedValueTag { DeletedValue };
+ TemplateRegistryKey(DeletedValueTag);
+ enum EmptyValueTag { EmptyValue };
+ TemplateRegistryKey(EmptyValueTag);
+
+ bool isDeletedValue() const { return m_rawStrings.isEmpty() && m_hash == std::numeric_limits<unsigned>::max(); }
+
+ bool isEmptyValue() const { return m_rawStrings.isEmpty() && !m_hash; }
+
+ unsigned hash() const { return m_hash; }
+
+ const StringVector& rawStrings() const { return m_rawStrings; }
+ const StringVector& cookedStrings() const { return m_cookedStrings; }
+
+ bool operator==(const TemplateRegistryKey& other) const { return m_hash == other.m_hash && m_rawStrings == other.m_rawStrings; }
+ bool operator!=(const TemplateRegistryKey& other) const { return m_hash != other.m_hash || m_rawStrings != other.m_rawStrings; }
+
+ struct Hasher {
+ static unsigned hash(const TemplateRegistryKey& key) { return key.hash(); }
+ static bool equal(const TemplateRegistryKey& a, const TemplateRegistryKey& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = false;
+ };
+
+private:
+ StringVector m_rawStrings;
+ StringVector m_cookedStrings;
+ unsigned m_hash { 0 };
+};
+
+inline TemplateRegistryKey::TemplateRegistryKey(const StringVector& rawStrings, const StringVector& cookedStrings)
+ : m_rawStrings(rawStrings)
+ , m_cookedStrings(cookedStrings)
+{
+ m_hash = 0;
+ for (const String& string : rawStrings)
+ m_hash += WTF::StringHash::hash(string);
+}
+
+inline TemplateRegistryKey::TemplateRegistryKey(DeletedValueTag)
+ : m_hash(std::numeric_limits<unsigned>::max())
+{
+}
+
+inline TemplateRegistryKey::TemplateRegistryKey(EmptyValueTag)
+ : m_hash(0)
+{
+}
+
+} // namespace JSC
+
+namespace WTF {
+template<typename T> struct DefaultHash;
+
+template<> struct DefaultHash<JSC::TemplateRegistryKey> {
+ typedef JSC::TemplateRegistryKey::Hasher Hash;
+};
+
+template<> struct HashTraits<JSC::TemplateRegistryKey> : CustomHashTraits<JSC::TemplateRegistryKey> {
+};
+
+} // namespace WTF
+
+#endif // TemplateRegistryKey_h
diff --git a/Source/JavaScriptCore/runtime/TestRunnerUtils.cpp b/Source/JavaScriptCore/runtime/TestRunnerUtils.cpp
index 337c00e6e..d13090fed 100644
--- a/Source/JavaScriptCore/runtime/TestRunnerUtils.cpp
+++ b/Source/JavaScriptCore/runtime/TestRunnerUtils.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * 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
@@ -27,11 +27,11 @@
#include "TestRunnerUtils.h"
#include "CodeBlock.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
-static FunctionExecutable* getExecutable(JSValue theFunctionValue)
+FunctionExecutable* getExecutableForFunction(JSValue theFunctionValue)
{
JSFunction* theFunction = jsDynamicCast<JSFunction*>(theFunctionValue);
if (!theFunction)
@@ -42,6 +42,20 @@ static FunctionExecutable* getExecutable(JSValue theFunctionValue)
return executable;
}
+CodeBlock* getSomeBaselineCodeBlockForFunction(JSValue theFunctionValue)
+{
+ FunctionExecutable* executable = getExecutableForFunction(theFunctionValue);
+ if (!executable)
+ return 0;
+
+ CodeBlock* baselineCodeBlock = executable->baselineCodeBlockFor(CodeForCall);
+
+ if (!baselineCodeBlock)
+ baselineCodeBlock = executable->baselineCodeBlockFor(CodeForConstruct);
+
+ return baselineCodeBlock;
+}
+
JSValue numberOfDFGCompiles(JSValue theFunctionValue)
{
bool pretendToHaveManyCompiles = false;
@@ -51,32 +65,51 @@ JSValue numberOfDFGCompiles(JSValue theFunctionValue)
#else
pretendToHaveManyCompiles = true;
#endif
-
- if (FunctionExecutable* executable = getExecutable(theFunctionValue)) {
- CodeBlock* baselineCodeBlock = executable->baselineCodeBlockFor(CodeForCall);
-
- if (!baselineCodeBlock)
- baselineCodeBlock = executable->baselineCodeBlockFor(CodeForConstruct);
-
- if (!baselineCodeBlock)
- return jsNumber(0);
+ if (CodeBlock* baselineCodeBlock = getSomeBaselineCodeBlockForFunction(theFunctionValue)) {
if (pretendToHaveManyCompiles)
return jsNumber(1000000.0);
return jsNumber(baselineCodeBlock->numberOfDFGCompiles());
}
- return jsUndefined();
+ return jsNumber(0);
}
JSValue setNeverInline(JSValue theFunctionValue)
{
- if (FunctionExecutable* executable = getExecutable(theFunctionValue))
+ if (FunctionExecutable* executable = getExecutableForFunction(theFunctionValue))
executable->setNeverInline(true);
return jsUndefined();
}
+JSValue setNeverOptimize(JSValue theFunctionValue)
+{
+ if (FunctionExecutable* executable = getExecutableForFunction(theFunctionValue))
+ executable->setNeverOptimize(true);
+
+ return jsUndefined();
+}
+
+JSValue optimizeNextInvocation(JSValue theFunctionValue)
+{
+#if ENABLE(JIT)
+ if (CodeBlock* baselineCodeBlock = getSomeBaselineCodeBlockForFunction(theFunctionValue))
+ baselineCodeBlock->optimizeNextInvocation();
+#else
+ UNUSED_PARAM(theFunctionValue);
+#endif
+
+ return jsUndefined();
+}
+
+JSValue failNextNewCodeBlock(ExecState* exec)
+{
+ exec->vm().setFailNextNewCodeBlock();
+
+ return jsUndefined();
+}
+
JSValue numberOfDFGCompiles(ExecState* exec)
{
if (exec->argumentCount() < 1)
@@ -91,5 +124,19 @@ JSValue setNeverInline(ExecState* exec)
return setNeverInline(exec->uncheckedArgument(0));
}
+JSValue setNeverOptimize(ExecState* exec)
+{
+ if (exec->argumentCount() < 1)
+ return jsUndefined();
+ return setNeverOptimize(exec->uncheckedArgument(0));
+}
+
+JSValue optimizeNextInvocation(ExecState* exec)
+{
+ if (exec->argumentCount() < 1)
+ return jsUndefined();
+ return optimizeNextInvocation(exec->uncheckedArgument(0));
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/TestRunnerUtils.h b/Source/JavaScriptCore/runtime/TestRunnerUtils.h
index 5ee87ac2c..b8dfaeac0 100644
--- a/Source/JavaScriptCore/runtime/TestRunnerUtils.h
+++ b/Source/JavaScriptCore/runtime/TestRunnerUtils.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-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
@@ -30,11 +30,27 @@
namespace JSC {
+class CodeBlock;
+class FunctionExecutable;
+
+JS_EXPORT_PRIVATE FunctionExecutable* getExecutableForFunction(JSValue theFunctionValue);
+JS_EXPORT_PRIVATE CodeBlock* getSomeBaselineCodeBlockForFunction(JSValue theFunctionValue);
+
JS_EXPORT_PRIVATE JSValue numberOfDFGCompiles(JSValue function);
JS_EXPORT_PRIVATE JSValue setNeverInline(JSValue function);
+JS_EXPORT_PRIVATE JSValue setNeverOptimize(JSValue function);
+JS_EXPORT_PRIVATE JSValue optimizeNextInvocation(JSValue function);
+JS_EXPORT_PRIVATE JSValue failNextNewCodeBlock(ExecState*);
JS_EXPORT_PRIVATE JSValue numberOfDFGCompiles(ExecState*);
JS_EXPORT_PRIVATE JSValue setNeverInline(ExecState*);
+JS_EXPORT_PRIVATE JSValue setNeverOptimize(ExecState*);
+JS_EXPORT_PRIVATE JSValue optimizeNextInvocation(ExecState*);
+
+JS_EXPORT_PRIVATE unsigned numberOfExceptionFuzzChecks();
+JS_EXPORT_PRIVATE unsigned numberOfExecutableAllocationFuzzChecks();
+JS_EXPORT_PRIVATE unsigned numberOfStaticOSRExitFuzzChecks();
+JS_EXPORT_PRIVATE unsigned numberOfOSRExitFuzzChecks();
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Tracing.d b/Source/JavaScriptCore/runtime/Tracing.d
new file mode 100644
index 000000000..ec13625d8
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Tracing.d
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+provider JavaScriptCore
+{
+ probe gc__begin();
+ probe gc__marked();
+ probe gc__end();
+
+ probe profile__will_execute(int, char*, char*, int, int);
+ probe profile__did_execute(int, char*, char*, int, int);
+};
+
+#pragma D attributes Unstable/Unstable/Common provider JavaScriptCore provider
+#pragma D attributes Private/Private/Unknown provider JavaScriptCore module
+#pragma D attributes Private/Private/Unknown provider JavaScriptCore function
+#pragma D attributes Unstable/Unstable/Common provider JavaScriptCore name
+#pragma D attributes Unstable/Unstable/Common provider JavaScriptCore args
diff --git a/Source/JavaScriptCore/runtime/Tracing.h b/Source/JavaScriptCore/runtime/Tracing.h
index c28c85f61..69ead921c 100644
--- a/Source/JavaScriptCore/runtime/Tracing.h
+++ b/Source/JavaScriptCore/runtime/Tracing.h
@@ -39,10 +39,10 @@
#define JAVASCRIPTCORE_GC_MARKED()
#define JAVASCRIPTCORE_GC_MARKED_ENABLED() 0
-#define JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(arg0, arg1, arg2, arg3)
+#define JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(arg0, arg1, arg2, arg3, arg4)
#define JAVASCRIPTCORE_PROFILE_WILL_EXECUTE_ENABLED() 0
-#define JAVASCRIPTCORE_PROFILE_DID_EXECUTE(arg0, arg1, arg2, arg3)
+#define JAVASCRIPTCORE_PROFILE_DID_EXECUTE(arg0, arg1, arg2, arg3, arg4)
#define JAVASCRIPTCORE_PROFILE_DID_EXECUTE_ENABLED() 0
#endif
diff --git a/Source/JavaScriptCore/runtime/TypeLocationCache.cpp b/Source/JavaScriptCore/runtime/TypeLocationCache.cpp
new file mode 100644
index 000000000..4c8069a8c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TypeLocationCache.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 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.
+ */
+
+
+#include "config.h"
+#include "TypeLocationCache.h"
+
+#include "TypeProfiler.h"
+#include "VM.h"
+
+namespace JSC {
+
+std::pair<TypeLocation*, bool> TypeLocationCache::getTypeLocation(GlobalVariableID globalVariableID, intptr_t sourceID, unsigned start, unsigned end, PassRefPtr<TypeSet> globalTypeSet, VM* vm)
+{
+ LocationKey key;
+ key.m_globalVariableID = globalVariableID;
+ key.m_sourceID = sourceID;
+ key.m_start = start;
+ key.m_end = end;
+
+ bool isNewLocation = false;
+ if (m_locationMap.find(key) == m_locationMap.end()) {
+ ASSERT(vm->typeProfiler());
+ TypeLocation* location = vm->typeProfiler()->nextTypeLocation();
+ location->m_globalVariableID = globalVariableID;
+ location->m_sourceID = sourceID;
+ location->m_divotStart = start;
+ location->m_divotEnd = end;
+ location->m_globalTypeSet = globalTypeSet;
+
+ m_locationMap[key] = location;
+ isNewLocation = true;
+ }
+
+ TypeLocation* location = m_locationMap.find(key)->second;
+ return std::pair<TypeLocation*, bool>(location, isNewLocation);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/TypeLocationCache.h b/Source/JavaScriptCore/runtime/TypeLocationCache.h
new file mode 100644
index 000000000..9f856666c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TypeLocationCache.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef TypeLocationCache_h
+#define TypeLocationCache_h
+
+#include "TypeLocation.h"
+#include <unordered_map>
+#include <wtf/HashMethod.h>
+
+namespace JSC {
+
+class VM;
+
+class TypeLocationCache {
+public:
+ struct LocationKey {
+ LocationKey() {}
+ bool operator==(const LocationKey& other) const
+ {
+ return m_globalVariableID == other.m_globalVariableID
+ && m_sourceID == other.m_sourceID
+ && m_start == other.m_start
+ && m_end == other.m_end;
+ }
+
+ unsigned hash() const
+ {
+ return m_globalVariableID + m_sourceID + m_start + m_end;
+ }
+
+ GlobalVariableID m_globalVariableID;
+ intptr_t m_sourceID;
+ unsigned m_start;
+ unsigned m_end;
+ };
+
+ std::pair<TypeLocation*, bool> getTypeLocation(GlobalVariableID, intptr_t, unsigned start, unsigned end, PassRefPtr<TypeSet>, VM*);
+private:
+ typedef std::unordered_map<LocationKey, TypeLocation*, HashMethod<LocationKey>> LocationMap;
+ LocationMap m_locationMap;
+};
+
+} // namespace JSC
+
+#endif // TypeLocationCache_h
diff --git a/Source/JavaScriptCore/runtime/TypeProfiler.cpp b/Source/JavaScriptCore/runtime/TypeProfiler.cpp
new file mode 100644
index 000000000..ab974928b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TypeProfiler.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "config.h"
+#include "TypeProfiler.h"
+
+#include "InspectorProtocolObjects.h"
+#include "TypeLocation.h"
+#include <wtf/text/StringBuilder.h>
+
+namespace JSC {
+
+static const bool verbose = false;
+
+TypeProfiler::TypeProfiler()
+ : m_nextUniqueVariableID(1)
+{
+}
+
+void TypeProfiler::logTypesForTypeLocation(TypeLocation* location, VM& vm)
+{
+ TypeProfilerSearchDescriptor descriptor = location->m_globalVariableID == TypeProfilerReturnStatement ? TypeProfilerSearchDescriptorFunctionReturn : TypeProfilerSearchDescriptorNormal;
+
+ dataLogF("[Start, End]::[%u, %u]\n", location->m_divotStart, location->m_divotEnd);
+
+ if (findLocation(location->m_divotStart, location->m_sourceID, descriptor, vm))
+ dataLog("\t\t[Entry IS in System]\n");
+ else
+ dataLog("\t\t[Entry IS NOT in system]\n");
+
+ dataLog("\t\t", location->m_globalVariableID == TypeProfilerReturnStatement ? "[Return Statement]" : "[Normal Statement]", "\n");
+
+ dataLog("\t\t#Local#\n\t\t", location->m_instructionTypeSet->dumpTypes().replace("\n", "\n\t\t"), "\n");
+ if (location->m_globalTypeSet)
+ dataLog("\t\t#Global#\n\t\t", location->m_globalTypeSet->dumpTypes().replace("\n", "\n\t\t"), "\n");
+}
+
+void TypeProfiler::insertNewLocation(TypeLocation* location)
+{
+ if (verbose)
+ dataLogF("Registering location:: divotStart:%u, divotEnd:%u\n", location->m_divotStart, location->m_divotEnd);
+
+ if (!m_bucketMap.contains(location->m_sourceID)) {
+ Vector<TypeLocation*> bucket;
+ m_bucketMap.set(location->m_sourceID, bucket);
+ }
+
+ Vector<TypeLocation*>& bucket = m_bucketMap.find(location->m_sourceID)->value;
+ bucket.append(location);
+}
+
+String TypeProfiler::typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptor descriptor, unsigned offset, intptr_t sourceID, VM& vm)
+{
+ // This returns a JSON string representing an Object with the following properties:
+ // globalTypeSet: 'JSON<TypeSet> | null'
+ // instructionTypeSet: 'JSON<TypeSet>'
+
+ TypeLocation* location = findLocation(offset, sourceID, descriptor, vm);
+ ASSERT(location);
+
+ StringBuilder json;
+
+ json.append('{');
+
+ json.appendLiteral("\"globalTypeSet\":");
+ if (location->m_globalTypeSet && location->m_globalVariableID != TypeProfilerNoGlobalIDExists)
+ json.append(location->m_globalTypeSet->toJSONString());
+ else
+ json.appendLiteral("null");
+ json.append(',');
+
+ json.appendLiteral("\"instructionTypeSet\":");
+ json.append(location->m_instructionTypeSet->toJSONString());
+ json.append(',');
+
+ json.appendLiteral("\"isOverflown\":");
+ if (location->m_instructionTypeSet->isOverflown() || (location->m_globalTypeSet && location->m_globalTypeSet->isOverflown()))
+ json.appendLiteral("true");
+ else
+ json.appendLiteral("false");
+
+ json.append('}');
+
+ return json.toString();
+}
+
+TypeLocation* TypeProfiler::findLocation(unsigned divot, intptr_t sourceID, TypeProfilerSearchDescriptor descriptor, VM& vm)
+{
+ QueryKey queryKey(sourceID, divot, descriptor);
+ auto iter = m_queryCache.find(queryKey);
+ if (iter != m_queryCache.end())
+ return iter->value;
+
+ if (!vm.functionHasExecutedCache()->hasExecutedAtOffset(sourceID, divot))
+ return nullptr;
+
+ if (!m_bucketMap.contains(sourceID))
+ return nullptr;
+
+ Vector<TypeLocation*>& bucket = m_bucketMap.find(sourceID)->value;
+ TypeLocation* bestMatch = nullptr;
+ unsigned distance = UINT_MAX; // Because assignments may be nested, make sure we find the closest enclosing assignment to this character offset.
+ for (size_t i = 0, size = bucket.size(); i < size; i++) {
+ TypeLocation* location = bucket.at(i);
+ // We found the type location that correlates to the convergence of all return statements in a function.
+ // This text offset is the offset of the opening brace in a function declaration.
+ if (descriptor == TypeProfilerSearchDescriptorFunctionReturn && location->m_globalVariableID == TypeProfilerReturnStatement && location->m_divotForFunctionOffsetIfReturnStatement == divot)
+ return location;
+
+ if (descriptor != TypeProfilerSearchDescriptorFunctionReturn && location->m_globalVariableID != TypeProfilerReturnStatement && location->m_divotStart <= divot && divot <= location->m_divotEnd && location->m_divotEnd - location->m_divotStart <= distance) {
+ distance = location->m_divotEnd - location->m_divotStart;
+ bestMatch = location;
+ }
+ }
+
+ if (bestMatch)
+ m_queryCache.set(queryKey, bestMatch);
+ // FIXME: BestMatch should never be null past this point. This doesn't hold currently because we ignore var assignments when code contains eval/With (VarInjection).
+ // https://bugs.webkit.org/show_bug.cgi?id=135184
+ return bestMatch;
+}
+
+TypeLocation* TypeProfiler::nextTypeLocation()
+{
+ return m_typeLocationInfo.add();
+}
+
+void TypeProfiler::invalidateTypeSetCache()
+{
+ for (Bag<TypeLocation>::iterator iter = m_typeLocationInfo.begin(); !!iter; ++iter) {
+ TypeLocation* location = *iter;
+ location->m_instructionTypeSet->invalidateCache();
+ if (location->m_globalTypeSet)
+ location->m_globalTypeSet->invalidateCache();
+ }
+}
+
+void TypeProfiler::dumpTypeProfilerData(VM& vm)
+{
+ for (Bag<TypeLocation>::iterator iter = m_typeLocationInfo.begin(); !!iter; ++iter) {
+ TypeLocation* location = *iter;
+ logTypesForTypeLocation(location, vm);
+ }
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/TypeProfiler.h b/Source/JavaScriptCore/runtime/TypeProfiler.h
new file mode 100644
index 000000000..ee17ebd99
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TypeProfiler.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef TypeProfiler_h
+#define TypeProfiler_h
+
+#include "CodeBlock.h"
+#include "TypeLocation.h"
+#include "TypeLocationCache.h"
+#include <wtf/Bag.h>
+#include <wtf/HashMap.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace Inspector { namespace Protocol { namespace Runtime {
+class TypeDescription;
+}}}
+
+namespace JSC {
+
+enum TypeProfilerSearchDescriptor {
+ TypeProfilerSearchDescriptorNormal = 1,
+ TypeProfilerSearchDescriptorFunctionReturn = 2
+};
+
+struct QueryKey {
+ QueryKey()
+ : m_sourceID(0)
+ , m_divot(0)
+ , m_searchDescriptor(TypeProfilerSearchDescriptorFunctionReturn)
+ { }
+
+ QueryKey(intptr_t sourceID, unsigned divot, TypeProfilerSearchDescriptor searchDescriptor)
+ : m_sourceID(sourceID)
+ , m_divot(divot)
+ , m_searchDescriptor(searchDescriptor)
+ { }
+
+ QueryKey(WTF::HashTableDeletedValueType)
+ : m_sourceID(INTPTR_MAX)
+ , m_divot(UINT_MAX)
+ , m_searchDescriptor(TypeProfilerSearchDescriptorFunctionReturn)
+ { }
+
+ bool isHashTableDeletedValue() const
+ {
+ return m_sourceID == INTPTR_MAX
+ && m_divot == UINT_MAX
+ && m_searchDescriptor == TypeProfilerSearchDescriptorFunctionReturn;
+ }
+
+ bool operator==(const QueryKey& other) const
+ {
+ return m_sourceID == other.m_sourceID
+ && m_divot == other.m_divot
+ && m_searchDescriptor == other.m_searchDescriptor;
+ }
+
+ unsigned hash() const
+ {
+ unsigned hash = m_sourceID + m_divot * m_searchDescriptor;
+ return hash;
+ }
+
+ intptr_t m_sourceID;
+ unsigned m_divot;
+ TypeProfilerSearchDescriptor m_searchDescriptor;
+};
+
+struct QueryKeyHash {
+ static unsigned hash(const QueryKey& key) { return key.hash(); }
+ static bool equal(const QueryKey& a, const QueryKey& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+} // namespace JSC
+
+namespace WTF {
+
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::QueryKey> {
+ typedef JSC::QueryKeyHash Hash;
+};
+
+template<typename T> struct HashTraits;
+template<> struct HashTraits<JSC::QueryKey> : SimpleClassHashTraits<JSC::QueryKey> {
+ static const bool emptyValueIsZero = false;
+};
+
+} // namespace WTF
+
+namespace JSC {
+
+class VM;
+
+class TypeProfiler {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ TypeProfiler();
+ void logTypesForTypeLocation(TypeLocation*, VM&);
+ JS_EXPORT_PRIVATE String typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptor, unsigned offset, intptr_t sourceID, VM&);
+ void insertNewLocation(TypeLocation*);
+ TypeLocationCache* typeLocationCache() { return &m_typeLocationCache; }
+ TypeLocation* findLocation(unsigned divot, intptr_t sourceID, TypeProfilerSearchDescriptor, VM&);
+ GlobalVariableID getNextUniqueVariableID() { return m_nextUniqueVariableID++; }
+ TypeLocation* nextTypeLocation();
+ void invalidateTypeSetCache();
+ void dumpTypeProfilerData(VM&);
+
+private:
+ typedef HashMap<intptr_t, Vector<TypeLocation*>> SourceIDToLocationBucketMap;
+ SourceIDToLocationBucketMap m_bucketMap;
+ TypeLocationCache m_typeLocationCache;
+ typedef HashMap<QueryKey, TypeLocation*> TypeLocationQueryCache;
+ TypeLocationQueryCache m_queryCache;
+ GlobalVariableID m_nextUniqueVariableID;
+ Bag<TypeLocation> m_typeLocationInfo;
+};
+
+} // namespace JSC
+
+#endif // TypeProfiler_h
diff --git a/Source/JavaScriptCore/runtime/TypeProfilerLog.cpp b/Source/JavaScriptCore/runtime/TypeProfilerLog.cpp
new file mode 100644
index 000000000..9d10aae88
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TypeProfilerLog.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 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.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "TypeProfilerLog.h"
+
+#include "JSCJSValueInlines.h"
+#include "TypeLocation.h"
+#include <wtf/CurrentTime.h>
+
+
+namespace JSC {
+
+static const bool verbose = false;
+
+void TypeProfilerLog::initializeLog()
+{
+ ASSERT(!m_logStartPtr);
+ m_logSize = 50000;
+ m_logStartPtr = new LogEntry[m_logSize];
+ m_currentLogEntryPtr = m_logStartPtr;
+ m_logEndPtr = m_logStartPtr + m_logSize;
+}
+
+TypeProfilerLog::~TypeProfilerLog()
+{
+ delete[] m_logStartPtr;
+}
+
+void TypeProfilerLog::processLogEntries(const String& reason)
+{
+ double before = 0;
+ if (verbose) {
+ dataLog("Process caller:'", reason, "'");
+ before = currentTimeMS();
+ }
+
+ LogEntry* entry = m_logStartPtr;
+ HashMap<Structure*, RefPtr<StructureShape>> seenShapes;
+ while (entry != m_currentLogEntryPtr) {
+ StructureID id = entry->structureID;
+ RefPtr<StructureShape> shape;
+ JSValue value = entry->value;
+ Structure* structure = nullptr;
+ if (id) {
+ structure = Heap::heap(value.asCell())->structureIDTable().get(id);
+ auto iter = seenShapes.find(structure);
+ if (iter == seenShapes.end()) {
+ shape = structure->toStructureShape(value);
+ seenShapes.set(structure, shape);
+ } else
+ shape = iter->value;
+ }
+
+ RuntimeType type = runtimeTypeForValue(value);
+ TypeLocation* location = entry->location;
+ location->m_lastSeenType = type;
+ if (location->m_globalTypeSet)
+ location->m_globalTypeSet->addTypeInformation(type, shape, structure);
+ location->m_instructionTypeSet->addTypeInformation(type, shape, structure);
+
+ entry++;
+ }
+
+ m_currentLogEntryPtr = m_logStartPtr;
+
+ if (verbose) {
+ double after = currentTimeMS();
+ dataLogF(" Processing the log took: '%f' ms\n", after - before);
+ }
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.h b/Source/JavaScriptCore/runtime/TypeProfilerLog.h
index 9bbb39196..1dd188ab7 100644
--- a/Source/JavaScriptCore/runtime/JSVariableObject.h
+++ b/Source/JavaScriptCore/runtime/TypeProfilerLog.h
@@ -1,18 +1,18 @@
/*
- * Copyright (C) 2007, 2008, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 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.
+ * 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.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * documentation and/or other materials provided with the distribution.
+ * 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.
+ * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -26,51 +26,59 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef JSVariableObject_h
-#define JSVariableObject_h
+#ifndef TypeProfilerLog_h
+#define TypeProfilerLog_h
-#include "JSObject.h"
-#include "JSSymbolTableObject.h"
-#include "Register.h"
-#include "SymbolTable.h"
+#include "JSCJSValue.h"
+#include "Structure.h"
+#include "TypeProfiler.h"
namespace JSC {
-class LLIntOffsetsExtractor;
-class Register;
-
-class JSVariableObject : public JSSymbolTableObject {
- friend class JIT;
- friend class LLIntOffsetsExtractor;
+class TypeLocation;
+class TypeProfilerLog {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- typedef JSSymbolTableObject Base;
-
- WriteBarrierBase<Unknown>* registers() { return m_registers; }
- WriteBarrierBase<Unknown>& registerAt(int index) const { return m_registers[index]; }
+ struct LogEntry {
+ public:
+ friend class LLIntOffsetsExtractor;
- WriteBarrierBase<Unknown>* const * addressOfRegisters() const { return &m_registers; }
- static size_t offsetOfRegisters() { return OBJECT_OFFSETOF(JSVariableObject, m_registers); }
+ JSValue value;
+ TypeLocation* location;
+ StructureID structureID;
- DECLARE_INFO;
+ static ptrdiff_t structureIDOffset() { return OBJECT_OFFSETOF(LogEntry, structureID); }
+ static ptrdiff_t valueOffset() { return OBJECT_OFFSETOF(LogEntry, value); }
+ static ptrdiff_t locationOffset() { return OBJECT_OFFSETOF(LogEntry, location); }
+ };
-protected:
- static const unsigned StructureFlags = Base::StructureFlags;
- JSVariableObject(
- VM& vm,
- Structure* structure,
- Register* registers,
- JSScope* scope,
- SymbolTable* symbolTable = 0)
- : Base(vm, structure, scope, symbolTable)
- , m_registers(reinterpret_cast<WriteBarrierBase<Unknown>*>(registers))
+ TypeProfilerLog()
+ : m_logStartPtr(0)
{
+ initializeLog();
}
- WriteBarrierBase<Unknown>* m_registers; // "r" in the stack.
+ ~TypeProfilerLog();
+
+ JS_EXPORT_PRIVATE void processLogEntries(const String&);
+ LogEntry* logEndPtr() const { return m_logEndPtr; }
+
+ static ptrdiff_t logStartOffset() { return OBJECT_OFFSETOF(TypeProfilerLog, m_logStartPtr); }
+ static ptrdiff_t currentLogEntryOffset() { return OBJECT_OFFSETOF(TypeProfilerLog, m_currentLogEntryPtr); }
+
+private:
+ friend class LLIntOffsetsExtractor;
+
+ void initializeLog();
+
+ unsigned m_logSize;
+ LogEntry* m_logStartPtr;
+ LogEntry* m_currentLogEntryPtr;
+ LogEntry* m_logEndPtr;
};
} // namespace JSC
-#endif // JSVariableObject_h
+#endif // TypeProfilerLog_h
diff --git a/Source/JavaScriptCore/runtime/TypeSet.cpp b/Source/JavaScriptCore/runtime/TypeSet.cpp
new file mode 100644
index 000000000..a5ec952d7
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TypeSet.cpp
@@ -0,0 +1,587 @@
+/*
+ * Copyright (C) 2014, 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.
+ */
+
+#include "config.h"
+#include "TypeSet.h"
+
+#include "InspectorProtocolObjects.h"
+#include "JSCJSValue.h"
+#include "JSCJSValueInlines.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+TypeSet::TypeSet()
+ : m_seenTypes(TypeNothing)
+ , m_isOverflown(false)
+{
+}
+
+void TypeSet::addTypeInformation(RuntimeType type, PassRefPtr<StructureShape> prpNewShape, Structure* structure)
+{
+ RefPtr<StructureShape> newShape = prpNewShape;
+ m_seenTypes = m_seenTypes | type;
+
+ if (structure && newShape && !runtimeTypeIsPrimitive(type)) {
+ if (!m_structureSet.contains(structure)) {
+ m_structureSet.add(structure);
+ // Make one more pass making sure that:
+ // - We don't have two instances of the same shape. (Same shapes may have different Structures).
+ // - We don't have two shapes that share the same prototype chain. If these shapes share the same
+ // prototype chain, they will be merged into one shape.
+ bool found = false;
+ String hash = newShape->propertyHash();
+ for (size_t i = 0; i < m_structureHistory.size(); i++) {
+ RefPtr<StructureShape>& seenShape = m_structureHistory.at(i);
+ if (seenShape->propertyHash() == hash) {
+ found = true;
+ break;
+ }
+ if (seenShape->hasSamePrototypeChain(newShape)) {
+ seenShape = StructureShape::merge(seenShape, newShape);
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ if (m_structureHistory.size() < 100)
+ m_structureHistory.append(newShape);
+ else if (!m_isOverflown)
+ m_isOverflown = true;
+ }
+ }
+ }
+}
+
+void TypeSet::invalidateCache()
+{
+ auto keepMarkedStructuresFilter = [] (Structure* structure) -> bool { return Heap::isMarked(structure); };
+ m_structureSet.genericFilter(keepMarkedStructuresFilter);
+}
+
+String TypeSet::dumpTypes() const
+{
+ if (m_seenTypes == TypeNothing)
+ return ASCIILiteral("(Unreached Statement)");
+
+ StringBuilder seen;
+
+ if (m_seenTypes & TypeFunction)
+ seen.appendLiteral("Function ");
+ if (m_seenTypes & TypeUndefined)
+ seen.appendLiteral("Undefined ");
+ if (m_seenTypes & TypeNull)
+ seen.appendLiteral("Null ");
+ if (m_seenTypes & TypeBoolean)
+ seen.appendLiteral("Boolean ");
+ if (m_seenTypes & TypeMachineInt)
+ seen.appendLiteral("MachineInt ");
+ if (m_seenTypes & TypeNumber)
+ seen.appendLiteral("Number ");
+ if (m_seenTypes & TypeString)
+ seen.appendLiteral("String ");
+ if (m_seenTypes & TypeObject)
+ seen.appendLiteral("Object ");
+ if (m_seenTypes & TypeSymbol)
+ seen.appendLiteral("Symbol ");
+
+ for (size_t i = 0; i < m_structureHistory.size(); i++) {
+ RefPtr<StructureShape> shape = m_structureHistory.at(i);
+ seen.append(shape->m_constructorName);
+ seen.append(' ');
+ }
+
+ if (m_structureHistory.size())
+ seen.appendLiteral("\nStructures:[ ");
+ for (size_t i = 0; i < m_structureHistory.size(); i++) {
+ seen.append(m_structureHistory.at(i)->stringRepresentation());
+ seen.append(' ');
+ }
+ if (m_structureHistory.size())
+ seen.append(']');
+
+ if (m_structureHistory.size()) {
+ seen.appendLiteral("\nLeast Common Ancestor: ");
+ seen.append(leastCommonAncestor());
+ }
+
+ return seen.toString();
+}
+
+bool TypeSet::doesTypeConformTo(RuntimeTypeMask test) const
+{
+ // This function checks if our seen types conform to the types described by the test bitstring. (i.e we haven't seen more types than test).
+ // We are <= to those types if ANDing with the bitstring doesn't zero out any of our bits.
+
+ // For example:
+
+ // 0b0110 (seen)
+ // 0b1111 (test)
+ // ------ (AND)
+ // 0b0110 == seen
+
+ // 0b0110 (seen)
+ // 0b0010 (test)
+ // ------ (AND)
+ // 0b0010 != seen
+
+ return m_seenTypes != TypeNothing && (m_seenTypes & test) == m_seenTypes;
+}
+
+String TypeSet::displayName() const
+{
+ if (m_seenTypes == TypeNothing)
+ return emptyString();
+
+ if (m_structureHistory.size() && doesTypeConformTo(TypeObject | TypeNull | TypeUndefined)) {
+ String ctorName = leastCommonAncestor();
+
+ if (doesTypeConformTo(TypeObject))
+ return ctorName;
+ if (doesTypeConformTo(TypeObject | TypeNull | TypeUndefined))
+ return ctorName + '?';
+ }
+
+ // The order of these checks are important. For example, if a value is only a function, it conforms to TypeFunction, but it also conforms to TypeFunction | TypeNull.
+ // Therefore, more specific types must be checked first.
+
+ if (doesTypeConformTo(TypeFunction))
+ return ASCIILiteral("Function");
+ if (doesTypeConformTo(TypeUndefined))
+ return ASCIILiteral("Undefined");
+ if (doesTypeConformTo(TypeNull))
+ return ASCIILiteral("Null");
+ if (doesTypeConformTo(TypeBoolean))
+ return ASCIILiteral("Boolean");
+ if (doesTypeConformTo(TypeMachineInt))
+ return ASCIILiteral("Integer");
+ if (doesTypeConformTo(TypeNumber | TypeMachineInt))
+ return ASCIILiteral("Number");
+ if (doesTypeConformTo(TypeString))
+ return ASCIILiteral("String");
+ if (doesTypeConformTo(TypeSymbol))
+ return ASCIILiteral("Symbol");
+
+ if (doesTypeConformTo(TypeNull | TypeUndefined))
+ return ASCIILiteral("(?)");
+
+ if (doesTypeConformTo(TypeFunction | TypeNull | TypeUndefined))
+ return ASCIILiteral("Function?");
+ if (doesTypeConformTo(TypeBoolean | TypeNull | TypeUndefined))
+ return ASCIILiteral("Boolean?");
+ if (doesTypeConformTo(TypeMachineInt | TypeNull | TypeUndefined))
+ return ASCIILiteral("Integer?");
+ if (doesTypeConformTo(TypeNumber | TypeMachineInt | TypeNull | TypeUndefined))
+ return ASCIILiteral("Number?");
+ if (doesTypeConformTo(TypeString | TypeNull | TypeUndefined))
+ return ASCIILiteral("String?");
+ if (doesTypeConformTo(TypeSymbol | TypeNull | TypeUndefined))
+ return ASCIILiteral("Symbol?");
+
+ if (doesTypeConformTo(TypeObject | TypeFunction | TypeString))
+ return ASCIILiteral("Object");
+ if (doesTypeConformTo(TypeObject | TypeFunction | TypeString | TypeNull | TypeUndefined))
+ return ASCIILiteral("Object?");
+
+ return ASCIILiteral("(many)");
+}
+
+String TypeSet::leastCommonAncestor() const
+{
+ return StructureShape::leastCommonAncestor(m_structureHistory);
+}
+
+Ref<Inspector::Protocol::Array<Inspector::Protocol::Runtime::StructureDescription>> TypeSet::allStructureRepresentations() const
+{
+ auto description = Inspector::Protocol::Array<Inspector::Protocol::Runtime::StructureDescription>::create();
+
+ for (size_t i = 0; i < m_structureHistory.size(); i++)
+ description->addItem(m_structureHistory.at(i)->inspectorRepresentation());
+
+ return description;
+}
+
+Ref<Inspector::Protocol::Runtime::TypeSet> TypeSet::inspectorTypeSet() const
+{
+ return Inspector::Protocol::Runtime::TypeSet::create()
+ .setIsFunction((m_seenTypes & TypeFunction) != TypeNothing)
+ .setIsUndefined((m_seenTypes & TypeUndefined) != TypeNothing)
+ .setIsNull((m_seenTypes & TypeNull) != TypeNothing)
+ .setIsBoolean((m_seenTypes & TypeBoolean) != TypeNothing)
+ .setIsInteger((m_seenTypes & TypeMachineInt) != TypeNothing)
+ .setIsNumber((m_seenTypes & TypeNumber) != TypeNothing)
+ .setIsString((m_seenTypes & TypeString) != TypeNothing)
+ .setIsObject((m_seenTypes & TypeObject) != TypeNothing)
+ .setIsSymbol((m_seenTypes & TypeSymbol) != TypeNothing)
+ .release();
+}
+
+String TypeSet::toJSONString() const
+{
+ // This returns a JSON string representing an Object with the following properties:
+ // displayTypeName: 'String'
+ // primitiveTypeNames: 'Array<String>'
+ // structures: 'Array<JSON<StructureShape>>'
+
+ StringBuilder json;
+ json.append('{');
+
+ json.appendLiteral("\"displayTypeName\":");
+ json.append('"');
+ json.append(displayName());
+ json.append('"');
+ json.append(',');
+
+ json.appendLiteral("\"primitiveTypeNames\":");
+ json.append('[');
+ bool hasAnItem = false;
+ if (m_seenTypes & TypeUndefined) {
+ hasAnItem = true;
+ json.appendLiteral("\"Undefined\"");
+ }
+ if (m_seenTypes & TypeNull) {
+ if (hasAnItem)
+ json.append(',');
+ hasAnItem = true;
+ json.appendLiteral("\"Null\"");
+ }
+ if (m_seenTypes & TypeBoolean) {
+ if (hasAnItem)
+ json.append(',');
+ hasAnItem = true;
+ json.appendLiteral("\"Boolean\"");
+ }
+ if (m_seenTypes & TypeMachineInt) {
+ if (hasAnItem)
+ json.append(',');
+ hasAnItem = true;
+ json.appendLiteral("\"Integer\"");
+ }
+ if (m_seenTypes & TypeNumber) {
+ if (hasAnItem)
+ json.append(',');
+ hasAnItem = true;
+ json.appendLiteral("\"Number\"");
+ }
+ if (m_seenTypes & TypeString) {
+ if (hasAnItem)
+ json.append(',');
+ hasAnItem = true;
+ json.appendLiteral("\"String\"");
+ }
+ if (m_seenTypes & TypeSymbol) {
+ if (hasAnItem)
+ json.append(',');
+ hasAnItem = true;
+ json.appendLiteral("\"Symbol\"");
+ }
+ json.append(']');
+
+ json.append(',');
+
+ json.appendLiteral("\"structures\":");
+ json.append('[');
+ hasAnItem = false;
+ for (size_t i = 0; i < m_structureHistory.size(); i++) {
+ if (hasAnItem)
+ json.append(',');
+ hasAnItem = true;
+ json.append(m_structureHistory[i]->toJSONString());
+ }
+ json.append(']');
+
+ json.append('}');
+ return json.toString();
+}
+
+StructureShape::StructureShape()
+ : m_proto(nullptr)
+ , m_propertyHash(nullptr)
+ , m_final(false)
+ , m_isInDictionaryMode(false)
+{
+}
+
+void StructureShape::markAsFinal()
+{
+ ASSERT(!m_final);
+ m_final = true;
+}
+
+void StructureShape::addProperty(UniquedStringImpl& uid)
+{
+ ASSERT(!m_final);
+ m_fields.add(&uid);
+}
+
+String StructureShape::propertyHash()
+{
+ ASSERT(m_final);
+ if (m_propertyHash)
+ return *m_propertyHash;
+
+ StringBuilder builder;
+ builder.append(':');
+ builder.append(m_constructorName);
+ builder.append(':');
+ for (auto& key : m_fields) {
+ String property = key.get();
+ property.replace(":", "\\:"); // Ensure that hash({"foo:", "bar"}) != hash({"foo", ":bar"}) because we're using colons as a separator and colons are legal characters in field names in JS.
+ builder.append(property);
+ }
+
+ if (m_proto) {
+ builder.append(':');
+ builder.appendLiteral("__proto__");
+ builder.append(m_proto->propertyHash());
+ }
+
+ m_propertyHash = std::make_unique<String>(builder.toString());
+ return *m_propertyHash;
+}
+
+String StructureShape::leastCommonAncestor(const Vector<RefPtr<StructureShape>> shapes)
+{
+ if (!shapes.size())
+ return emptyString();
+
+ RefPtr<StructureShape> origin = shapes.at(0);
+ for (size_t i = 1; i < shapes.size(); i++) {
+ bool foundLUB = false;
+ while (!foundLUB) {
+ RefPtr<StructureShape> check = shapes.at(i);
+ String curCtorName = origin->m_constructorName;
+ while (check) {
+ if (check->m_constructorName == curCtorName) {
+ foundLUB = true;
+ break;
+ }
+ check = check->m_proto;
+ }
+ if (!foundLUB) {
+ origin = origin->m_proto;
+ // All Objects must share the 'Object' Prototype. Therefore, at the very least, we should always converge on 'Object' before reaching a null prototype.
+ RELEASE_ASSERT(origin);
+ }
+ }
+
+ if (origin->m_constructorName == "Object")
+ break;
+ }
+
+ return origin->m_constructorName;
+}
+
+String StructureShape::stringRepresentation()
+{
+ StringBuilder representation;
+ RefPtr<StructureShape> curShape = this;
+
+ representation.append('{');
+ while (curShape) {
+ for (auto it = curShape->m_fields.begin(), end = curShape->m_fields.end(); it != end; ++it) {
+ String prop((*it).get());
+ representation.append(prop);
+ representation.appendLiteral(", ");
+ }
+
+ if (curShape->m_proto) {
+ representation.appendLiteral("__proto__ [");
+ representation.append(curShape->m_proto->m_constructorName);
+ representation.appendLiteral("], ");
+ }
+
+ curShape = curShape->m_proto;
+ }
+
+ if (representation.length() >= 3)
+ representation.resize(representation.length() - 2);
+
+ representation.append('}');
+
+ return representation.toString();
+}
+
+String StructureShape::toJSONString() const
+{
+ // This returns a JSON string representing an Object with the following properties:
+ // constructorName: 'String'
+ // fields: 'Array<String>'
+ // optionalFields: 'Array<String>'
+ // proto: 'JSON<StructureShape> | null'
+
+ StringBuilder json;
+ json.append('{');
+
+ json.appendLiteral("\"constructorName\":");
+ json.append('"');
+ json.append(m_constructorName);
+ json.append('"');
+ json.append(',');
+
+ json.appendLiteral("\"isInDictionaryMode\":");
+ if (m_isInDictionaryMode)
+ json.appendLiteral("true");
+ else
+ json.appendLiteral("false");
+ json.append(',');
+
+ json.appendLiteral("\"fields\":");
+ json.append('[');
+ bool hasAnItem = false;
+ for (auto it = m_fields.begin(), end = m_fields.end(); it != end; ++it) {
+ if (hasAnItem)
+ json.append(',');
+ hasAnItem = true;
+
+ String fieldName((*it).get());
+ json.append('"');
+ json.append(fieldName);
+ json.append('"');
+ }
+ json.append(']');
+ json.append(',');
+
+ json.appendLiteral("\"optionalFields\":");
+ json.append('[');
+ hasAnItem = false;
+ for (auto it = m_optionalFields.begin(), end = m_optionalFields.end(); it != end; ++it) {
+ if (hasAnItem)
+ json.append(',');
+ hasAnItem = true;
+
+ String fieldName((*it).get());
+ json.append('"');
+ json.append(fieldName);
+ json.append('"');
+ }
+ json.append(']');
+ json.append(',');
+
+ json.appendLiteral("\"proto\":");
+ if (m_proto)
+ json.append(m_proto->toJSONString());
+ else
+ json.appendLiteral("null");
+
+ json.append('}');
+
+ return json.toString();
+}
+
+Ref<Inspector::Protocol::Runtime::StructureDescription> StructureShape::inspectorRepresentation()
+{
+ auto base = Inspector::Protocol::Runtime::StructureDescription::create().release();
+ Ref<Inspector::Protocol::Runtime::StructureDescription> currentObject = base.copyRef();
+ RefPtr<StructureShape> currentShape(this);
+
+ while (currentShape) {
+ auto fields = Inspector::Protocol::Array<String>::create();
+ auto optionalFields = Inspector::Protocol::Array<String>::create();
+ for (auto field : currentShape->m_fields)
+ fields->addItem(field.get());
+ for (auto field : currentShape->m_optionalFields)
+ optionalFields->addItem(field.get());
+
+ currentObject->setFields(&fields.get());
+ currentObject->setOptionalFields(&optionalFields.get());
+ currentObject->setConstructorName(currentShape->m_constructorName);
+ currentObject->setIsImprecise(currentShape->m_isInDictionaryMode);
+
+ if (currentShape->m_proto) {
+ auto nextObject = Inspector::Protocol::Runtime::StructureDescription::create().release();
+ currentObject->setPrototypeStructure(&nextObject.get());
+ currentObject = WTFMove(nextObject);
+ }
+
+ currentShape = currentShape->m_proto;
+ }
+
+ return base;
+}
+
+bool StructureShape::hasSamePrototypeChain(PassRefPtr<StructureShape> prpOther)
+{
+ RefPtr<StructureShape> self = this;
+ RefPtr<StructureShape> other = prpOther;
+ while (self && other) {
+ if (self->m_constructorName != other->m_constructorName)
+ return false;
+ self = self->m_proto;
+ other = other->m_proto;
+ }
+
+ return !self && !other;
+}
+
+PassRefPtr<StructureShape> StructureShape::merge(const PassRefPtr<StructureShape> prpA, const PassRefPtr<StructureShape> prpB)
+{
+ RefPtr<StructureShape> a = prpA;
+ RefPtr<StructureShape> b = prpB;
+ ASSERT(a->hasSamePrototypeChain(b));
+
+ RefPtr<StructureShape> merged = StructureShape::create();
+ for (auto field : a->m_fields) {
+ if (b->m_fields.contains(field))
+ merged->m_fields.add(field);
+ else
+ merged->m_optionalFields.add(field);
+ }
+
+ for (auto field : b->m_fields) {
+ if (!merged->m_fields.contains(field)) {
+ auto addResult = merged->m_optionalFields.add(field);
+ ASSERT_UNUSED(addResult, addResult.isNewEntry);
+ }
+ }
+
+ for (auto field : a->m_optionalFields)
+ merged->m_optionalFields.add(field);
+ for (auto field : b->m_optionalFields)
+ merged->m_optionalFields.add(field);
+
+ ASSERT(a->m_constructorName == b->m_constructorName);
+ merged->setConstructorName(a->m_constructorName);
+
+ if (a->m_proto) {
+ RELEASE_ASSERT(b->m_proto);
+ merged->setProto(StructureShape::merge(a->m_proto, b->m_proto));
+ }
+
+ merged->markAsFinal();
+
+ return merged.release();
+}
+
+void StructureShape::enterDictionaryMode()
+{
+ m_isInDictionaryMode = true;
+}
+
+} //namespace JSC
diff --git a/Source/JavaScriptCore/runtime/TypeSet.h b/Source/JavaScriptCore/runtime/TypeSet.h
new file mode 100644
index 000000000..eb29e6c5f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TypeSet.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008, 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.
+ */
+
+#ifndef TypeSet_h
+#define TypeSet_h
+
+#include "RuntimeType.h"
+#include "StructureSet.h"
+#include <wtf/HashSet.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/WTFString.h>
+#include <wtf/Vector.h>
+
+namespace Inspector {
+namespace Protocol {
+template<typename T> class Array;
+
+namespace Runtime {
+class StructureDescription;
+class TypeSet;
+}
+
+}
+}
+
+namespace JSC {
+
+class StructureShape : public RefCounted<StructureShape> {
+ friend class TypeSet;
+
+public:
+ StructureShape();
+
+ static Ref<StructureShape> create() { return adoptRef(*new StructureShape); }
+ String propertyHash();
+ void markAsFinal();
+ void addProperty(UniquedStringImpl&);
+ String stringRepresentation();
+ String toJSONString() const;
+ Ref<Inspector::Protocol::Runtime::StructureDescription> inspectorRepresentation();
+ void setConstructorName(String name) { m_constructorName = (name.isEmpty() ? "Object" : name); }
+ String constructorName() { return m_constructorName; }
+ void setProto(PassRefPtr<StructureShape> shape) { m_proto = shape; }
+ void enterDictionaryMode();
+
+private:
+ static String leastCommonAncestor(const Vector<RefPtr<StructureShape>>);
+ static PassRefPtr<StructureShape> merge(const PassRefPtr<StructureShape>, const PassRefPtr<StructureShape>);
+ bool hasSamePrototypeChain(PassRefPtr<StructureShape>);
+
+ HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> m_fields;
+ HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> m_optionalFields;
+ RefPtr<StructureShape> m_proto;
+ std::unique_ptr<String> m_propertyHash;
+ String m_constructorName;
+ bool m_final;
+ bool m_isInDictionaryMode;
+};
+
+class TypeSet : public RefCounted<TypeSet> {
+
+public:
+ static Ref<TypeSet> create() { return adoptRef(*new TypeSet); }
+ TypeSet();
+ void addTypeInformation(RuntimeType, PassRefPtr<StructureShape>, Structure*);
+ void invalidateCache();
+ String dumpTypes() const;
+ String displayName() const;
+ Ref<Inspector::Protocol::Array<Inspector::Protocol::Runtime::StructureDescription>> allStructureRepresentations() const;
+ String toJSONString() const;
+ bool isOverflown() const { return m_isOverflown; }
+ String leastCommonAncestor() const;
+ Ref<Inspector::Protocol::Runtime::TypeSet> inspectorTypeSet() const;
+ bool isEmpty() const { return m_seenTypes == TypeNothing; }
+ bool doesTypeConformTo(RuntimeTypeMask test) const;
+ RuntimeTypeMask seenTypes() const { return m_seenTypes; }
+ StructureSet structureSet() const { return m_structureSet; };
+
+private:
+ RuntimeTypeMask m_seenTypes;
+ bool m_isOverflown;
+ Vector<RefPtr<StructureShape>> m_structureHistory;
+ StructureSet m_structureSet;
+};
+
+} //namespace JSC
+
+#endif //TypeSet_h
diff --git a/Source/JavaScriptCore/runtime/TypedArrayAdaptors.h b/Source/JavaScriptCore/runtime/TypedArrayAdaptors.h
index 84d3db5e1..d4dc53557 100644
--- a/Source/JavaScriptCore/runtime/TypedArrayAdaptors.h
+++ b/Source/JavaScriptCore/runtime/TypedArrayAdaptors.h
@@ -89,9 +89,7 @@ struct FloatTypedArrayAdaptor {
static JSValue toJSValue(Type value)
{
- if (value != value)
- return jsDoubleNumber(QNaN);
- return jsDoubleNumber(value);
+ return jsDoubleNumber(purifyNaN(value));
}
static double toDouble(Type value)
diff --git a/Source/JavaScriptCore/runtime/TypedArrayBase.h b/Source/JavaScriptCore/runtime/TypedArrayBase.h
index 4fe7a6c1a..ee2746d78 100644
--- a/Source/JavaScriptCore/runtime/TypedArrayBase.h
+++ b/Source/JavaScriptCore/runtime/TypedArrayBase.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
@@ -94,7 +94,7 @@ protected:
RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(length, sizeof(T));
if (!buffer.get())
return 0;
- return create<Subclass>(buffer, 0, length);
+ return create<Subclass>(buffer.release(), 0, length);
}
template <class Subclass>
@@ -104,30 +104,30 @@ protected:
if (a)
for (unsigned i = 0; i < length; ++i)
a->set(i, array[i]);
- return a;
+ return a.release();
}
template <class Subclass>
- static PassRefPtr<Subclass> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
+ static RefPtr<Subclass> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length)
{
RefPtr<ArrayBuffer> buf(buffer);
if (!verifySubRange<T>(buf, byteOffset, length))
- return 0;
+ return nullptr;
- return adoptRef(new Subclass(buf, byteOffset, length));
+ return adoptRef(new Subclass(buf.release(), byteOffset, length));
}
template <class Subclass>
- static PassRefPtr<Subclass> createUninitialized(unsigned length)
+ static RefPtr<Subclass> createUninitialized(unsigned length)
{
RefPtr<ArrayBuffer> buffer = ArrayBuffer::createUninitialized(length, sizeof(T));
if (!buffer.get())
- return 0;
- return create<Subclass>(buffer, 0, length);
+ return nullptr;
+ return create<Subclass>(buffer.release(), 0, length);
}
template <class Subclass>
- PassRefPtr<Subclass> subarrayImpl(int start, int end) const
+ RefPtr<Subclass> subarrayImpl(int start, int end) const
{
unsigned offset, length;
calculateOffsetAndLength(start, end, m_length, &offset, &length);
diff --git a/Source/JavaScriptCore/runtime/TypedArrayType.cpp b/Source/JavaScriptCore/runtime/TypedArrayType.cpp
index 46d505137..60875a209 100644
--- a/Source/JavaScriptCore/runtime/TypedArrayType.cpp
+++ b/Source/JavaScriptCore/runtime/TypedArrayType.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
@@ -32,34 +32,37 @@
namespace JSC {
-const ClassInfo* classInfoForType(TypedArrayType type)
+JSType typeForTypedArrayType(TypedArrayType type)
{
switch (type) {
case NotTypedArray:
- return 0;
+ RELEASE_ASSERT_NOT_REACHED();
+ return UnspecifiedType;
case TypeInt8:
- return JSInt8Array::info();
+ return Int8ArrayType;
case TypeUint8:
- return JSUint8Array::info();
+ return Uint8ArrayType;
case TypeUint8Clamped:
- return JSUint8ClampedArray::info();
+ return Uint8ClampedArrayType;
case TypeInt16:
- return JSInt16Array::info();
+ return Int16ArrayType;
case TypeUint16:
- return JSUint16Array::info();
+ return Uint16ArrayType;
case TypeInt32:
- return JSInt32Array::info();
+ return Int32ArrayType;
case TypeUint32:
- return JSUint32Array::info();
+ return Uint32ArrayType;
case TypeFloat32:
- return JSFloat32Array::info();
+ return Float32ArrayType;
case TypeFloat64:
- return JSFloat64Array::info();
+ return Float64ArrayType;
case TypeDataView:
- return JSDataView::info();
+ return DataViewType;
+
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return UnspecifiedType;
}
- RELEASE_ASSERT_NOT_REACHED();
- return 0;
}
const ClassInfo* constructorClassInfoForType(TypedArrayType type)
diff --git a/Source/JavaScriptCore/runtime/TypedArrayType.h b/Source/JavaScriptCore/runtime/TypedArrayType.h
index ae3e5a88c..3a08eebf6 100644
--- a/Source/JavaScriptCore/runtime/TypedArrayType.h
+++ b/Source/JavaScriptCore/runtime/TypedArrayType.h
@@ -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,6 +26,7 @@
#ifndef TypedArrayType_h
#define TypedArrayType_h
+#include "JSType.h"
#include <wtf/PrintStream.h>
namespace JSC {
@@ -100,8 +101,8 @@ inline size_t elementSize(TypedArrayType type)
return static_cast<size_t>(1) << logElementSize(type);
}
-const ClassInfo* classInfoForType(TypedArrayType);
const ClassInfo* constructorClassInfoForType(TypedArrayType);
+JSType typeForTypedArrayType(TypedArrayType);
inline bool isInt(TypedArrayType type)
{
diff --git a/Source/JavaScriptCore/runtime/TypeofType.cpp b/Source/JavaScriptCore/runtime/TypeofType.cpp
new file mode 100644
index 000000000..db162b7f4
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TypeofType.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "TypeofType.h"
+
+namespace WTF {
+
+using namespace JSC;
+
+void printInternal(PrintStream& out, TypeofType type)
+{
+ switch (type) {
+ case TypeofType::Undefined:
+ out.print("undefined");
+ return;
+ case TypeofType::Boolean:
+ out.print("boolean");
+ return;
+ case TypeofType::Number:
+ out.print("number");
+ return;
+ case TypeofType::String:
+ out.print("string");
+ return;
+ case TypeofType::Symbol:
+ out.print("symbol");
+ return;
+ case TypeofType::Object:
+ out.print("object");
+ return;
+ case TypeofType::Function:
+ out.print("function");
+ return;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace WTF
+
diff --git a/Source/JavaScriptCore/runtime/TypeofType.h b/Source/JavaScriptCore/runtime/TypeofType.h
new file mode 100644
index 000000000..3eb78d4f9
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TypeofType.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef TypeofType_h
+#define TypeofType_h
+
+#include <wtf/PrintStream.h>
+
+namespace JSC {
+
+enum class TypeofType {
+ Undefined,
+ Boolean,
+ Number,
+ String,
+ Symbol,
+ Object,
+ Function
+};
+
+} // namespace JSC
+
+namespace WTF {
+
+void printInternal(PrintStream& out, JSC::TypeofType);
+
+} // namespace WTF
+
+#endif // TypeofType_h
+
diff --git a/Source/JavaScriptCore/runtime/VM.cpp b/Source/JavaScriptCore/runtime/VM.cpp
index d7e50ed61..de96ca07f 100644
--- a/Source/JavaScriptCore/runtime/VM.cpp
+++ b/Source/JavaScriptCore/runtime/VM.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2011, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2011, 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,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.
*
@@ -31,54 +31,78 @@
#include "ArgList.h"
#include "ArrayBufferNeuteringWatchpoint.h"
-#include "CallFrameInlines.h"
+#include "BuiltinExecutables.h"
+#include "BytecodeIntrinsicRegistry.h"
#include "CodeBlock.h"
#include "CodeCache.h"
#include "CommonIdentifiers.h"
+#include "CommonSlowPaths.h"
+#include "CustomGetterSetter.h"
#include "DFGLongLivedState.h"
#include "DFGWorklist.h"
-#include "DebuggerActivation.h"
+#include "Disassembler.h"
#include "ErrorInstance.h"
+#include "Exception.h"
#include "FTLThunks.h"
#include "FunctionConstructor.h"
#include "GCActivityCallback.h"
+#include "GeneratorFrame.h"
#include "GetterSetter.h"
#include "Heap.h"
#include "HeapIterationScope.h"
#include "HostCallReturnValue.h"
#include "Identifier.h"
#include "IncrementalSweeper.h"
+#include "InferredTypeTable.h"
#include "Interpreter.h"
+#include "JITCode.h"
#include "JSAPIValueWrapper.h"
-#include "JSActivation.h"
#include "JSArray.h"
+#include "JSCInlines.h"
#include "JSFunction.h"
#include "JSGlobalObjectFunctions.h"
+#include "JSInternalPromiseDeferred.h"
+#include "JSLexicalEnvironment.h"
#include "JSLock.h"
-#include "JSNameScope.h"
#include "JSNotAnObject.h"
#include "JSPromiseDeferred.h"
-#include "JSPromiseReaction.h"
-#include "JSPropertyNameIterator.h"
+#include "JSPropertyNameEnumerator.h"
+#include "JSTemplateRegistryKey.h"
#include "JSWithScope.h"
#include "Lexer.h"
#include "Lookup.h"
#include "MapData.h"
+#include "NativeStdFunctionCell.h"
#include "Nodes.h"
-#include "ParserArena.h"
+#include "Parser.h"
+#include "ProfilerDatabase.h"
+#include "PropertyMapHashTable.h"
#include "RegExpCache.h"
#include "RegExpObject.h"
+#include "RegisterAtOffsetList.h"
+#include "RuntimeType.h"
+#include "SamplingProfiler.h"
#include "SimpleTypedArrayController.h"
#include "SourceProviderCache.h"
+#include "StackVisitor.h"
#include "StrictEvalActivation.h"
#include "StrongInlines.h"
+#include "StructureInlines.h"
+#include "TypeProfiler.h"
+#include "TypeProfilerLog.h"
#include "UnlinkedCodeBlock.h"
+#include "VMEntryScope.h"
+#include "Watchdog.h"
+#include "WeakGCMapInlines.h"
#include "WeakMapData.h"
+#include <wtf/CurrentTime.h>
#include <wtf/ProcessID.h>
#include <wtf/RetainPtr.h>
#include <wtf/StringPrintStream.h>
#include <wtf/Threading.h>
#include <wtf/WTFThreadData.h>
+#include <wtf/text/AtomicStringTable.h>
+#include <wtf/text/SymbolRegistry.h>
#if ENABLE(DFG_JIT)
#include "ConservativeRoots.h"
@@ -96,28 +120,6 @@ using namespace WTF;
namespace JSC {
-extern const HashTable arrayConstructorTable;
-extern const HashTable arrayPrototypeTable;
-extern const HashTable booleanPrototypeTable;
-extern const HashTable jsonTable;
-extern const HashTable dataViewTable;
-extern const HashTable dateTable;
-extern const HashTable dateConstructorTable;
-extern const HashTable errorPrototypeTable;
-extern const HashTable globalObjectTable;
-extern const HashTable numberConstructorTable;
-extern const HashTable numberPrototypeTable;
-JS_EXPORTDATA extern const HashTable objectConstructorTable;
-extern const HashTable privateNamePrototypeTable;
-extern const HashTable regExpTable;
-extern const HashTable regExpConstructorTable;
-extern const HashTable regExpPrototypeTable;
-extern const HashTable stringConstructorTable;
-#if ENABLE(PROMISES)
-extern const HashTable promisePrototypeTable;
-extern const HashTable promiseConstructorTable;
-#endif
-
// Note: Platform.h will enforce that ENABLE(ASSEMBLER) is true if either
// ENABLE(JIT) or ENABLE(YARR_JIT) or both are enabled. The code below
// just checks for ENABLE(JIT) or ENABLE(YARR_JIT) with this premise in mind.
@@ -134,20 +136,6 @@ static bool enableAssembler(ExecutableAllocator& executableAllocator)
return false;
}
-#if USE(CF)
-#if COMPILER(GCC) && !COMPILER(CLANG)
- // FIXME: remove this once the EWS have been upgraded to LLVM.
- // Work around a bug of GCC with strict-aliasing.
- RetainPtr<CFStringRef> canUseJITKeyRetain = adoptCF(CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman));
- CFStringRef canUseJITKey = canUseJITKeyRetain.get();
-#else
- CFStringRef canUseJITKey = CFSTR("JavaScriptCoreUseJIT");
-#endif // COMPILER(GCC) && !COMPILER(CLANG)
- RetainPtr<CFTypeRef> canUseJIT = adoptCF(CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication));
- if (canUseJIT)
- return kCFBooleanTrue == canUseJIT.get();
-#endif
-
#if USE(CF) || OS(UNIX)
char* canUseJITString = getenv("JavaScriptCoreUseJIT");
return !canUseJITString || atoi(canUseJITString);
@@ -165,33 +153,14 @@ VM::VM(VMType vmType, HeapType heapType)
, heap(this, heapType)
, vmType(vmType)
, clientData(0)
+ , topVMEntryFrame(nullptr)
, topCallFrame(CallFrame::noCaller())
- , arrayConstructorTable(adoptPtr(new HashTable(JSC::arrayConstructorTable)))
- , arrayPrototypeTable(adoptPtr(new HashTable(JSC::arrayPrototypeTable)))
- , booleanPrototypeTable(adoptPtr(new HashTable(JSC::booleanPrototypeTable)))
- , dataViewTable(adoptPtr(new HashTable(JSC::dataViewTable)))
- , dateTable(adoptPtr(new HashTable(JSC::dateTable)))
- , dateConstructorTable(adoptPtr(new HashTable(JSC::dateConstructorTable)))
- , errorPrototypeTable(adoptPtr(new HashTable(JSC::errorPrototypeTable)))
- , globalObjectTable(adoptPtr(new HashTable(JSC::globalObjectTable)))
- , jsonTable(adoptPtr(new HashTable(JSC::jsonTable)))
- , numberConstructorTable(adoptPtr(new HashTable(JSC::numberConstructorTable)))
- , numberPrototypeTable(adoptPtr(new HashTable(JSC::numberPrototypeTable)))
- , objectConstructorTable(adoptPtr(new HashTable(JSC::objectConstructorTable)))
- , privateNamePrototypeTable(adoptPtr(new HashTable(JSC::privateNamePrototypeTable)))
- , regExpTable(adoptPtr(new HashTable(JSC::regExpTable)))
- , regExpConstructorTable(adoptPtr(new HashTable(JSC::regExpConstructorTable)))
- , regExpPrototypeTable(adoptPtr(new HashTable(JSC::regExpPrototypeTable)))
- , stringConstructorTable(adoptPtr(new HashTable(JSC::stringConstructorTable)))
-#if ENABLE(PROMISES)
- , promisePrototypeTable(adoptPtr(new HashTable(JSC::promisePrototypeTable)))
- , promiseConstructorTable(adoptPtr(new HashTable(JSC::promiseConstructorTable)))
-#endif
- , identifierTable(vmType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
- , propertyNames(new CommonIdentifiers(this))
+ , m_atomicStringTable(vmType == Default ? wtfThreadData().atomicStringTable() : new AtomicStringTable)
+ , propertyNames(nullptr)
, emptyList(new MarkedArgumentBuffer)
- , parserArena(adoptPtr(new ParserArena))
- , keywords(adoptPtr(new Keywords(*this)))
+ , customGetterSetterFunctionMap(*this)
+ , stringCache(*this)
+ , prototypeMap(*this)
, interpreter(0)
, jsArrayClassInfo(JSArray::info())
, jsFinalObjectClassInfo(JSFinalObject::info())
@@ -201,8 +170,6 @@ VM::VM(VMType vmType, HeapType heapType)
#if ENABLE(REGEXP_TRACING)
, m_rtTraceList(new RTTraceList())
#endif
- , exclusiveThread(0)
- , m_newStringsSinceLastHashCons(0)
#if ENABLE(ASSEMBLER)
, m_canUseAssembler(enableAssembler(executableAllocator))
#endif
@@ -215,29 +182,43 @@ VM::VM(VMType vmType, HeapType heapType)
#if ENABLE(GC_VALIDATION)
, m_initializingObjectClass(0)
#endif
+ , m_stackPointerAtVMEntry(0)
, m_stackLimit(0)
-#if USE(SEPARATE_C_AND_JS_STACK)
+#if !ENABLE(JIT)
, m_jsStackLimit(0)
#endif
+#if ENABLE(FTL_JIT)
+ , m_ftlStackLimit(0)
+ , m_largestFTLStackSize(0)
+#endif
, m_inDefineOwnProperty(false)
- , m_codeCache(CodeCache::create())
+ , m_codeCache(std::make_unique<CodeCache>())
, m_enabledProfiler(nullptr)
+ , m_builtinExecutables(std::make_unique<BuiltinExecutables>(*this))
+ , m_typeProfilerEnabledCount(0)
+ , m_controlFlowProfilerEnabledCount(0)
{
interpreter = new Interpreter(*this);
StackBounds stack = wtfThreadData().stack();
- setStackLimit(stack.recursionLimit());
+ updateReservedZoneSize(Options::reservedZoneSize());
+#if !ENABLE(JIT)
+ interpreter->stack().setReservedZoneSize(Options::reservedZoneSize());
+#endif
+ setLastStackTop(stack.origin());
// Need to be careful to keep everything consistent here
JSLockHolder lock(this);
- IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable);
+ AtomicStringTable* existingEntryAtomicStringTable = wtfThreadData().setCurrentAtomicStringTable(m_atomicStringTable);
+ propertyNames = new CommonIdentifiers(this);
structureStructure.set(*this, Structure::createStructure(*this));
structureRareDataStructure.set(*this, StructureRareData::createStructure(*this, 0, jsNull()));
- debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull()));
terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull()));
notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull()));
- propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull()));
+ propertyNameEnumeratorStructure.set(*this, JSPropertyNameEnumerator::createStructure(*this, 0, jsNull()));
getterSetterStructure.set(*this, GetterSetter::createStructure(*this, 0, jsNull()));
+ customGetterSetterStructure.set(*this, CustomGetterSetter::createStructure(*this, 0, jsNull()));
+ scopedArgumentsTableStructure.set(*this, ScopedArgumentsTable::createStructure(*this, 0, jsNull()));
apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull()));
JSScopeStructure.set(*this, JSScope::createStructure(*this, 0, jsNull()));
executableStructure.set(*this, ExecutableBase::createStructure(*this, 0, jsNull()));
@@ -245,84 +226,138 @@ VM::VM(VMType vmType, HeapType heapType)
evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, 0, jsNull()));
programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull()));
functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull()));
+#if ENABLE(WEBASSEMBLY)
+ webAssemblyExecutableStructure.set(*this, WebAssemblyExecutable::createStructure(*this, 0, jsNull()));
+#endif
+ moduleProgramExecutableStructure.set(*this, ModuleProgramExecutable::createStructure(*this, 0, jsNull()));
regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull()));
+ symbolStructure.set(*this, Symbol::createStructure(*this, 0, jsNull()));
symbolTableStructure.set(*this, SymbolTable::createStructure(*this, 0, jsNull()));
structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull()));
sparseArrayValueMapStructure.set(*this, SparseArrayValueMap::createStructure(*this, 0, jsNull()));
+ templateRegistryKeyStructure.set(*this, JSTemplateRegistryKey::createStructure(*this, 0, jsNull()));
arrayBufferNeuteringWatchpointStructure.set(*this, ArrayBufferNeuteringWatchpoint::createStructure(*this));
- withScopeStructure.set(*this, JSWithScope::createStructure(*this, 0, jsNull()));
unlinkedFunctionExecutableStructure.set(*this, UnlinkedFunctionExecutable::createStructure(*this, 0, jsNull()));
unlinkedProgramCodeBlockStructure.set(*this, UnlinkedProgramCodeBlock::createStructure(*this, 0, jsNull()));
unlinkedEvalCodeBlockStructure.set(*this, UnlinkedEvalCodeBlock::createStructure(*this, 0, jsNull()));
unlinkedFunctionCodeBlockStructure.set(*this, UnlinkedFunctionCodeBlock::createStructure(*this, 0, jsNull()));
+ unlinkedModuleProgramCodeBlockStructure.set(*this, UnlinkedModuleProgramCodeBlock::createStructure(*this, 0, jsNull()));
propertyTableStructure.set(*this, PropertyTable::createStructure(*this, 0, jsNull()));
- mapDataStructure.set(*this, MapData::createStructure(*this, 0, jsNull()));
weakMapDataStructure.set(*this, WeakMapData::createStructure(*this, 0, jsNull()));
+ inferredValueStructure.set(*this, InferredValue::createStructure(*this, 0, jsNull()));
+ inferredTypeStructure.set(*this, InferredType::createStructure(*this, 0, jsNull()));
+ inferredTypeTableStructure.set(*this, InferredTypeTable::createStructure(*this, 0, jsNull()));
+ functionRareDataStructure.set(*this, FunctionRareData::createStructure(*this, 0, jsNull()));
+ generatorFrameStructure.set(*this, GeneratorFrame::createStructure(*this, 0, jsNull()));
+ exceptionStructure.set(*this, Exception::createStructure(*this, 0, jsNull()));
promiseDeferredStructure.set(*this, JSPromiseDeferred::createStructure(*this, 0, jsNull()));
- promiseReactionStructure.set(*this, JSPromiseReaction::createStructure(*this, 0, jsNull()));
+ internalPromiseDeferredStructure.set(*this, JSInternalPromiseDeferred::createStructure(*this, 0, jsNull()));
+ programCodeBlockStructure.set(*this, ProgramCodeBlock::createStructure(*this, 0, jsNull()));
+ moduleProgramCodeBlockStructure.set(*this, ModuleProgramCodeBlock::createStructure(*this, 0, jsNull()));
+ evalCodeBlockStructure.set(*this, EvalCodeBlock::createStructure(*this, 0, jsNull()));
+ functionCodeBlockStructure.set(*this, FunctionCodeBlock::createStructure(*this, 0, jsNull()));
+#if ENABLE(WEBASSEMBLY)
+ webAssemblyCodeBlockStructure.set(*this, WebAssemblyCodeBlock::createStructure(*this, 0, jsNull()));
+#endif
+
iterationTerminator.set(*this, JSFinalObject::create(*this, JSFinalObject::createStructure(*this, 0, jsNull(), 1)));
+ nativeStdFunctionCellStructure.set(*this, NativeStdFunctionCell::createStructure(*this, 0, jsNull()));
smallStrings.initializeCommonStrings(*this);
- wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
+ wtfThreadData().setCurrentAtomicStringTable(existingEntryAtomicStringTable);
#if ENABLE(JIT)
- jitStubs = adoptPtr(new JITThunks());
+ jitStubs = std::make_unique<JITThunks>();
+ allCalleeSaveRegisterOffsets = std::make_unique<RegisterAtOffsetList>(RegisterSet::vmCalleeSaveRegisters(), RegisterAtOffsetList::ZeroBased);
#endif
+ arityCheckData = std::make_unique<CommonSlowPaths::ArityCheckData>();
#if ENABLE(FTL_JIT)
ftlThunks = std::make_unique<FTL::Thunks>();
#endif // ENABLE(FTL_JIT)
- interpreter->initialize(this->canUseJIT());
+ interpreter->initialize();
#if ENABLE(JIT)
initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support.
#endif
heap.notifyIsSafeToCollect();
-
+
LLInt::Data::performAssertions(*this);
- if (Options::enableProfiler()) {
- m_perBytecodeProfiler = adoptPtr(new Profiler::Database(*this));
+ if (Options::useProfiler()) {
+ m_perBytecodeProfiler = std::make_unique<Profiler::Database>(*this);
StringPrintStream pathOut;
-#if !OS(WINCE)
const char* profilerPath = getenv("JSC_PROFILER_PATH");
if (profilerPath)
pathOut.print(profilerPath, "/");
-#endif
pathOut.print("JSCProfile-", getCurrentProcessID(), "-", m_perBytecodeProfiler->databaseID(), ".json");
m_perBytecodeProfiler->registerToSaveAtExit(pathOut.toCString().data());
}
+ callFrameForCatch = nullptr;
+
#if ENABLE(DFG_JIT)
if (canUseJIT())
- dfgState = adoptPtr(new DFG::LongLivedState());
+ dfgState = std::make_unique<DFG::LongLivedState>();
#endif
// Initialize this last, as a free way of asserting that VM initialization itself
// won't use this.
m_typedArrayController = adoptRef(new SimpleTypedArrayController());
+
+ m_bytecodeIntrinsicRegistry = std::make_unique<BytecodeIntrinsicRegistry>(*this);
+
+ if (Options::useTypeProfiler())
+ enableTypeProfiler();
+ if (Options::useControlFlowProfiler())
+ enableControlFlowProfiler();
+#if ENABLE(SAMPLING_PROFILER)
+ if (Options::useSamplingProfiler()) {
+ setShouldBuildPCToCodeOriginMapping();
+ m_samplingProfiler = adoptRef(new SamplingProfiler(*this, Stopwatch::create()));
+ m_samplingProfiler->start();
+ }
+#endif // ENABLE(SAMPLING_PROFILER)
+
+ if (Options::alwaysGeneratePCToCodeOriginMap())
+ setShouldBuildPCToCodeOriginMapping();
+
+ if (Options::watchdog()) {
+ std::chrono::milliseconds timeoutMillis(Options::watchdog());
+ Watchdog& watchdog = ensureWatchdog();
+ watchdog.setTimeLimit(timeoutMillis);
+ }
}
VM::~VM()
{
// Never GC, ever again.
heap.incrementDeferralDepth();
+
+#if ENABLE(SAMPLING_PROFILER)
+ if (m_samplingProfiler)
+ m_samplingProfiler->shutdown();
+#endif // ENABLE(SAMPLING_PROFILER)
#if ENABLE(DFG_JIT)
// Make sure concurrent compilations are done, but don't install them, since there is
// no point to doing so.
- if (worklist) {
- worklist->waitUntilAllPlansForVMAreReady(*this);
- worklist->removeAllReadyPlansForVM(*this);
+ for (unsigned i = DFG::numberOfWorklists(); i--;) {
+ if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) {
+ worklist->waitUntilAllPlansForVMAreReady(*this);
+ worklist->removeAllReadyPlansForVM(*this);
+ }
}
#endif // ENABLE(DFG_JIT)
- // Clear this first to ensure that nobody tries to remove themselves from it.
- m_perBytecodeProfiler.clear();
+ waitForAsynchronousDisassembly();
+ // Clear this first to ensure that nobody tries to remove themselves from it.
+ m_perBytecodeProfiler = nullptr;
+
ASSERT(m_apiLock->currentThreadIsHoldingLock());
m_apiLock->willDestroyVM(this);
heap.lastChanceToFinalize();
@@ -332,33 +367,11 @@ VM::~VM()
interpreter = reinterpret_cast<Interpreter*>(0xbbadbeef);
#endif
- arrayPrototypeTable->deleteTable();
- arrayConstructorTable->deleteTable();
- booleanPrototypeTable->deleteTable();
- dataViewTable->deleteTable();
- dateTable->deleteTable();
- dateConstructorTable->deleteTable();
- errorPrototypeTable->deleteTable();
- globalObjectTable->deleteTable();
- jsonTable->deleteTable();
- numberConstructorTable->deleteTable();
- numberPrototypeTable->deleteTable();
- objectConstructorTable->deleteTable();
- privateNamePrototypeTable->deleteTable();
- regExpTable->deleteTable();
- regExpConstructorTable->deleteTable();
- regExpPrototypeTable->deleteTable();
- stringConstructorTable->deleteTable();
-#if ENABLE(PROMISES)
- promisePrototypeTable->deleteTable();
- promiseConstructorTable->deleteTable();
-#endif
-
delete emptyList;
delete propertyNames;
if (vmType != Default)
- deleteIdentifierTable(identifierTable);
+ delete m_atomicStringTable;
delete clientData;
delete m_regExpCache;
@@ -372,17 +385,22 @@ VM::~VM()
#endif
}
-PassRefPtr<VM> VM::createContextGroup(HeapType heapType)
+void VM::setLastStackTop(void* lastStackTop)
+{
+ m_lastStackTop = lastStackTop;
+}
+
+Ref<VM> VM::createContextGroup(HeapType heapType)
{
- return adoptRef(new VM(APIContextGroup, heapType));
+ return adoptRef(*new VM(APIContextGroup, heapType));
}
-PassRefPtr<VM> VM::create(HeapType heapType)
+Ref<VM> VM::create(HeapType heapType)
{
- return adoptRef(new VM(Default, heapType));
+ return adoptRef(*new VM(Default, heapType));
}
-PassRefPtr<VM> VM::createLeaked(HeapType heapType)
+Ref<VM> VM::createLeaked(HeapType heapType)
{
return create(heapType);
}
@@ -396,10 +414,8 @@ VM& VM::sharedInstance()
{
GlobalJSLock globalLock;
VM*& instance = sharedInstanceInternal();
- if (!instance) {
+ if (!instance)
instance = adoptRef(new VM(APIShared, SmallHeap)).leakRef();
- instance->makeUsableFromMultipleThreads();
- }
return *instance;
}
@@ -409,6 +425,32 @@ VM*& VM::sharedInstanceInternal()
return sharedInstance;
}
+Watchdog& VM::ensureWatchdog()
+{
+ if (!m_watchdog) {
+ m_watchdog = adoptRef(new Watchdog());
+
+ // The LLINT peeks into the Watchdog object directly. In order to do that,
+ // the LLINT assumes that the internal shape of a std::unique_ptr is the
+ // same as a plain C++ pointer, and loads the address of Watchdog from it.
+ RELEASE_ASSERT(*reinterpret_cast<Watchdog**>(&m_watchdog) == m_watchdog.get());
+
+ // And if we've previously compiled any functions, we need to revert
+ // them because they don't have the needed polling checks for the watchdog
+ // yet.
+ deleteAllCode();
+ }
+ return *m_watchdog;
+}
+
+#if ENABLE(SAMPLING_PROFILER)
+void VM::ensureSamplingProfiler(RefPtr<Stopwatch>&& stopwatch)
+{
+ if (!m_samplingProfiler)
+ m_samplingProfiler = adoptRef(new SamplingProfiler(*this, WTFMove(stopwatch)));
+}
+#endif // ENABLE(SAMPLING_PROFILER)
+
#if ENABLE(JIT)
static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic)
{
@@ -417,6 +459,8 @@ static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic)
return charCodeAtThunkGenerator;
case CharAtIntrinsic:
return charAtThunkGenerator;
+ case Clz32Intrinsic:
+ return clz32ThunkGenerator;
case FromCharCodeIntrinsic:
return fromCharCodeThunkGenerator;
case SqrtIntrinsic:
@@ -437,33 +481,31 @@ static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic)
return logThunkGenerator;
case IMulIntrinsic:
return imulThunkGenerator;
- case ArrayIteratorNextKeyIntrinsic:
- return arrayIteratorNextKeyThunkGenerator;
- case ArrayIteratorNextValueIntrinsic:
- return arrayIteratorNextValueThunkGenerator;
+ case RandomIntrinsic:
+ return randomThunkGenerator;
default:
return 0;
}
}
-NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor)
+NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor, const String& name)
{
- return jitStubs->hostFunctionStub(this, function, constructor);
+ return jitStubs->hostFunctionStub(this, function, constructor, name);
}
-NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrinsic)
+NativeExecutable* VM::getHostFunction(NativeFunction function, Intrinsic intrinsic, const String& name)
{
ASSERT(canUseJIT());
- return jitStubs->hostFunctionStub(this, function, intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0, intrinsic);
+ return jitStubs->hostFunctionStub(this, function, intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0, intrinsic, name);
}
#else // !ENABLE(JIT)
-NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor)
+NativeExecutable* VM::getHostFunction(NativeFunction function, NativeFunction constructor, const String& name)
{
return NativeExecutable::create(*this,
- MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_call_trampoline), function,
- MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_construct_trampoline), constructor,
- NoIntrinsic);
+ adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_call_trampoline), JITCode::HostCallThunk)), function,
+ adoptRef(new NativeJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_native_construct_trampoline), JITCode::HostCallThunk)), constructor,
+ NoIntrinsic, name);
}
#endif // !ENABLE(JIT)
@@ -476,7 +518,7 @@ void VM::resetDateCache()
{
localTimeOffsetCache.reset();
cachedDateString = String();
- cachedDateStringValue = QNaN;
+ cachedDateStringValue = std::numeric_limits<double>::quiet_NaN();
dateInstanceCache.reset();
}
@@ -490,22 +532,33 @@ void VM::stopSampling()
interpreter->stopSampling();
}
-void VM::prepareToDiscardCode()
+void VM::whenIdle(std::function<void()> callback)
{
-#if ENABLE(DFG_JIT)
- if (!worklist)
+ if (!entryScope) {
+ callback();
return;
-
- worklist->completeAllPlansForVM(*this);
-#endif
+ }
+
+ entryScope->addDidPopListener(callback);
}
-void VM::discardAllCode()
+void VM::deleteAllLinkedCode()
{
- prepareToDiscardCode();
- m_codeCache->clear();
- heap.deleteAllCompiledCode();
- heap.reportAbandonedObjectGraph();
+ whenIdle([this]() {
+ heap.deleteAllCodeBlocks();
+ heap.reportAbandonedObjectGraph();
+ });
+}
+
+void VM::deleteAllCode()
+{
+ whenIdle([this]() {
+ m_codeCache->clear();
+ m_regExpCache->deleteAllCode();
+ heap.deleteAllCodeBlocks();
+ heap.deleteAllUnlinkedCodeBlocks();
+ heap.reportAbandonedObjectGraph();
+ });
}
void VM::dumpSampleData(ExecState* exec)
@@ -529,187 +582,115 @@ void VM::clearSourceProviderCaches()
sourceProviderCacheMap.clear();
}
-struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor {
- HashSet<FunctionExecutable*> currentlyExecutingFunctions;
- void operator()(JSCell* cell)
- {
- if (!cell->inherits(FunctionExecutable::info()))
- return;
- FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
- if (currentlyExecutingFunctions.contains(executable))
- return;
- executable->clearCodeIfNotCompiling();
- }
-};
-
-void VM::releaseExecutableMemory()
+void VM::throwException(ExecState* exec, Exception* exception)
{
- prepareToDiscardCode();
-
- if (entryScope) {
- StackPreservingRecompiler recompiler;
- HeapIterationScope iterationScope(heap);
- HashSet<JSCell*> roots;
- heap.getConservativeRegisterRoots(roots);
- HashSet<JSCell*>::iterator end = roots.end();
- for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) {
- ScriptExecutable* executable = 0;
- JSCell* cell = *ptr;
- if (cell->inherits(ScriptExecutable::info()))
- executable = static_cast<ScriptExecutable*>(*ptr);
- else if (cell->inherits(JSFunction::info())) {
- JSFunction* function = jsCast<JSFunction*>(*ptr);
- if (function->isHostFunction())
- continue;
- executable = function->jsExecutable();
- } else
- continue;
- ASSERT(executable->inherits(ScriptExecutable::info()));
- executable->unlinkCalls();
- if (executable->inherits(FunctionExecutable::info()))
- recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable));
-
- }
- heap.objectSpace().forEachLiveCell<StackPreservingRecompiler>(iterationScope, recompiler);
+ if (Options::breakOnThrow()) {
+ dataLog("In call frame ", RawPointer(exec), " for code block ", *exec->codeBlock(), "\n");
+ CRASH();
}
- m_regExpCache->invalidateCode();
- heap.collectAllGarbage();
-}
-static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset)
-{
- exception->clearAppendSourceToMessage();
-
- if (!callFrame->codeBlock()->hasExpressionInfo())
- return;
-
- int startOffset = 0;
- int endOffset = 0;
- int divotPoint = 0;
- unsigned line = 0;
- unsigned column = 0;
-
- CodeBlock* codeBlock = callFrame->codeBlock();
- codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset, line, column);
-
- int expressionStart = divotPoint - startOffset;
- int expressionStop = divotPoint + endOffset;
-
- const String& sourceString = codeBlock->source()->source();
- if (!expressionStop || expressionStart > static_cast<int>(sourceString.length()))
- return;
-
- VM* vm = &callFrame->vm();
- JSValue jsMessage = exception->getDirect(*vm, vm->propertyNames->message);
- if (!jsMessage || !jsMessage.isString())
- return;
-
- String message = asString(jsMessage)->value(callFrame);
-
- if (expressionStart < expressionStop)
- message = makeString(message, " (evaluating '", codeBlock->source()->getRange(expressionStart, expressionStop), "')");
- else {
- // No range information, so give a few characters of context.
- const StringImpl* data = sourceString.impl();
- int dataLength = sourceString.length();
- int start = expressionStart;
- int stop = expressionStart;
- // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
- // Then strip whitespace.
- while (start > 0 && (expressionStart - start < 20) && (*data)[start - 1] != '\n')
- start--;
- while (start < (expressionStart - 1) && isStrWhiteSpace((*data)[start]))
- start++;
- while (stop < dataLength && (stop - expressionStart < 20) && (*data)[stop] != '\n')
- stop++;
- while (stop > expressionStart && isStrWhiteSpace((*data)[stop - 1]))
- stop--;
- message = makeString(message, " (near '...", codeBlock->source()->getRange(start, stop), "...')");
- }
-
- exception->putDirect(*vm, vm->propertyNames->message, jsString(vm, message));
+ ASSERT(exec == topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec());
+
+ interpreter->notifyDebuggerOfExceptionToBeThrown(exec, exception);
+
+ setException(exception);
}
-
-JSValue VM::throwException(ExecState* exec, JSValue error)
+
+JSValue VM::throwException(ExecState* exec, JSValue thrownValue)
{
- ASSERT(exec == topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec());
-
- Vector<StackFrame> stackTrace;
- interpreter->getStackTrace(stackTrace);
- m_exceptionStack = RefCountedArray<StackFrame>(stackTrace);
- m_exception = error;
-
- if (stackTrace.isEmpty() || !error.isObject())
- return error;
- JSObject* exception = asObject(error);
-
- StackFrame stackFrame;
- for (unsigned i = 0 ; i < stackTrace.size(); ++i) {
- stackFrame = stackTrace.at(i);
- if (stackFrame.bytecodeOffset)
- break;
- }
- unsigned bytecodeOffset = stackFrame.bytecodeOffset;
- if (!hasErrorInfo(exec, exception)) {
- // FIXME: We should only really be adding these properties to VM generated exceptions,
- // but the inspector currently requires these for all thrown objects.
- unsigned line;
- unsigned column;
- stackFrame.computeLineAndColumn(line, column);
- exception->putDirect(*this, Identifier(this, "line"), jsNumber(line), ReadOnly | DontDelete);
- exception->putDirect(*this, Identifier(this, "column"), jsNumber(column), ReadOnly | DontDelete);
- if (!stackFrame.sourceURL.isEmpty())
- exception->putDirect(*this, Identifier(this, "sourceURL"), jsString(this, stackFrame.sourceURL), ReadOnly | DontDelete);
- }
- if (exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->appendSourceToMessage()) {
- unsigned stackIndex = 0;
- CallFrame* callFrame;
- for (callFrame = exec; callFrame && !callFrame->codeBlock(); ) {
- stackIndex++;
- callFrame = callFrame->callerFrameSkippingVMEntrySentinel();
- }
- if (callFrame && callFrame->codeBlock()) {
- stackFrame = stackTrace.at(stackIndex);
- bytecodeOffset = stackFrame.bytecodeOffset;
- appendSourceToError(callFrame, static_cast<ErrorInstance*>(exception), bytecodeOffset);
- }
- }
+ Exception* exception = jsDynamicCast<Exception*>(thrownValue);
+ if (!exception)
+ exception = Exception::create(*this, thrownValue);
- if (exception->hasProperty(exec, this->propertyNames->stack))
- return error;
-
- exception->putDirect(*this, propertyNames->stack, interpreter->stackTraceAsString(topCallFrame, stackTrace), DontEnum);
- return error;
+ throwException(exec, exception);
+ return JSValue(exception);
}
-
+
JSObject* VM::throwException(ExecState* exec, JSObject* error)
{
return asObject(throwException(exec, JSValue(error)));
}
-void VM::getExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack)
+
+void VM::setStackPointerAtVMEntry(void* sp)
{
- exception = m_exception;
- exceptionStack = m_exceptionStack;
+ m_stackPointerAtVMEntry = sp;
+ updateStackLimit();
}
-void VM::setExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack)
+
+size_t VM::updateReservedZoneSize(size_t reservedZoneSize)
{
- m_exception = exception;
- m_exceptionStack = exceptionStack;
+ size_t oldReservedZoneSize = m_reservedZoneSize;
+ m_reservedZoneSize = reservedZoneSize;
+
+ updateStackLimit();
+
+ return oldReservedZoneSize;
}
-void VM::clearException()
+#if PLATFORM(WIN)
+// On Windows the reserved stack space consists of committed memory, a guard page, and uncommitted memory,
+// where the guard page is a barrier between committed and uncommitted memory.
+// When data from the guard page is read or written, the guard page is moved, and memory is committed.
+// This is how the system grows the stack.
+// When using the C stack on Windows we need to precommit the needed stack space.
+// Otherwise we might crash later if we access uncommitted stack memory.
+// This can happen if we allocate stack space larger than the page guard size (4K).
+// The system does not get the chance to move the guard page, and commit more memory,
+// and we crash if uncommitted memory is accessed.
+// The MSVC compiler fixes this by inserting a call to the _chkstk() function,
+// when needed, see http://support.microsoft.com/kb/100775.
+// By touching every page up to the stack limit with a dummy operation,
+// we force the system to move the guard page, and commit memory.
+
+static void preCommitStackMemory(void* stackLimit)
{
- m_exception = JSValue();
+ const int pageSize = 4096;
+ for (volatile char* p = reinterpret_cast<char*>(&stackLimit); p > stackLimit; p -= pageSize) {
+ char ch = *p;
+ *p = ch;
+ }
}
-void VM:: clearExceptionStack()
+#endif
+
+inline void VM::updateStackLimit()
{
- m_exceptionStack = RefCountedArray<StackFrame>();
+#if PLATFORM(WIN)
+ void* lastStackLimit = m_stackLimit;
+#endif
+
+ if (m_stackPointerAtVMEntry) {
+ ASSERT(wtfThreadData().stack().isGrowingDownward());
+ char* startOfStack = reinterpret_cast<char*>(m_stackPointerAtVMEntry);
+#if ENABLE(FTL_JIT)
+ m_stackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_reservedZoneSize + m_largestFTLStackSize);
+ m_ftlStackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_reservedZoneSize + 2 * m_largestFTLStackSize);
+#else
+ m_stackLimit = wtfThreadData().stack().recursionLimit(startOfStack, Options::maxPerThreadStackUsage(), m_reservedZoneSize);
+#endif
+ } else {
+#if ENABLE(FTL_JIT)
+ m_stackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize + m_largestFTLStackSize);
+ m_ftlStackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize + 2 * m_largestFTLStackSize);
+#else
+ m_stackLimit = wtfThreadData().stack().recursionLimit(m_reservedZoneSize);
+#endif
+ }
+
+#if PLATFORM(WIN)
+ if (lastStackLimit != m_stackLimit)
+ preCommitStackMemory(m_stackLimit);
+#endif
}
-void releaseExecutableMemory(VM& vm)
+#if ENABLE(FTL_JIT)
+void VM::updateFTLLargestStackSize(size_t stackSize)
{
- vm.releaseExecutableMemory();
+ if (stackSize > m_largestFTLStackSize) {
+ m_largestFTLStackSize = stackSize;
+ updateStackLimit();
+ }
}
+#endif
#if ENABLE(DFG_JIT)
void VM::gatherConservativeRoots(ConservativeRoots& conservativeRoots)
@@ -722,20 +703,24 @@ void VM::gatherConservativeRoots(ConservativeRoots& conservativeRoots)
}
}
}
+#endif
-DFG::Worklist* VM::ensureWorklist()
+void logSanitizeStack(VM* vm)
{
- if (!DFG::enableConcurrentJIT())
- return 0;
- if (!worklist)
- worklist = DFG::globalWorklist();
- return worklist.get();
+ if (Options::verboseSanitizeStack() && vm->topCallFrame) {
+ int dummy;
+ dataLog(
+ "Sanitizing stack with top call frame at ", RawPointer(vm->topCallFrame),
+ ", current stack pointer at ", RawPointer(&dummy), ", in ",
+ pointerDump(vm->topCallFrame->codeBlock()), " and last code origin = ",
+ vm->topCallFrame->codeOrigin(), "\n");
+ }
}
-#endif
#if ENABLE(REGEXP_TRACING)
void VM::addRegExpToTrace(RegExp* regExp)
{
+ gcProtect(regExp);
m_rtTraceList->add(regExp);
}
@@ -746,14 +731,16 @@ void VM::dumpRegExpTrace()
if (iter != m_rtTraceList->end()) {
dataLogF("\nRegExp Tracing\n");
- dataLogF(" match() matches\n");
- dataLogF("Regular Expression JIT Address calls found\n");
- dataLogF("----------------------------------------+----------------+----------+----------\n");
+ dataLogF("Regular Expression 8 Bit 16 Bit match() Matches Average\n");
+ dataLogF(" <Match only / Match> JIT Addr JIT Address calls found String len\n");
+ dataLogF("----------------------------------------+----------------+----------------+----------+----------+-----------\n");
unsigned reCount = 0;
- for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
+ for (; iter != m_rtTraceList->end(); ++iter, ++reCount) {
(*iter)->printTraceData();
+ gcUnprotect(*iter);
+ }
dataLogF("%d Regular Expressions\n", reCount);
}
@@ -777,15 +764,15 @@ void VM::registerWatchpointForImpureProperty(const Identifier& propertyName, Wat
void VM::addImpureProperty(const String& propertyName)
{
if (RefPtr<WatchpointSet> watchpointSet = m_impurePropertyWatchpointSets.take(propertyName))
- watchpointSet->fireAll();
+ watchpointSet->fireAll("Impure property added");
}
class SetEnabledProfilerFunctor {
public:
bool operator()(CodeBlock* codeBlock)
{
- if (codeBlock->jitType() == JITCode::DFGJIT)
- codeBlock->jettison();
+ if (JITCode::isOptimizingJIT(codeBlock->jitType()))
+ codeBlock->jettison(Profiler::JettisonDueToLegacyProfiler);
return false;
}
};
@@ -799,4 +786,102 @@ void VM::setEnabledProfiler(LegacyProfiler* profiler)
}
}
+static bool enableProfilerWithRespectToCount(unsigned& counter, std::function<void()> doEnableWork)
+{
+ bool needsToRecompile = false;
+ if (!counter) {
+ doEnableWork();
+ needsToRecompile = true;
+ }
+ counter++;
+
+ return needsToRecompile;
+}
+
+static bool disableProfilerWithRespectToCount(unsigned& counter, std::function<void()> doDisableWork)
+{
+ RELEASE_ASSERT(counter > 0);
+ bool needsToRecompile = false;
+ counter--;
+ if (!counter) {
+ doDisableWork();
+ needsToRecompile = true;
+ }
+
+ return needsToRecompile;
+}
+
+bool VM::enableTypeProfiler()
+{
+ auto enableTypeProfiler = [this] () {
+ this->m_typeProfiler = std::make_unique<TypeProfiler>();
+ this->m_typeProfilerLog = std::make_unique<TypeProfilerLog>();
+ };
+
+ return enableProfilerWithRespectToCount(m_typeProfilerEnabledCount, enableTypeProfiler);
+}
+
+bool VM::disableTypeProfiler()
+{
+ auto disableTypeProfiler = [this] () {
+ this->m_typeProfiler.reset(nullptr);
+ this->m_typeProfilerLog.reset(nullptr);
+ };
+
+ return disableProfilerWithRespectToCount(m_typeProfilerEnabledCount, disableTypeProfiler);
+}
+
+bool VM::enableControlFlowProfiler()
+{
+ auto enableControlFlowProfiler = [this] () {
+ this->m_controlFlowProfiler = std::make_unique<ControlFlowProfiler>();
+ };
+
+ return enableProfilerWithRespectToCount(m_controlFlowProfilerEnabledCount, enableControlFlowProfiler);
+}
+
+bool VM::disableControlFlowProfiler()
+{
+ auto disableControlFlowProfiler = [this] () {
+ this->m_controlFlowProfiler.reset(nullptr);
+ };
+
+ return disableProfilerWithRespectToCount(m_controlFlowProfilerEnabledCount, disableControlFlowProfiler);
+}
+
+void VM::dumpTypeProfilerData()
+{
+ if (!typeProfiler())
+ return;
+
+ typeProfilerLog()->processLogEntries(ASCIILiteral("VM Dump Types"));
+ typeProfiler()->dumpTypeProfilerData(*this);
+}
+
+void VM::queueMicrotask(JSGlobalObject* globalObject, PassRefPtr<Microtask> task)
+{
+ m_microtaskQueue.append(std::make_unique<QueuedTask>(*this, globalObject, task));
+}
+
+void VM::drainMicrotasks()
+{
+ while (!m_microtaskQueue.isEmpty())
+ m_microtaskQueue.takeFirst()->run();
+}
+
+void QueuedTask::run()
+{
+ m_microtask->run(m_globalObject->globalExec());
+}
+
+void sanitizeStackForVM(VM* vm)
+{
+ logSanitizeStack(vm);
+#if !ENABLE(JIT)
+ vm->interpreter->stack().sanitizeStack();
+#else
+ sanitizeStackForVMImpl(vm);
+#endif
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/VM.h b/Source/JavaScriptCore/runtime/VM.h
index 1de423e0e..759bbd97d 100644
--- a/Source/JavaScriptCore/runtime/VM.h
+++ b/Source/JavaScriptCore/runtime/VM.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 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,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.
*
@@ -29,9 +29,13 @@
#ifndef VM_h
#define VM_h
+#include "ControlFlowProfiler.h"
#include "DateInstanceCache.h"
#include "ExecutableAllocator.h"
+#include "FunctionHasExecutedCache.h"
+#if ENABLE(JIT)
#include "GPRInfo.h"
+#endif
#include "Heap.h"
#include "Intrinsic.h"
#include "JITThunks.h"
@@ -39,28 +43,32 @@
#include "JSLock.h"
#include "LLIntData.h"
#include "MacroAssemblerCodeRef.h"
+#include "Microtask.h"
#include "NumericStrings.h"
-#include "ProfilerDatabase.h"
#include "PrivateName.h"
#include "PrototypeMap.h"
#include "SmallStrings.h"
+#include "SourceCode.h"
#include "Strong.h"
#include "ThunkGenerators.h"
#include "TypedArrayController.h"
-#include "Watchdog.h"
+#include "VMEntryRecord.h"
#include "Watchpoint.h"
-#include "WeakRandom.h"
+#include <wtf/Bag.h>
#include <wtf/BumpPointerAllocator.h>
#include <wtf/DateMath.h>
+#include <wtf/Deque.h>
#include <wtf/Forward.h>
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
-#include <wtf/RefCountedArray.h>
#include <wtf/SimpleStats.h>
#include <wtf/StackBounds.h>
+#include <wtf/Stopwatch.h>
#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/ThreadSpecific.h>
#include <wtf/WTFThreadData.h>
+#include <wtf/WeakRandom.h>
+#include <wtf/text/SymbolRegistry.h>
#include <wtf/text/WTFString.h>
#if ENABLE(REGEXP_TRACING)
#include <wtf/ListHashSet.h>
@@ -68,484 +76,631 @@
namespace JSC {
- class CodeBlock;
- class CodeCache;
- class CommonIdentifiers;
- class ExecState;
- class HandleStack;
- class Identifier;
- class IdentifierTable;
- class Interpreter;
- class JSGlobalObject;
- class JSObject;
- class Keywords;
- class LLIntOffsetsExtractor;
- class LegacyProfiler;
- class NativeExecutable;
- class ParserArena;
- class RegExpCache;
- class SourceProvider;
- class SourceProviderCache;
- struct StackFrame;
- class Stringifier;
- class Structure;
+class BuiltinExecutables;
+class BytecodeIntrinsicRegistry;
+class CodeBlock;
+class CodeCache;
+class CommonIdentifiers;
+class CustomGetterSetter;
+class ExecState;
+class Exception;
+class HandleStack;
+class TypeProfiler;
+class TypeProfilerLog;
+class Identifier;
+class Interpreter;
+class JSBoundSlotBaseFunction;
+class JSGlobalObject;
+class JSObject;
+class LLIntOffsetsExtractor;
+class LegacyProfiler;
+class NativeExecutable;
+class RegExpCache;
+class RegisterAtOffsetList;
+#if ENABLE(SAMPLING_PROFILER)
+class SamplingProfiler;
+#endif
+class ScriptExecutable;
+class SourceProvider;
+class SourceProviderCache;
+struct StackFrame;
+class Structure;
#if ENABLE(REGEXP_TRACING)
- class RegExp;
+class RegExp;
#endif
- class UnlinkedCodeBlock;
- class UnlinkedEvalCodeBlock;
- class UnlinkedFunctionExecutable;
- class UnlinkedProgramCodeBlock;
- class VMEntryScope;
- class Watchpoint;
- class WatchpointSet;
+class UnlinkedCodeBlock;
+class UnlinkedEvalCodeBlock;
+class UnlinkedFunctionExecutable;
+class UnlinkedProgramCodeBlock;
+class UnlinkedModuleProgramCodeBlock;
+class VirtualRegister;
+class VMEntryScope;
+class Watchdog;
+class Watchpoint;
+class WatchpointSet;
#if ENABLE(DFG_JIT)
- namespace DFG {
- class LongLivedState;
- class Worklist;
- }
+namespace DFG {
+class LongLivedState;
+}
#endif // ENABLE(DFG_JIT)
#if ENABLE(FTL_JIT)
- namespace FTL {
- class Thunks;
- }
+namespace FTL {
+class Thunks;
+}
#endif // ENABLE(FTL_JIT)
+namespace CommonSlowPaths {
+struct ArityCheckData;
+}
+namespace Profiler {
+class Database;
+}
+
+struct HashTable;
+struct Instruction;
+
+struct LocalTimeOffsetCache {
+ LocalTimeOffsetCache()
+ : start(0.0)
+ , end(-1.0)
+ , increment(0.0)
+ , timeType(WTF::UTCTime)
+ {
+ }
- struct HashTable;
- struct Instruction;
+ void reset()
+ {
+ offset = LocalTimeOffset();
+ start = 0.0;
+ end = -1.0;
+ increment = 0.0;
+ timeType = WTF::UTCTime;
+ }
- struct LocalTimeOffsetCache {
- LocalTimeOffsetCache()
- : start(0.0)
- , end(-1.0)
- , increment(0.0)
- , timeType(WTF::UTCTime)
- {
- }
-
- void reset()
- {
- offset = LocalTimeOffset();
- start = 0.0;
- end = -1.0;
- increment = 0.0;
- timeType = WTF::UTCTime;
- }
+ LocalTimeOffset offset;
+ double start;
+ double end;
+ double increment;
+ WTF::TimeType timeType;
+};
+
+class QueuedTask {
+ WTF_MAKE_NONCOPYABLE(QueuedTask);
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ void run();
+
+ QueuedTask(VM& vm, JSGlobalObject* globalObject, PassRefPtr<Microtask> microtask)
+ : m_globalObject(vm, globalObject)
+ , m_microtask(microtask)
+ {
+ }
- LocalTimeOffset offset;
- double start;
- double end;
- double increment;
- WTF::TimeType timeType;
- };
+private:
+ Strong<JSGlobalObject> m_globalObject;
+ RefPtr<Microtask> m_microtask;
+};
- class ConservativeRoots;
+class ConservativeRoots;
#if COMPILER(MSVC)
#pragma warning(push)
#pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" warning
#endif
- struct ScratchBuffer {
- ScratchBuffer()
- {
- u.m_activeLength = 0;
- }
+struct ScratchBuffer {
+ ScratchBuffer()
+ {
+ u.m_activeLength = 0;
+ }
- static ScratchBuffer* create(size_t size)
- {
- ScratchBuffer* result = new (fastMalloc(ScratchBuffer::allocationSize(size))) ScratchBuffer;
+ static ScratchBuffer* create(size_t size)
+ {
+ ScratchBuffer* result = new (fastMalloc(ScratchBuffer::allocationSize(size))) ScratchBuffer;
- return result;
- }
+ return result;
+ }
- static size_t allocationSize(size_t bufferSize) { return sizeof(ScratchBuffer) + bufferSize; }
- void setActiveLength(size_t activeLength) { u.m_activeLength = activeLength; }
- size_t activeLength() const { return u.m_activeLength; };
- size_t* activeLengthPtr() { return &u.m_activeLength; };
- void* dataBuffer() { return m_buffer; }
+ static size_t allocationSize(size_t bufferSize) { return sizeof(ScratchBuffer) + bufferSize; }
+ void setActiveLength(size_t activeLength) { u.m_activeLength = activeLength; }
+ size_t activeLength() const { return u.m_activeLength; };
+ size_t* activeLengthPtr() { return &u.m_activeLength; };
+ void* dataBuffer() { return m_buffer; }
- union {
- size_t m_activeLength;
- double pad; // Make sure m_buffer is double aligned.
- } u;
+ union {
+ size_t m_activeLength;
+ double pad; // Make sure m_buffer is double aligned.
+ } u;
#if CPU(MIPS) && (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == 2)
- void* m_buffer[0] __attribute__((aligned(8)));
+ void* m_buffer[0] __attribute__((aligned(8)));
#else
- void* m_buffer[0];
+ void* m_buffer[0];
#endif
- };
+};
#if COMPILER(MSVC)
#pragma warning(pop)
#endif
- class VM : public ThreadSafeRefCounted<VM> {
- public:
- // WebCore has a one-to-one mapping of threads to VMs;
- // either create() or createLeaked() should only be called once
- // on a thread, this is the 'default' VM (it uses the
- // thread's default string uniquing table from wtfThreadData).
- // API contexts created using the new context group aware interface
- // create APIContextGroup objects which require less locking of JSC
- // than the old singleton APIShared VM created for use by
- // the original API.
- enum VMType { Default, APIContextGroup, APIShared };
-
- struct ClientData {
- JS_EXPORT_PRIVATE virtual ~ClientData() = 0;
- };
-
- bool isSharedInstance() { return vmType == APIShared; }
- bool usingAPI() { return vmType != Default; }
- JS_EXPORT_PRIVATE static bool sharedInstanceExists();
- JS_EXPORT_PRIVATE static VM& sharedInstance();
-
- JS_EXPORT_PRIVATE static PassRefPtr<VM> create(HeapType = SmallHeap);
- JS_EXPORT_PRIVATE static PassRefPtr<VM> createLeaked(HeapType = SmallHeap);
- static PassRefPtr<VM> createContextGroup(HeapType = SmallHeap);
- JS_EXPORT_PRIVATE ~VM();
-
- void makeUsableFromMultipleThreads() { heap.machineThreads().makeUsableFromMultipleThreads(); }
-
-#if ENABLE(DFG_JIT)
- DFG::Worklist* ensureWorklist();
-#endif // ENABLE(DFG_JIT)
+class VM : public ThreadSafeRefCounted<VM> {
+public:
+ // WebCore has a one-to-one mapping of threads to VMs;
+ // either create() or createLeaked() should only be called once
+ // on a thread, this is the 'default' VM (it uses the
+ // thread's default string uniquing table from wtfThreadData).
+ // API contexts created using the new context group aware interface
+ // create APIContextGroup objects which require less locking of JSC
+ // than the old singleton APIShared VM created for use by
+ // the original API.
+ enum VMType { Default, APIContextGroup, APIShared };
+
+ struct ClientData {
+ JS_EXPORT_PRIVATE virtual ~ClientData() = 0;
+ };
+
+ bool isSharedInstance() { return vmType == APIShared; }
+ bool usingAPI() { return vmType != Default; }
+ JS_EXPORT_PRIVATE static bool sharedInstanceExists();
+ JS_EXPORT_PRIVATE static VM& sharedInstance();
+
+ JS_EXPORT_PRIVATE static Ref<VM> create(HeapType = SmallHeap);
+ JS_EXPORT_PRIVATE static Ref<VM> createLeaked(HeapType = SmallHeap);
+ static Ref<VM> createContextGroup(HeapType = SmallHeap);
+ JS_EXPORT_PRIVATE ~VM();
+
+ JS_EXPORT_PRIVATE Watchdog& ensureWatchdog();
+ JS_EXPORT_PRIVATE Watchdog* watchdog() { return m_watchdog.get(); }
+
+#if ENABLE(SAMPLING_PROFILER)
+ JS_EXPORT_PRIVATE SamplingProfiler* samplingProfiler() { return m_samplingProfiler.get(); }
+ JS_EXPORT_PRIVATE void ensureSamplingProfiler(RefPtr<Stopwatch>&&);
+#endif
- private:
- RefPtr<JSLock> m_apiLock;
+private:
+ RefPtr<JSLock> m_apiLock;
- public:
+public:
#if ENABLE(ASSEMBLER)
- // executableAllocator should be destructed after the heap, as the heap can call executableAllocator
- // in its destructor.
- ExecutableAllocator executableAllocator;
+ // executableAllocator should be destructed after the heap, as the heap can call executableAllocator
+ // in its destructor.
+ ExecutableAllocator executableAllocator;
#endif
- // The heap should be just after executableAllocator and before other members to ensure that it's
- // destructed after all the objects that reference it.
- Heap heap;
-
+ // The heap should be just after executableAllocator and before other members to ensure that it's
+ // destructed after all the objects that reference it.
+ Heap heap;
+
#if ENABLE(DFG_JIT)
- OwnPtr<DFG::LongLivedState> dfgState;
- RefPtr<DFG::Worklist> worklist;
+ std::unique_ptr<DFG::LongLivedState> dfgState;
#endif // ENABLE(DFG_JIT)
- VMType vmType;
- ClientData* clientData;
- ExecState* topCallFrame;
- Watchdog watchdog;
-
- const OwnPtr<const HashTable> arrayConstructorTable;
- const OwnPtr<const HashTable> arrayPrototypeTable;
- const OwnPtr<const HashTable> booleanPrototypeTable;
- const OwnPtr<const HashTable> dataViewTable;
- const OwnPtr<const HashTable> dateTable;
- const OwnPtr<const HashTable> dateConstructorTable;
- const OwnPtr<const HashTable> errorPrototypeTable;
- const OwnPtr<const HashTable> globalObjectTable;
- const OwnPtr<const HashTable> jsonTable;
- const OwnPtr<const HashTable> numberConstructorTable;
- const OwnPtr<const HashTable> numberPrototypeTable;
- const OwnPtr<const HashTable> objectConstructorTable;
- const OwnPtr<const HashTable> privateNamePrototypeTable;
- const OwnPtr<const HashTable> regExpTable;
- const OwnPtr<const HashTable> regExpConstructorTable;
- const OwnPtr<const HashTable> regExpPrototypeTable;
- const OwnPtr<const HashTable> stringConstructorTable;
-#if ENABLE(PROMISES)
- const OwnPtr<const HashTable> promisePrototypeTable;
- const OwnPtr<const HashTable> promiseConstructorTable;
+ VMType vmType;
+ ClientData* clientData;
+ VMEntryFrame* topVMEntryFrame;
+ ExecState* topCallFrame;
+ Strong<Structure> structureStructure;
+ Strong<Structure> structureRareDataStructure;
+ Strong<Structure> terminatedExecutionErrorStructure;
+ Strong<Structure> stringStructure;
+ Strong<Structure> notAnObjectStructure;
+ Strong<Structure> propertyNameIteratorStructure;
+ Strong<Structure> propertyNameEnumeratorStructure;
+ Strong<Structure> getterSetterStructure;
+ Strong<Structure> customGetterSetterStructure;
+ Strong<Structure> scopedArgumentsTableStructure;
+ Strong<Structure> apiWrapperStructure;
+ Strong<Structure> JSScopeStructure;
+ Strong<Structure> executableStructure;
+ Strong<Structure> nativeExecutableStructure;
+ Strong<Structure> evalExecutableStructure;
+ Strong<Structure> programExecutableStructure;
+ Strong<Structure> functionExecutableStructure;
+#if ENABLE(WEBASSEMBLY)
+ Strong<Structure> webAssemblyExecutableStructure;
#endif
+ Strong<Structure> moduleProgramExecutableStructure;
+ Strong<Structure> regExpStructure;
+ Strong<Structure> symbolStructure;
+ Strong<Structure> symbolTableStructure;
+ Strong<Structure> structureChainStructure;
+ Strong<Structure> sparseArrayValueMapStructure;
+ Strong<Structure> templateRegistryKeyStructure;
+ Strong<Structure> arrayBufferNeuteringWatchpointStructure;
+ Strong<Structure> unlinkedFunctionExecutableStructure;
+ Strong<Structure> unlinkedProgramCodeBlockStructure;
+ Strong<Structure> unlinkedEvalCodeBlockStructure;
+ Strong<Structure> unlinkedFunctionCodeBlockStructure;
+ Strong<Structure> unlinkedModuleProgramCodeBlockStructure;
+ Strong<Structure> propertyTableStructure;
+ Strong<Structure> weakMapDataStructure;
+ Strong<Structure> inferredValueStructure;
+ Strong<Structure> inferredTypeStructure;
+ Strong<Structure> inferredTypeTableStructure;
+ Strong<Structure> functionRareDataStructure;
+ Strong<Structure> generatorFrameStructure;
+ Strong<Structure> exceptionStructure;
+ Strong<Structure> promiseDeferredStructure;
+ Strong<Structure> internalPromiseDeferredStructure;
+ Strong<Structure> nativeStdFunctionCellStructure;
+ Strong<Structure> programCodeBlockStructure;
+ Strong<Structure> moduleProgramCodeBlockStructure;
+ Strong<Structure> evalCodeBlockStructure;
+ Strong<Structure> functionCodeBlockStructure;
+ Strong<Structure> webAssemblyCodeBlockStructure;
+
+ Strong<JSCell> iterationTerminator;
+ Strong<JSCell> emptyPropertyNameEnumerator;
+
+ AtomicStringTable* m_atomicStringTable;
+ WTF::SymbolRegistry m_symbolRegistry;
+ CommonIdentifiers* propertyNames;
+ const MarkedArgumentBuffer* emptyList; // Lists are supposed to be allocated on the stack to have their elements properly marked, which is not the case here - but this list has nothing to mark.
+ SmallStrings smallStrings;
+ NumericStrings numericStrings;
+ DateInstanceCache dateInstanceCache;
+ WTF::SimpleStats machineCodeBytesPerBytecodeWordForBaselineJIT;
+ WeakGCMap<std::pair<CustomGetterSetter*, int>, JSBoundSlotBaseFunction> customGetterSetterFunctionMap;
+ WeakGCMap<StringImpl*, JSString, PtrHash<StringImpl*>> stringCache;
+ Strong<JSString> lastCachedString;
+
+ AtomicStringTable* atomicStringTable() const { return m_atomicStringTable; }
+ WTF::SymbolRegistry& symbolRegistry() { return m_symbolRegistry; }
+
+ void setInDefineOwnProperty(bool inDefineOwnProperty)
+ {
+ m_inDefineOwnProperty = inDefineOwnProperty;
+ }
- Strong<Structure> structureStructure;
- Strong<Structure> structureRareDataStructure;
- Strong<Structure> debuggerActivationStructure;
- Strong<Structure> terminatedExecutionErrorStructure;
- Strong<Structure> stringStructure;
- Strong<Structure> notAnObjectStructure;
- Strong<Structure> propertyNameIteratorStructure;
- Strong<Structure> getterSetterStructure;
- Strong<Structure> apiWrapperStructure;
- Strong<Structure> JSScopeStructure;
- Strong<Structure> executableStructure;
- Strong<Structure> nativeExecutableStructure;
- Strong<Structure> evalExecutableStructure;
- Strong<Structure> programExecutableStructure;
- Strong<Structure> functionExecutableStructure;
- Strong<Structure> regExpStructure;
- Strong<Structure> symbolTableStructure;
- Strong<Structure> structureChainStructure;
- Strong<Structure> sparseArrayValueMapStructure;
- Strong<Structure> arrayBufferNeuteringWatchpointStructure;
- Strong<Structure> withScopeStructure;
- Strong<Structure> unlinkedFunctionExecutableStructure;
- Strong<Structure> unlinkedProgramCodeBlockStructure;
- Strong<Structure> unlinkedEvalCodeBlockStructure;
- Strong<Structure> unlinkedFunctionCodeBlockStructure;
- Strong<Structure> propertyTableStructure;
- Strong<Structure> mapDataStructure;
- Strong<Structure> weakMapDataStructure;
- Strong<Structure> promiseDeferredStructure;
- Strong<Structure> promiseReactionStructure;
- Strong<JSCell> iterationTerminator;
-
- IdentifierTable* identifierTable;
- CommonIdentifiers* propertyNames;
- const MarkedArgumentBuffer* emptyList; // Lists are supposed to be allocated on the stack to have their elements properly marked, which is not the case here - but this list has nothing to mark.
- SmallStrings smallStrings;
- NumericStrings numericStrings;
- DateInstanceCache dateInstanceCache;
- WTF::SimpleStats machineCodeBytesPerBytecodeWordForBaselineJIT;
-
- void setInDefineOwnProperty(bool inDefineOwnProperty)
- {
- m_inDefineOwnProperty = inDefineOwnProperty;
- }
-
- bool isInDefineOwnProperty()
- {
- return m_inDefineOwnProperty;
- }
+ bool isInDefineOwnProperty()
+ {
+ return m_inDefineOwnProperty;
+ }
- LegacyProfiler* enabledProfiler() { return m_enabledProfiler; }
- void setEnabledProfiler(LegacyProfiler*);
+ LegacyProfiler* enabledProfiler() { return m_enabledProfiler; }
+ void setEnabledProfiler(LegacyProfiler*);
- void* enabledProfilerAddress() { return &m_enabledProfiler; }
+ void* enabledProfilerAddress() { return &m_enabledProfiler; }
-#if ENABLE(JIT) && ENABLE(LLINT)
- bool canUseJIT() { return m_canUseJIT; }
-#elif ENABLE(JIT)
- bool canUseJIT() { return true; } // jit only
+#if ENABLE(JIT)
+ bool canUseJIT() { return m_canUseJIT; }
#else
- bool canUseJIT() { return false; } // interpreter only
+ bool canUseJIT() { return false; } // interpreter only
#endif
#if ENABLE(YARR_JIT)
- bool canUseRegExpJIT() { return m_canUseRegExpJIT; }
+ bool canUseRegExpJIT() { return m_canUseRegExpJIT; }
#else
- bool canUseRegExpJIT() { return false; } // interpreter only
+ bool canUseRegExpJIT() { return false; } // interpreter only
#endif
- SourceProviderCache* addSourceProviderCache(SourceProvider*);
- void clearSourceProviderCaches();
+ SourceProviderCache* addSourceProviderCache(SourceProvider*);
+ void clearSourceProviderCaches();
- PrototypeMap prototypeMap;
+ PrototypeMap prototypeMap;
- OwnPtr<ParserArena> parserArena;
- typedef HashMap<RefPtr<SourceProvider>, RefPtr<SourceProviderCache>> SourceProviderCacheMap;
- SourceProviderCacheMap sourceProviderCacheMap;
- OwnPtr<Keywords> keywords;
- Interpreter* interpreter;
+ typedef HashMap<RefPtr<SourceProvider>, RefPtr<SourceProviderCache>> SourceProviderCacheMap;
+ SourceProviderCacheMap sourceProviderCacheMap;
+ Interpreter* interpreter;
#if ENABLE(JIT)
- OwnPtr<JITThunks> jitStubs;
- MacroAssemblerCodeRef getCTIStub(ThunkGenerator generator)
- {
- return jitStubs->ctiStub(this, generator);
- }
- NativeExecutable* getHostFunction(NativeFunction, Intrinsic);
+#if NUMBER_OF_CALLEE_SAVES_REGISTERS > 0
+ intptr_t calleeSaveRegistersBuffer[NUMBER_OF_CALLEE_SAVES_REGISTERS];
+
+ static ptrdiff_t calleeSaveRegistersBufferOffset()
+ {
+ return OBJECT_OFFSETOF(VM, calleeSaveRegistersBuffer);
+ }
+#endif // NUMBER_OF_CALLEE_SAVES_REGISTERS > 0
+
+ std::unique_ptr<JITThunks> jitStubs;
+ MacroAssemblerCodeRef getCTIStub(ThunkGenerator generator)
+ {
+ return jitStubs->ctiStub(this, generator);
+ }
+ NativeExecutable* getHostFunction(NativeFunction, Intrinsic, const String& name);
+
+ std::unique_ptr<RegisterAtOffsetList> allCalleeSaveRegisterOffsets;
+
+ RegisterAtOffsetList* getAllCalleeSaveRegisterOffsets() { return allCalleeSaveRegisterOffsets.get(); }
+
+#endif // ENABLE(JIT)
+ std::unique_ptr<CommonSlowPaths::ArityCheckData> arityCheckData;
+#if ENABLE(FTL_JIT)
+ std::unique_ptr<FTL::Thunks> ftlThunks;
#endif
+ NativeExecutable* getHostFunction(NativeFunction, NativeFunction constructor, const String& name);
+
+ static ptrdiff_t exceptionOffset()
+ {
+ return OBJECT_OFFSETOF(VM, m_exception);
+ }
+
+ static ptrdiff_t callFrameForCatchOffset()
+ {
+ return OBJECT_OFFSETOF(VM, callFrameForCatch);
+ }
+
+ static ptrdiff_t targetMachinePCForThrowOffset()
+ {
+ return OBJECT_OFFSETOF(VM, targetMachinePCForThrow);
+ }
+
+ void restorePreviousException(Exception* exception) { setException(exception); }
+
+ void clearException() { m_exception = nullptr; }
+ void clearLastException() { m_lastException = nullptr; }
+
+ ExecState** addressOfCallFrameForCatch() { return &callFrameForCatch; }
+
+ Exception* exception() const { return m_exception; }
+ JSCell** addressOfException() { return reinterpret_cast<JSCell**>(&m_exception); }
+
+ Exception* lastException() const { return m_lastException; }
+ JSCell** addressOfLastException() { return reinterpret_cast<JSCell**>(&m_lastException); }
+
+ JS_EXPORT_PRIVATE void throwException(ExecState*, Exception*);
+ JS_EXPORT_PRIVATE JSValue throwException(ExecState*, JSValue);
+ JS_EXPORT_PRIVATE JSObject* throwException(ExecState*, JSObject*);
+
+ void setFailNextNewCodeBlock() { m_failNextNewCodeBlock = true; }
+ bool getAndClearFailNextNewCodeBlock()
+ {
+ bool result = m_failNextNewCodeBlock;
+ m_failNextNewCodeBlock = false;
+ return result;
+ }
+
+ void* stackPointerAtVMEntry() const { return m_stackPointerAtVMEntry; }
+ void setStackPointerAtVMEntry(void*);
+
+ size_t reservedZoneSize() const { return m_reservedZoneSize; }
+ size_t updateReservedZoneSize(size_t reservedZoneSize);
+
#if ENABLE(FTL_JIT)
- std::unique_ptr<FTL::Thunks> ftlThunks;
+ void updateFTLLargestStackSize(size_t);
+ void** addressOfFTLStackLimit() { return &m_ftlStackLimit; }
#endif
- NativeExecutable* getHostFunction(NativeFunction, NativeFunction constructor);
- static ptrdiff_t exceptionOffset()
- {
- return OBJECT_OFFSETOF(VM, m_exception);
- }
+#if !ENABLE(JIT)
+ void* jsStackLimit() { return m_jsStackLimit; }
+ void setJSStackLimit(void* limit) { m_jsStackLimit = limit; }
+#endif
+ void* stackLimit() { return m_stackLimit; }
+ void** addressOfStackLimit() { return &m_stackLimit; }
- static ptrdiff_t callFrameForThrowOffset()
- {
- return OBJECT_OFFSETOF(VM, callFrameForThrow);
- }
+ bool isSafeToRecurse(size_t neededStackInBytes = 0) const
+ {
+ ASSERT(wtfThreadData().stack().isGrowingDownward());
+ int8_t* curr = reinterpret_cast<int8_t*>(&curr);
+ int8_t* limit = reinterpret_cast<int8_t*>(m_stackLimit);
+ return curr >= limit && static_cast<size_t>(curr - limit) >= neededStackInBytes;
+ }
- static ptrdiff_t targetMachinePCForThrowOffset()
- {
- return OBJECT_OFFSETOF(VM, targetMachinePCForThrow);
- }
+ void* lastStackTop() { return m_lastStackTop; }
+ void setLastStackTop(void*);
- JS_EXPORT_PRIVATE void clearException();
- JS_EXPORT_PRIVATE void clearExceptionStack();
- void getExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack);
- void setExceptionInfo(JSValue& exception, RefCountedArray<StackFrame>& exceptionStack);
- JSValue exception() const { return m_exception; }
- JSValue* addressOfException() { return &m_exception; }
- const RefCountedArray<StackFrame>& exceptionStack() const { return m_exceptionStack; }
-
- JS_EXPORT_PRIVATE JSValue throwException(ExecState*, JSValue);
- JS_EXPORT_PRIVATE JSObject* throwException(ExecState*, JSObject*);
-
- void** addressOfJSStackLimit() { return &m_jsStackLimit; }
- void* jsStackLimit() { return m_jsStackLimit; }
- void setJSStackLimit(void* limit) { m_jsStackLimit = limit; }
-
- void* stackLimit() { return m_stackLimit; }
- void setStackLimit(void* limit) { m_stackLimit = limit; }
- bool isSafeToRecurse(size_t neededStackInBytes = 0) const
- {
- ASSERT(wtfThreadData().stack().isGrowingDownward());
- int8_t* curr = reinterpret_cast<int8_t*>(&curr);
- int8_t* limit = reinterpret_cast<int8_t*>(m_stackLimit);
- return curr >= limit && static_cast<size_t>(curr - limit) >= neededStackInBytes;
- }
+ const ClassInfo* const jsArrayClassInfo;
+ const ClassInfo* const jsFinalObjectClassInfo;
- const ClassInfo* const jsArrayClassInfo;
- const ClassInfo* const jsFinalObjectClassInfo;
-
- ReturnAddressPtr exceptionLocation;
- JSValue hostCallReturnValue;
- ExecState* newCallFrameReturnValue;
- ExecState* callFrameForThrow;
- void* targetMachinePCForThrow;
- Instruction* targetInterpreterPCForThrow;
- uint32_t osrExitIndex;
- void* osrExitJumpDestination;
- Vector<ScratchBuffer*> scratchBuffers;
- size_t sizeOfLastScratchBuffer;
-
- ScratchBuffer* scratchBufferForSize(size_t size)
- {
- if (!size)
- return 0;
-
- if (size > sizeOfLastScratchBuffer) {
- // Protect against a N^2 memory usage pathology by ensuring
- // that at worst, we get a geometric series, meaning that the
- // total memory usage is somewhere around
- // max(scratch buffer size) * 4.
- sizeOfLastScratchBuffer = size * 2;
-
- scratchBuffers.append(ScratchBuffer::create(sizeOfLastScratchBuffer));
- }
-
- ScratchBuffer* result = scratchBuffers.last();
- result->setActiveLength(0);
- return result;
+ JSValue hostCallReturnValue;
+ unsigned varargsLength;
+ ExecState* newCallFrameReturnValue;
+ ExecState* callFrameForCatch;
+ void* targetMachinePCForThrow;
+ Instruction* targetInterpreterPCForThrow;
+ uint32_t osrExitIndex;
+ void* osrExitJumpDestination;
+ Vector<ScratchBuffer*> scratchBuffers;
+ size_t sizeOfLastScratchBuffer;
+
+ bool isExecutingInRegExpJIT { false };
+
+ ScratchBuffer* scratchBufferForSize(size_t size)
+ {
+ if (!size)
+ return 0;
+
+ if (size > sizeOfLastScratchBuffer) {
+ // Protect against a N^2 memory usage pathology by ensuring
+ // that at worst, we get a geometric series, meaning that the
+ // total memory usage is somewhere around
+ // max(scratch buffer size) * 4.
+ sizeOfLastScratchBuffer = size * 2;
+
+ ScratchBuffer* newBuffer = ScratchBuffer::create(sizeOfLastScratchBuffer);
+ RELEASE_ASSERT(newBuffer);
+ scratchBuffers.append(newBuffer);
}
- void gatherConservativeRoots(ConservativeRoots&);
+ ScratchBuffer* result = scratchBuffers.last();
+ result->setActiveLength(0);
+ return result;
+ }
+
+ EncodedJSValue* exceptionFuzzingBuffer(size_t size)
+ {
+ ASSERT(Options::useExceptionFuzz());
+ if (!m_exceptionFuzzBuffer)
+ m_exceptionFuzzBuffer = MallocPtr<EncodedJSValue>::malloc(size);
+ return m_exceptionFuzzBuffer.get();
+ }
+
+ void gatherConservativeRoots(ConservativeRoots&);
+
+ VMEntryScope* entryScope;
- VMEntryScope* entryScope;
+ JSObject* stringRecursionCheckFirstObject { nullptr };
+ HashSet<JSObject*> stringRecursionCheckVisitedObjects;
- HashSet<JSObject*> stringRecursionCheckVisitedObjects;
+ LocalTimeOffsetCache localTimeOffsetCache;
- LocalTimeOffsetCache localTimeOffsetCache;
-
- String cachedDateString;
- double cachedDateStringValue;
+ String cachedDateString;
+ double cachedDateStringValue;
- OwnPtr<Profiler::Database> m_perBytecodeProfiler;
- RefPtr<TypedArrayController> m_typedArrayController;
- RegExpCache* m_regExpCache;
- BumpPointerAllocator m_regExpAllocator;
+ std::unique_ptr<Profiler::Database> m_perBytecodeProfiler;
+ RefPtr<TypedArrayController> m_typedArrayController;
+ RegExpCache* m_regExpCache;
+ BumpPointerAllocator m_regExpAllocator;
#if ENABLE(REGEXP_TRACING)
- typedef ListHashSet<RefPtr<RegExp>> RTTraceList;
- RTTraceList* m_rtTraceList;
+ typedef ListHashSet<RegExp*> RTTraceList;
+ RTTraceList* m_rtTraceList;
#endif
- ThreadIdentifier exclusiveThread;
+ bool hasExclusiveThread() const { return m_apiLock->hasExclusiveThread(); }
+ std::thread::id exclusiveThread() const { return m_apiLock->exclusiveThread(); }
+ void setExclusiveThread(std::thread::id threadId) { m_apiLock->setExclusiveThread(threadId); }
- JS_EXPORT_PRIVATE void resetDateCache();
+ JS_EXPORT_PRIVATE void resetDateCache();
- JS_EXPORT_PRIVATE void startSampling();
- JS_EXPORT_PRIVATE void stopSampling();
- JS_EXPORT_PRIVATE void dumpSampleData(ExecState* exec);
- RegExpCache* regExpCache() { return m_regExpCache; }
+ JS_EXPORT_PRIVATE void startSampling();
+ JS_EXPORT_PRIVATE void stopSampling();
+ JS_EXPORT_PRIVATE void dumpSampleData(ExecState*);
+ RegExpCache* regExpCache() { return m_regExpCache; }
#if ENABLE(REGEXP_TRACING)
- void addRegExpToTrace(PassRefPtr<RegExp> regExp);
+ void addRegExpToTrace(RegExp*);
#endif
- JS_EXPORT_PRIVATE void dumpRegExpTrace();
+ JS_EXPORT_PRIVATE void dumpRegExpTrace();
- bool isCollectorBusy() { return heap.isBusy(); }
- JS_EXPORT_PRIVATE void releaseExecutableMemory();
+ bool isCollectorBusy() { return heap.isBusy(); }
#if ENABLE(GC_VALIDATION)
- bool isInitializingObject() const;
- void setInitializingObjectClass(const ClassInfo*);
+ bool isInitializingObject() const;
+ void setInitializingObjectClass(const ClassInfo*);
#endif
- unsigned m_newStringsSinceLastHashCons;
+ bool currentThreadIsHoldingAPILock() const { return m_apiLock->currentThreadIsHoldingLock(); }
- static const unsigned s_minNumberOfNewStringsToHashCons = 100;
+ JSLock& apiLock() { return *m_apiLock; }
+ CodeCache* codeCache() { return m_codeCache.get(); }
- bool haveEnoughNewStringsToHashCons() { return m_newStringsSinceLastHashCons > s_minNumberOfNewStringsToHashCons; }
- void resetNewStringsSinceLastHashCons() { m_newStringsSinceLastHashCons = 0; }
+ JS_EXPORT_PRIVATE void whenIdle(std::function<void()>);
- bool currentThreadIsHoldingAPILock() const
- {
- return m_apiLock->currentThreadIsHoldingLock() || exclusiveThread == currentThread();
- }
+ JS_EXPORT_PRIVATE void deleteAllCode();
+ JS_EXPORT_PRIVATE void deleteAllLinkedCode();
+
+ void registerWatchpointForImpureProperty(const Identifier&, Watchpoint*);
+
+ // FIXME: Use AtomicString once it got merged with Identifier.
+ JS_EXPORT_PRIVATE void addImpureProperty(const String&);
+
+ BuiltinExecutables* builtinExecutables() { return m_builtinExecutables.get(); }
+
+ bool enableTypeProfiler();
+ bool disableTypeProfiler();
+ TypeProfilerLog* typeProfilerLog() { return m_typeProfilerLog.get(); }
+ TypeProfiler* typeProfiler() { return m_typeProfiler.get(); }
+ JS_EXPORT_PRIVATE void dumpTypeProfilerData();
+
+ FunctionHasExecutedCache* functionHasExecutedCache() { return &m_functionHasExecutedCache; }
+
+ ControlFlowProfiler* controlFlowProfiler() { return m_controlFlowProfiler.get(); }
+ bool enableControlFlowProfiler();
+ bool disableControlFlowProfiler();
+
+ JS_EXPORT_PRIVATE void queueMicrotask(JSGlobalObject*, PassRefPtr<Microtask>);
+ JS_EXPORT_PRIVATE void drainMicrotasks();
+ JS_EXPORT_PRIVATE void setShouldRewriteConstAsVar(bool shouldRewrite) { m_shouldRewriteConstAsVar = shouldRewrite; }
+ ALWAYS_INLINE bool shouldRewriteConstAsVar() { return m_shouldRewriteConstAsVar; }
+
+ inline bool shouldTriggerTermination(ExecState*);
+
+ void setShouldBuildPCToCodeOriginMapping() { m_shouldBuildPCToCodeOriginMapping = true; }
+ bool shouldBuilderPCToCodeOriginMapping() const { return m_shouldBuildPCToCodeOriginMapping; }
+
+ BytecodeIntrinsicRegistry& bytecodeIntrinsicRegistry() { return *m_bytecodeIntrinsicRegistry; }
+
+private:
+ friend class LLIntOffsetsExtractor;
+ friend class ClearExceptionScope;
+
+ VM(VMType, HeapType);
+ static VM*& sharedInstanceInternal();
+ void createNativeThunk();
+
+ void updateStackLimit();
+
+ void setException(Exception* exception)
+ {
+ m_exception = exception;
+ m_lastException = exception;
+ }
- JSLock& apiLock() { return *m_apiLock; }
- CodeCache* codeCache() { return m_codeCache.get(); }
-
- void prepareToDiscardCode();
-
- JS_EXPORT_PRIVATE void discardAllCode();
-
- void registerWatchpointForImpureProperty(const Identifier&, Watchpoint*);
- // FIXME: Use AtomicString once it got merged with Identifier.
- JS_EXPORT_PRIVATE void addImpureProperty(const String&);
-
- private:
- friend class LLIntOffsetsExtractor;
- friend class ClearExceptionScope;
- friend class RecursiveAllocationScope;
-
- VM(VMType, HeapType);
- static VM*& sharedInstanceInternal();
- void createNativeThunk();
#if ENABLE(ASSEMBLER)
- bool m_canUseAssembler;
+ bool m_canUseAssembler;
#endif
#if ENABLE(JIT)
- bool m_canUseJIT;
+ bool m_canUseJIT;
#endif
#if ENABLE(YARR_JIT)
- bool m_canUseRegExpJIT;
+ bool m_canUseRegExpJIT;
#endif
#if ENABLE(GC_VALIDATION)
- const ClassInfo* m_initializingObjectClass;
+ const ClassInfo* m_initializingObjectClass;
#endif
-
-#if USE(SEPARATE_C_AND_JS_STACK)
- struct {
- void* m_stackLimit;
- void* m_jsStackLimit;
- };
+ void* m_stackPointerAtVMEntry;
+ size_t m_reservedZoneSize;
+#if !ENABLE(JIT)
+ struct {
+ void* m_stackLimit;
+ void* m_jsStackLimit;
+ };
#else
- union {
- void* m_stackLimit;
- void* m_jsStackLimit;
- };
-#endif
- JSValue m_exception;
- bool m_inDefineOwnProperty;
- OwnPtr<CodeCache> m_codeCache;
- RefCountedArray<StackFrame> m_exceptionStack;
-
- LegacyProfiler* m_enabledProfiler;
-
- HashMap<String, RefPtr<WatchpointSet>> m_impurePropertyWatchpointSets;
+ union {
+ void* m_stackLimit;
+ void* m_jsStackLimit;
};
+#if ENABLE(FTL_JIT)
+ void* m_ftlStackLimit;
+ size_t m_largestFTLStackSize;
+#endif
+#endif
+ void* m_lastStackTop;
+ Exception* m_exception { nullptr };
+ Exception* m_lastException { nullptr };
+ bool m_failNextNewCodeBlock { false };
+ bool m_inDefineOwnProperty;
+ bool m_shouldRewriteConstAsVar { false };
+ bool m_shouldBuildPCToCodeOriginMapping { false };
+ std::unique_ptr<CodeCache> m_codeCache;
+ LegacyProfiler* m_enabledProfiler;
+ std::unique_ptr<BuiltinExecutables> m_builtinExecutables;
+ HashMap<String, RefPtr<WatchpointSet>> m_impurePropertyWatchpointSets;
+ std::unique_ptr<TypeProfiler> m_typeProfiler;
+ std::unique_ptr<TypeProfilerLog> m_typeProfilerLog;
+ unsigned m_typeProfilerEnabledCount;
+ FunctionHasExecutedCache m_functionHasExecutedCache;
+ std::unique_ptr<ControlFlowProfiler> m_controlFlowProfiler;
+ unsigned m_controlFlowProfilerEnabledCount;
+ Deque<std::unique_ptr<QueuedTask>> m_microtaskQueue;
+ MallocPtr<EncodedJSValue> m_exceptionFuzzBuffer;
+ RefPtr<Watchdog> m_watchdog;
+#if ENABLE(SAMPLING_PROFILER)
+ RefPtr<SamplingProfiler> m_samplingProfiler;
+#endif
+ std::unique_ptr<BytecodeIntrinsicRegistry> m_bytecodeIntrinsicRegistry;
+};
#if ENABLE(GC_VALIDATION)
- inline bool VM::isInitializingObject() const
- {
- return !!m_initializingObjectClass;
- }
+inline bool VM::isInitializingObject() const
+{
+ return !!m_initializingObjectClass;
+}
+
+inline void VM::setInitializingObjectClass(const ClassInfo* initializingObjectClass)
+{
+ m_initializingObjectClass = initializingObjectClass;
+}
+#endif
- inline void VM::setInitializingObjectClass(const ClassInfo* initializingObjectClass)
- {
- m_initializingObjectClass = initializingObjectClass;
- }
+inline Heap* WeakSet::heap() const
+{
+ return &m_vm->heap;
+}
+
+#if ENABLE(JIT)
+extern "C" void sanitizeStackForVMImpl(VM*);
#endif
- inline Heap* WeakSet::heap() const
- {
- return &m_vm->heap;
- }
+void sanitizeStackForVM(VM*);
+void logSanitizeStack(VM*);
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/VMEntryScope.cpp b/Source/JavaScriptCore/runtime/VMEntryScope.cpp
index 47782ce3b..8241dece2 100644
--- a/Source/JavaScriptCore/runtime/VMEntryScope.cpp
+++ b/Source/JavaScriptCore/runtime/VMEntryScope.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-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
@@ -27,69 +27,55 @@
#include "VMEntryScope.h"
#include "Debugger.h"
+#include "Options.h"
+#include "SamplingProfiler.h"
#include "VM.h"
+#include "Watchdog.h"
#include <wtf/StackBounds.h>
namespace JSC {
VMEntryScope::VMEntryScope(VM& vm, JSGlobalObject* globalObject)
: m_vm(vm)
- , m_stack(wtfThreadData().stack())
, m_globalObject(globalObject)
- , m_prev(vm.entryScope)
- , m_prevStackLimit(vm.stackLimit())
- , m_recompilationNeeded(false)
{
+ ASSERT(wtfThreadData().stack().isGrowingDownward());
if (!vm.entryScope) {
-#if ENABLE(ASSEMBLER)
- if (ExecutableAllocator::underMemoryPressure())
- vm.heap.deleteAllCompiledCode();
-#endif
vm.entryScope = this;
// Reset the date cache between JS invocations to force the VM to
- // observe time xone changes.
+ // observe time zone changes.
vm.resetDateCache();
+
+ if (vm.watchdog())
+ vm.watchdog()->enteredVM();
+
+#if ENABLE(SAMPLING_PROFILER)
+ if (SamplingProfiler* samplingProfiler = vm.samplingProfiler())
+ samplingProfiler->noticeVMEntry();
+#endif
}
- // Clear the exception stack between entries
- vm.clearExceptionStack();
- void* limit = m_stack.recursionLimit(requiredCapacity());
- vm.setStackLimit(limit);
+ vm.clearLastException();
}
-VMEntryScope::~VMEntryScope()
+void VMEntryScope::addDidPopListener(std::function<void ()> listener)
{
- m_vm.entryScope = m_prev;
- m_vm.setStackLimit(m_prevStackLimit);
-
- if (m_recompilationNeeded) {
- if (m_vm.entryScope)
- m_vm.entryScope->setRecompilationNeeded(true);
- else {
- if (Debugger* debugger = m_globalObject->debugger())
- debugger->recompileAllJSFunctions(&m_vm);
- }
- }
+ m_didPopListeners.append(listener);
}
-size_t VMEntryScope::requiredCapacity() const
+VMEntryScope::~VMEntryScope()
{
- Interpreter* interpreter = m_vm.interpreter;
+ if (m_vm.entryScope != this)
+ return;
+
+ if (m_vm.watchdog())
+ m_vm.watchdog()->exitedVM();
- // We require a smaller stack budget for the error stack. This is to allow
- // some minimal JS execution to proceed and do the work of throwing a stack
- // overflow error if needed. In contrast, arbitrary JS code will require the
- // more generous stack budget in order to proceed.
- //
- // These sizes were derived from the stack usage of a number of sites when
- // layout occurs when we've already consumed most of the C stack.
- const size_t requiredStack = 128 * KB;
- const size_t errorModeRequiredStack = 64 * KB;
+ m_vm.entryScope = nullptr;
- size_t requiredCapacity = interpreter->isInErrorHandlingMode() ? errorModeRequiredStack : requiredStack;
- RELEASE_ASSERT(m_stack.size() >= requiredCapacity);
- return requiredCapacity;
+ for (auto& listener : m_didPopListeners)
+ listener();
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/VMEntryScope.h b/Source/JavaScriptCore/runtime/VMEntryScope.h
index d5ba823d0..95c60ac97 100644
--- a/Source/JavaScriptCore/runtime/VMEntryScope.h
+++ b/Source/JavaScriptCore/runtime/VMEntryScope.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * 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
@@ -29,6 +29,7 @@
#include "Interpreter.h"
#include <wtf/StackBounds.h>
#include <wtf/StackStats.h>
+#include <wtf/Vector.h>
namespace JSC {
@@ -42,23 +43,14 @@ public:
JSGlobalObject* globalObject() const { return m_globalObject; }
- void setRecompilationNeeded(bool recompileNeeded) { m_recompilationNeeded = recompileNeeded; }
+ void addDidPopListener(std::function<void ()>);
private:
- size_t requiredCapacity() const;
-
VM& m_vm;
- StackStats::CheckPoint m_stackCheckPoint;
- StackBounds m_stack;
JSGlobalObject* m_globalObject;
-
- // m_prev and m_prevStackLimit may belong to a different thread's stack.
- VMEntryScope* m_prev;
- void* m_prevStackLimit;
- bool m_recompilationNeeded;
+ Vector<std::function<void ()>> m_didPopListeners;
};
} // namespace JSC
#endif // VMEntryScope_h
-
diff --git a/Source/JavaScriptCore/runtime/VMInlines.h b/Source/JavaScriptCore/runtime/VMInlines.h
new file mode 100644
index 000000000..7a639352d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/VMInlines.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#ifndef VMInlines_h
+#define VMInlines_h
+
+#include "VM.h"
+#include "Watchdog.h"
+
+namespace JSC {
+
+bool VM::shouldTriggerTermination(ExecState* exec)
+{
+ if (!watchdog())
+ return false;
+ return watchdog()->shouldTerminate(exec);
+}
+
+} // namespace JSC
+
+#endif // LLIntData_h
+
diff --git a/Source/JavaScriptCore/runtime/VarOffset.cpp b/Source/JavaScriptCore/runtime/VarOffset.cpp
new file mode 100644
index 000000000..e0d65e54f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/VarOffset.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "VarOffset.h"
+
+namespace JSC {
+
+void VarOffset::dump(PrintStream& out) const
+{
+ switch (m_kind) {
+ case VarKind::Invalid:
+ out.print("invalid");
+ return;
+ case VarKind::Scope:
+ out.print(scopeOffset());
+ return;
+ case VarKind::Stack:
+ out.print(stackOffset());
+ return;
+ case VarKind::DirectArgument:
+ out.print(capturedArgumentsOffset());
+ return;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace JSC
+
+namespace WTF {
+
+using namespace JSC;
+
+void printInternal(PrintStream& out, VarKind varKind)
+{
+ switch (varKind) {
+ case VarKind::Invalid:
+ out.print("Invalid");
+ return;
+ case VarKind::Scope:
+ out.print("Scope");
+ return;
+ case VarKind::Stack:
+ out.print("Stack");
+ return;
+ case VarKind::DirectArgument:
+ out.print("DirectArgument");
+ return;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace WTF
+
diff --git a/Source/JavaScriptCore/runtime/VarOffset.h b/Source/JavaScriptCore/runtime/VarOffset.h
new file mode 100644
index 000000000..b844f57e4
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/VarOffset.h
@@ -0,0 +1,247 @@
+/*
+ * 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.
+ */
+
+#ifndef VarOffset_h
+#define VarOffset_h
+
+#include "DirectArgumentsOffset.h"
+#include "ScopeOffset.h"
+#include "VirtualRegister.h"
+#include <wtf/HashMap.h>
+
+namespace JSC {
+
+enum class VarKind : uint8_t {
+ Invalid,
+ Scope,
+ Stack,
+ DirectArgument
+};
+
+class VarOffset {
+public:
+ VarOffset()
+ : m_kind(VarKind::Invalid)
+ , m_offset(UINT_MAX)
+ {
+ }
+
+ VarOffset(WTF::HashTableDeletedValueType)
+ : m_kind(VarKind::Invalid)
+ , m_offset(0)
+ {
+ }
+
+ explicit VarOffset(VirtualRegister stackOffset)
+ {
+ if (!stackOffset.isValid()) {
+ m_kind = VarKind::Invalid;
+ m_offset = UINT_MAX;
+ } else {
+ m_kind = VarKind::Stack;
+ m_offset = stackOffset.offset();
+ }
+ }
+
+ explicit VarOffset(ScopeOffset scopeOffset)
+ {
+ if (!scopeOffset) {
+ m_kind = VarKind::Invalid;
+ m_offset = UINT_MAX;
+ } else {
+ m_kind = VarKind::Scope;
+ m_offset = scopeOffset.offset();
+ }
+ }
+
+ explicit VarOffset(DirectArgumentsOffset capturedArgumentsOffset)
+ {
+ if (!capturedArgumentsOffset) {
+ m_kind = VarKind::Invalid;
+ m_offset = UINT_MAX;
+ } else {
+ m_kind = VarKind::DirectArgument;
+ m_offset = capturedArgumentsOffset.offset();
+ }
+ }
+
+ static VarOffset assemble(VarKind kind, unsigned offset)
+ {
+ VarOffset result;
+ result.m_kind = kind;
+ result.m_offset = offset;
+ result.checkSanity();
+ return result;
+ }
+
+ bool isValid() const
+ {
+ return m_kind != VarKind::Invalid;
+ }
+
+ bool operator!() const
+ {
+ return !isValid();
+ }
+
+ VarKind kind() const { return m_kind; }
+
+ bool isStack() const
+ {
+ return m_kind == VarKind::Stack;
+ }
+
+ bool isScope() const
+ {
+ return m_kind == VarKind::Scope;
+ }
+
+ bool isDirectArgument() const
+ {
+ return m_kind == VarKind::DirectArgument;
+ }
+
+ VirtualRegister stackOffsetUnchecked() const
+ {
+ if (!isStack())
+ return VirtualRegister();
+ return VirtualRegister(m_offset);
+ }
+
+ ScopeOffset scopeOffsetUnchecked() const
+ {
+ if (!isScope())
+ return ScopeOffset();
+ return ScopeOffset(m_offset);
+ }
+
+ DirectArgumentsOffset capturedArgumentsOffsetUnchecked() const
+ {
+ if (!isDirectArgument())
+ return DirectArgumentsOffset();
+ return DirectArgumentsOffset(m_offset);
+ }
+
+ VirtualRegister stackOffset() const
+ {
+ ASSERT(isStack());
+ return VirtualRegister(m_offset);
+ }
+
+ ScopeOffset scopeOffset() const
+ {
+ ASSERT(isScope());
+ return ScopeOffset(m_offset);
+ }
+
+ DirectArgumentsOffset capturedArgumentsOffset() const
+ {
+ ASSERT(isDirectArgument());
+ return DirectArgumentsOffset(m_offset);
+ }
+
+ unsigned rawOffset() const
+ {
+ ASSERT(isValid());
+ return m_offset;
+ }
+
+ void checkSanity() const
+ {
+ if (ASSERT_DISABLED)
+ return;
+
+ switch (m_kind) {
+ case VarKind::Invalid:
+ ASSERT(m_offset == UINT_MAX);
+ return;
+ case VarKind::Scope:
+ ASSERT(scopeOffset());
+ return;
+ case VarKind::Stack:
+ ASSERT(stackOffset().isValid());
+ return;
+ case VarKind::DirectArgument:
+ ASSERT(capturedArgumentsOffset());
+ return;
+ }
+
+ ASSERT_NOT_REACHED();
+ }
+
+ bool operator==(const VarOffset& other) const
+ {
+ return m_kind == other.m_kind
+ && m_offset == other.m_offset;
+ }
+
+ bool operator!=(const VarOffset& other) const
+ {
+ return !(*this == other);
+ }
+
+ unsigned hash() const
+ {
+ return WTF::IntHash<unsigned>::hash((static_cast<unsigned>(m_kind) << 20) + m_offset);
+ }
+
+ bool isHashTableDeletedValue() const
+ {
+ return m_kind == VarKind::Invalid && !m_offset;
+ }
+
+ void dump(PrintStream&) const;
+
+private:
+ VarKind m_kind;
+ unsigned m_offset;
+};
+
+struct VarOffsetHash {
+ static unsigned hash(const VarOffset& key) { return key.hash(); }
+ static bool equal(const VarOffset& a, const VarOffset& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+} // namespace JSC
+
+namespace WTF {
+
+void printInternal(PrintStream&, JSC::VarKind);
+
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::VarOffset> {
+ typedef JSC::VarOffsetHash Hash;
+};
+
+template<typename T> struct HashTraits;
+template<> struct HashTraits<JSC::VarOffset> : SimpleClassHashTraits<JSC::VarOffset> {
+ static const bool emptyValueIsZero = false;
+};
+
+} // namespace WTF
+
+#endif // VarOffset_h
+
diff --git a/Source/JavaScriptCore/runtime/Watchdog.cpp b/Source/JavaScriptCore/runtime/Watchdog.cpp
index 573260b16..e463f4dc9 100644
--- a/Source/JavaScriptCore/runtime/Watchdog.cpp
+++ b/Source/JavaScriptCore/runtime/Watchdog.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 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
@@ -32,168 +32,157 @@
namespace JSC {
-#define NO_LIMIT std::numeric_limits<double>::infinity()
+const std::chrono::microseconds Watchdog::noTimeLimit = std::chrono::microseconds::max();
+
+static std::chrono::microseconds currentWallClockTime()
+{
+ auto steadyTimeSinceEpoch = std::chrono::steady_clock::now().time_since_epoch();
+ return std::chrono::duration_cast<std::chrono::microseconds>(steadyTimeSinceEpoch);
+}
Watchdog::Watchdog()
: m_timerDidFire(false)
- , m_didFire(false)
- , m_limit(NO_LIMIT)
- , m_startTime(0)
- , m_elapsedTime(0)
- , m_reentryCount(0)
- , m_isStopped(true)
+ , m_timeLimit(noTimeLimit)
+ , m_cpuDeadline(noTimeLimit)
+ , m_wallClockDeadline(noTimeLimit)
, m_callback(0)
, m_callbackData1(0)
, m_callbackData2(0)
+ , m_timerQueue(WorkQueue::create("jsc.watchdog.queue", WorkQueue::Type::Serial, WorkQueue::QOS::Utility))
{
- initTimer();
-}
-
-Watchdog::~Watchdog()
-{
- ASSERT(!isArmed());
- stopCountdown();
- destroyTimer();
+ m_timerHandler = [this] {
+ {
+ LockHolder locker(m_lock);
+ this->m_timerDidFire = true;
+ }
+ this->deref();
+ };
}
-void Watchdog::setTimeLimit(VM& vm, double limit,
+void Watchdog::setTimeLimit(std::chrono::microseconds limit,
ShouldTerminateCallback callback, void* data1, void* data2)
{
- bool wasEnabled = isEnabled();
-
- if (!m_isStopped)
- stopCountdown();
+ LockHolder locker(m_lock);
- m_didFire = false; // Reset the watchdog.
-
- m_limit = limit;
+ m_timeLimit = limit;
m_callback = callback;
m_callbackData1 = data1;
m_callbackData2 = data2;
- // If this is the first time that timeout is being enabled, then any
- // previously JIT compiled code will not have the needed polling checks.
- // Hence, we need to flush all the pre-existing compiled code.
- //
- // However, if the timeout is already enabled, and we're just changing the
- // timeout value, then any existing JITted code will have the appropriate
- // polling checks. Hence, there is no need to re-do this flushing.
- if (!wasEnabled) {
- // And if we've previously compiled any functions, we need to revert
- // them because they don't have the needed polling checks yet.
- vm.releaseExecutableMemory();
- }
+ if (m_hasEnteredVM && hasTimeLimit())
+ startTimer(locker, m_timeLimit);
+}
+
+JS_EXPORT_PRIVATE void Watchdog::terminateSoon()
+{
+ LockHolder locker(m_lock);
- startCountdownIfNeeded();
+ m_timeLimit = std::chrono::microseconds(0);
+ m_cpuDeadline = std::chrono::microseconds(0);
+ m_wallClockDeadline = std::chrono::microseconds(0);
+ m_timerDidFire = true;
}
-bool Watchdog::didFire(ExecState* exec)
+bool Watchdog::shouldTerminateSlow(ExecState* exec)
{
- if (m_didFire)
- return true;
+ {
+ LockHolder locker(m_lock);
- if (!m_timerDidFire)
- return false;
- m_timerDidFire = false;
- stopCountdown();
-
- double currentTime = currentCPUTime();
- double deltaTime = currentTime - m_startTime;
- double totalElapsedTime = m_elapsedTime + deltaTime;
- if (totalElapsedTime > m_limit) {
- // Case 1: the allowed CPU time has elapsed.
-
- // If m_callback is not set, then we terminate by default.
- // Else, we let m_callback decide if we should terminate or not.
- bool needsTermination = !m_callback
- || m_callback(exec, m_callbackData1, m_callbackData2);
- if (needsTermination) {
- m_didFire = true;
- return true;
- }
+ ASSERT(m_timerDidFire);
+ m_timerDidFire = false;
- // The m_callback may have set a new limit. So, we may need to restart
- // the countdown.
- startCountdownIfNeeded();
+ if (currentWallClockTime() < m_wallClockDeadline)
+ return false; // Just a stale timer firing. Nothing to do.
- } else {
- // Case 2: the allowed CPU time has NOT elapsed.
+ // Set m_wallClockDeadline to noTimeLimit here so that we can reject all future
+ // spurious wakes.
+ m_wallClockDeadline = noTimeLimit;
- // Tell the timer to alarm us again when it thinks we've reached the
- // end of the allowed time.
- double remainingTime = m_limit - totalElapsedTime;
- m_elapsedTime = totalElapsedTime;
- m_startTime = currentTime;
- startCountdown(remainingTime);
+ auto cpuTime = currentCPUTime();
+ if (cpuTime < m_cpuDeadline) {
+ auto remainingCPUTime = m_cpuDeadline - cpuTime;
+ startTimer(locker, remainingCPUTime);
+ return false;
+ }
}
- return false;
-}
+ // Note: we should not be holding the lock while calling the callbacks. The callbacks may
+ // call setTimeLimit() which will try to lock as well.
-bool Watchdog::isEnabled()
-{
- return (m_limit != NO_LIMIT);
+ // If m_callback is not set, then we terminate by default.
+ // Else, we let m_callback decide if we should terminate or not.
+ bool needsTermination = !m_callback
+ || m_callback(exec, m_callbackData1, m_callbackData2);
+ if (needsTermination)
+ return true;
+
+ {
+ LockHolder locker(m_lock);
+
+ // If we get here, then the callback above did not want to terminate execution. As a
+ // result, the callback may have done one of the following:
+ // 1. cleared the time limit (i.e. watchdog is disabled),
+ // 2. set a new time limit via Watchdog::setTimeLimit(), or
+ // 3. did nothing (i.e. allow another cycle of the current time limit).
+ //
+ // In the case of 1, we don't have to do anything.
+ // In the case of 2, Watchdog::setTimeLimit() would already have started the timer.
+ // In the case of 3, we need to re-start the timer here.
+
+ ASSERT(m_hasEnteredVM);
+ bool callbackAlreadyStartedTimer = (m_cpuDeadline != noTimeLimit);
+ if (hasTimeLimit() && !callbackAlreadyStartedTimer)
+ startTimer(locker, m_timeLimit);
+ }
+ return false;
}
-void Watchdog::fire()
+bool Watchdog::hasTimeLimit()
{
- m_didFire = true;
+ return (m_timeLimit != noTimeLimit);
}
-void Watchdog::arm()
+void Watchdog::enteredVM()
{
- m_reentryCount++;
- if (m_reentryCount == 1)
- startCountdownIfNeeded();
+ m_hasEnteredVM = true;
+ if (hasTimeLimit()) {
+ LockHolder locker(m_lock);
+ startTimer(locker, m_timeLimit);
+ }
}
-void Watchdog::disarm()
+void Watchdog::exitedVM()
{
- ASSERT(m_reentryCount > 0);
- if (m_reentryCount == 1)
- stopCountdown();
- m_reentryCount--;
+ ASSERT(m_hasEnteredVM);
+ LockHolder locker(m_lock);
+ stopTimer(locker);
+ m_hasEnteredVM = false;
}
-void Watchdog::startCountdownIfNeeded()
+void Watchdog::startTimer(LockHolder&, std::chrono::microseconds timeLimit)
{
- if (!m_isStopped)
- return; // Already started.
+ ASSERT(m_hasEnteredVM);
+ ASSERT(hasTimeLimit());
+ ASSERT(timeLimit <= m_timeLimit);
- if (!isArmed())
- return; // Not executing JS script. No need to start.
+ m_cpuDeadline = currentCPUTime() + timeLimit;
+ auto wallClockTime = currentWallClockTime();
+ auto wallClockDeadline = wallClockTime + timeLimit;
- if (isEnabled()) {
- m_elapsedTime = 0;
- m_startTime = currentCPUTime();
- startCountdown(m_limit);
- }
-}
-
-void Watchdog::startCountdown(double limit)
-{
- ASSERT(m_isStopped);
- m_isStopped = false;
- startTimer(limit);
-}
+ if ((wallClockTime < m_wallClockDeadline)
+ && (m_wallClockDeadline <= wallClockDeadline))
+ return; // Wait for the current active timer to expire before starting a new one.
-void Watchdog::stopCountdown()
-{
- if (m_isStopped)
- return;
- stopTimer();
- m_isStopped = true;
-}
+ // Else, the current active timer won't fire soon enough. So, start a new timer.
+ this->ref(); // m_timerHandler will deref to match later.
+ m_wallClockDeadline = wallClockDeadline;
-Watchdog::Scope::Scope(Watchdog& watchdog)
- : m_watchdog(watchdog)
-{
- m_watchdog.arm();
+ m_timerQueue->dispatchAfter(std::chrono::nanoseconds(timeLimit), m_timerHandler);
}
-Watchdog::Scope::~Scope()
+void Watchdog::stopTimer(LockHolder&)
{
- m_watchdog.disarm();
+ m_cpuDeadline = noTimeLimit;
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Watchdog.h b/Source/JavaScriptCore/runtime/Watchdog.h
index 15784d6e2..01a869748 100644
--- a/Source/JavaScriptCore/runtime/Watchdog.h
+++ b/Source/JavaScriptCore/runtime/Watchdog.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 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
@@ -26,91 +26,76 @@
#ifndef Watchdog_h
#define Watchdog_h
-#if PLATFORM(MAC) || PLATFORM(IOS)
-#include <dispatch/dispatch.h>
-#endif
+#include <wtf/Lock.h>
+#include <wtf/Ref.h>
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/WorkQueue.h>
namespace JSC {
class ExecState;
class VM;
-class Watchdog {
+class Watchdog : public WTF::ThreadSafeRefCounted<Watchdog> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
class Scope;
Watchdog();
- ~Watchdog();
typedef bool (*ShouldTerminateCallback)(ExecState*, void* data1, void* data2);
- void setTimeLimit(VM&, double seconds, ShouldTerminateCallback = 0, void* data1 = 0, void* data2 = 0);
+ void setTimeLimit(std::chrono::microseconds limit, ShouldTerminateCallback = 0, void* data1 = 0, void* data2 = 0);
+ JS_EXPORT_PRIVATE void terminateSoon();
- // This version of didFire() will check the elapsed CPU time and call the
- // callback (if needed) to determine if the watchdog should fire.
- bool didFire(ExecState*);
+ bool shouldTerminate(ExecState* exec)
+ {
+ if (!m_timerDidFire)
+ return false;
+ return shouldTerminateSlow(exec);
+ }
- bool isEnabled();
-
- // This version of didFire() is a more efficient version for when we want
- // to know if the watchdog has fired in the past, and not whether it should
- // fire right now.
- bool didFire() { return m_didFire; }
- JS_EXPORT_PRIVATE void fire();
+ bool hasTimeLimit();
+ void enteredVM();
+ void exitedVM();
void* timerDidFireAddress() { return &m_timerDidFire; }
+ static const std::chrono::microseconds noTimeLimit;
+
private:
- void arm();
- void disarm();
- void startCountdownIfNeeded();
- void startCountdown(double limit);
- void stopCountdown();
- bool isArmed() { return !!m_reentryCount; }
-
- // Platform specific timer implementation:
- void initTimer();
- void destroyTimer();
- void startTimer(double limit);
- void stopTimer();
-
- // m_timerDidFire (above) indicates whether the timer fired. The Watchdog
+ void startTimer(LockHolder&, std::chrono::microseconds timeLimit);
+ void stopTimer(LockHolder&);
+
+ bool shouldTerminateSlow(ExecState*);
+
+ // m_timerDidFire indicates whether the timer fired. The Watchdog
// still needs to check if the allowed CPU time has elapsed. If so, then
// the Watchdog fires and m_didFire will be set.
// NOTE: m_timerDidFire is only set by the platform specific timer
// (probably from another thread) but is only cleared in the script thread.
bool m_timerDidFire;
- bool m_didFire;
- // All time units are in seconds.
- double m_limit;
- double m_startTime;
- double m_elapsedTime;
+ std::chrono::microseconds m_timeLimit;
+
+ std::chrono::microseconds m_cpuDeadline;
+ std::chrono::microseconds m_wallClockDeadline;
+
+ // Writes to m_timerDidFire and m_timeLimit, and Reads+Writes to m_cpuDeadline and m_wallClockDeadline
+ // must be guarded by this lock.
+ Lock m_lock;
- int m_reentryCount;
- bool m_isStopped;
+ bool m_hasEnteredVM { false };
ShouldTerminateCallback m_callback;
void* m_callbackData1;
void* m_callbackData2;
-#if PLATFORM(MAC) || PLATFORM(IOS)
- dispatch_queue_t m_queue;
- dispatch_source_t m_timer;
-#endif
+ Ref<WorkQueue> m_timerQueue;
+ std::function<void ()> m_timerHandler;
- friend class Watchdog::Scope;
friend class LLIntOffsetsExtractor;
};
-class Watchdog::Scope {
-public:
- Scope(Watchdog&);
- ~Scope();
-
-private:
- Watchdog& m_watchdog;
-};
-
} // namespace JSC
#endif // Watchdog_h
diff --git a/Source/JavaScriptCore/runtime/WatchdogMac.cpp b/Source/JavaScriptCore/runtime/WatchdogMac.cpp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/WatchdogMac.cpp
diff --git a/Source/JavaScriptCore/runtime/WatchdogNone.cpp b/Source/JavaScriptCore/runtime/WatchdogNone.cpp
index 615314bb3..e69de29bb 100644
--- a/Source/JavaScriptCore/runtime/WatchdogNone.cpp
+++ b/Source/JavaScriptCore/runtime/WatchdogNone.cpp
@@ -1,50 +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 "Watchdog.h"
-
-namespace JSC {
-
-// This is a stub for platforms that have not implemented this functionality.
-// In this case, the platform timer here never fires.
-
-void Watchdog::initTimer()
-{
-}
-
-void Watchdog::destroyTimer()
-{
-}
-
-void Watchdog::startTimer(double)
-{
-}
-
-void Watchdog::stopTimer()
-{
-}
-
-} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/WeakGCMap.h b/Source/JavaScriptCore/runtime/WeakGCMap.h
index d9c1fb63e..2627030e0 100644
--- a/Source/JavaScriptCore/runtime/WeakGCMap.h
+++ b/Source/JavaScriptCore/runtime/WeakGCMap.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 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
@@ -37,6 +37,7 @@ namespace JSC {
template<typename KeyArg, typename ValueArg, typename HashArg = typename DefaultHash<KeyArg>::Hash,
typename KeyTraitsArg = HashTraits<KeyArg>>
class WeakGCMap {
+ WTF_MAKE_FAST_ALLOCATED;
typedef Weak<ValueArg> ValueType;
typedef HashMap<KeyArg, ValueType, HashArg, KeyTraitsArg> HashMapType;
@@ -46,10 +47,8 @@ public:
typedef typename HashMapType::iterator iterator;
typedef typename HashMapType::const_iterator const_iterator;
- WeakGCMap()
- : m_gcThreshold(minGCThreshold)
- {
- }
+ explicit WeakGCMap(VM&);
+ ~WeakGCMap();
ValueArg* get(const KeyType& key) const
{
@@ -58,19 +57,7 @@ public:
AddResult set(const KeyType& key, ValueType value)
{
- gcMapIfNeeded();
- return m_map.set(key, std::move(value));
- }
-
- AddResult add(const KeyType& key, ValueType value)
- {
- gcMapIfNeeded();
- AddResult addResult = m_map.add(key, nullptr);
- if (!addResult.iterator->value) { // New value or found a zombie value.
- addResult.isNewEntry = true;
- addResult.iterator->value = std::move(value);
- }
- return addResult;
+ return m_map.set(key, WTFMove(value));
}
bool remove(const KeyType& key)
@@ -83,6 +70,17 @@ public:
m_map.clear();
}
+ bool isEmpty() const
+ {
+ const_iterator it = m_map.begin();
+ const_iterator end = m_map.end();
+ while (it != end) {
+ if (it->value)
+ return true;
+ }
+ return false;
+ }
+
iterator find(const KeyType& key)
{
iterator it = m_map.find(key);
@@ -97,43 +95,27 @@ public:
return const_cast<WeakGCMap*>(this)->find(key);
}
- bool contains(const KeyType& key) const
+ template<typename Functor>
+ void forEach(Functor functor)
{
- return find(key) != m_map.end();
- }
-
-private:
- static const int minGCThreshold = 3;
-
- void gcMap()
- {
- Vector<KeyType, 4> zombies;
-
- for (iterator it = m_map.begin(), end = m_map.end(); it != end; ++it) {
- if (!it->value)
- zombies.append(it->key);
+ for (auto& pair : m_map) {
+ if (pair.value)
+ functor(pair.key, pair.value.get());
}
-
- for (size_t i = 0; i < zombies.size(); ++i)
- m_map.remove(zombies[i]);
}
- void gcMapIfNeeded()
+ bool contains(const KeyType& key) const
{
- if (m_map.size() < m_gcThreshold)
- return;
-
- gcMap();
- m_gcThreshold = std::max(minGCThreshold, m_map.size() * 2 - 1);
+ return find(key) != m_map.end();
}
+ void pruneStaleEntries();
+
+private:
HashMapType m_map;
- int m_gcThreshold;
+ VM& m_vm;
};
-template<typename KeyArg, typename RawMappedArg, typename HashArg, typename KeyTraitsArg>
-const int WeakGCMap<KeyArg, RawMappedArg, HashArg, KeyTraitsArg>::minGCThreshold;
-
} // namespace JSC
#endif // WeakGCMap_h
diff --git a/Source/JavaScriptCore/runtime/WeakGCMapInlines.h b/Source/JavaScriptCore/runtime/WeakGCMapInlines.h
new file mode 100644
index 000000000..b90acc089
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/WeakGCMapInlines.h
@@ -0,0 +1,59 @@
+/*
+ * 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. 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.
+ */
+
+#ifndef WeakGCMapInlines_h
+#define WeakGCMapInlines_h
+
+#include "HeapInlines.h"
+#include "WeakGCMap.h"
+
+namespace JSC {
+
+template<typename KeyArg, typename ValueArg, typename HashArg, typename KeyTraitsArg>
+inline WeakGCMap<KeyArg, ValueArg, HashArg, KeyTraitsArg>::WeakGCMap(VM& vm)
+ : m_vm(vm)
+{
+ vm.heap.registerWeakGCMap(this, [this]() {
+ pruneStaleEntries();
+ });
+}
+
+template<typename KeyArg, typename ValueArg, typename HashArg, typename KeyTraitsArg>
+inline WeakGCMap<KeyArg, ValueArg, HashArg, KeyTraitsArg>::~WeakGCMap()
+{
+ m_vm.heap.unregisterWeakGCMap(this);
+}
+
+template<typename KeyArg, typename ValueArg, typename HashArg, typename KeyTraitsArg>
+NEVER_INLINE void WeakGCMap<KeyArg, ValueArg, HashArg, KeyTraitsArg>::pruneStaleEntries()
+{
+ m_map.removeIf([](typename HashMapType::KeyValuePairType& entry) {
+ return !entry.value;
+ });
+}
+
+} // namespace JSC
+
+#endif // WeakGCMapInlines_h
diff --git a/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp b/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp
index f3540faaa..d60f3fdd5 100644
--- a/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp
@@ -26,15 +26,18 @@
#include "config.h"
#include "WeakMapConstructor.h"
+#include "Error.h"
+#include "IteratorOperations.h"
#include "JSCJSValueInlines.h"
#include "JSCellInlines.h"
#include "JSGlobalObject.h"
#include "JSWeakMap.h"
+#include "StructureInlines.h"
#include "WeakMapPrototype.h"
namespace JSC {
-const ClassInfo WeakMapConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(WeakMapConstructor) };
+const ClassInfo WeakMapConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(WeakMapConstructor) };
void WeakMapConstructor::finishCreation(VM& vm, WeakMapPrototype* prototype)
{
@@ -43,11 +46,87 @@ void WeakMapConstructor::finishCreation(VM& vm, WeakMapPrototype* prototype)
putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum | DontDelete);
}
+static EncodedJSValue JSC_HOST_CALL callWeakMap(ExecState* exec)
+{
+ return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(exec, "WeakMap"));
+}
+
static EncodedJSValue JSC_HOST_CALL constructWeakMap(ExecState* exec)
{
JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject();
- Structure* structure = globalObject->weakMapStructure();
- return JSValue::encode(JSWeakMap::create(exec, structure));
+ Structure* weakMapStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), globalObject->weakMapStructure());
+ JSWeakMap* weakMap = JSWeakMap::create(exec, weakMapStructure);
+ JSValue iterable = exec->argument(0);
+ if (iterable.isUndefinedOrNull())
+ return JSValue::encode(weakMap);
+
+ JSValue adderFunction = weakMap->JSObject::get(exec, exec->propertyNames().set);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ CallData adderFunctionCallData;
+ CallType adderFunctionCallType = getCallData(adderFunction, adderFunctionCallData);
+ if (adderFunctionCallType == CallTypeNone)
+ return JSValue::encode(throwTypeError(exec));
+
+ JSValue iteratorFunction = iterable.get(exec, exec->propertyNames().iteratorSymbol);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ CallData iteratorFunctionCallData;
+ CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData);
+ if (iteratorFunctionCallType == CallTypeNone)
+ return JSValue::encode(throwTypeError(exec));
+
+ ArgList iteratorFunctionArguments;
+ JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (!iterator.isObject())
+ return JSValue::encode(throwTypeError(exec));
+
+ while (true) {
+ JSValue next = iteratorStep(exec, iterator);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (next.isFalse())
+ return JSValue::encode(weakMap);
+
+ JSValue nextItem = iteratorValue(exec, next);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (!nextItem.isObject()) {
+ throwTypeError(exec);
+ iteratorClose(exec, iterator);
+ return JSValue::encode(jsUndefined());
+ }
+
+ JSValue key = nextItem.get(exec, 0);
+ if (exec->hadException()) {
+ iteratorClose(exec, iterator);
+ return JSValue::encode(jsUndefined());
+ }
+
+ JSValue value = nextItem.get(exec, 1);
+ if (exec->hadException()) {
+ iteratorClose(exec, iterator);
+ return JSValue::encode(jsUndefined());
+ }
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(key);
+ arguments.append(value);
+ call(exec, adderFunction, adderFunctionCallType, adderFunctionCallData, weakMap, arguments);
+ if (exec->hadException()) {
+ iteratorClose(exec, iterator);
+ return JSValue::encode(jsUndefined());
+ }
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return JSValue::encode(weakMap);
}
ConstructType WeakMapConstructor::getConstructData(JSCell*, ConstructData& constructData)
@@ -56,9 +135,10 @@ ConstructType WeakMapConstructor::getConstructData(JSCell*, ConstructData& const
return ConstructTypeHost;
}
-CallType WeakMapConstructor::getCallData(JSCell*, CallData&)
+CallType WeakMapConstructor::getCallData(JSCell*, CallData& callData)
{
- return CallTypeNone;
+ callData.native.function = callWeakMap;
+ return CallTypeHost;
}
}
diff --git a/Source/JavaScriptCore/runtime/WeakMapConstructor.h b/Source/JavaScriptCore/runtime/WeakMapConstructor.h
index 66edbcb16..2fc2072d3 100644
--- a/Source/JavaScriptCore/runtime/WeakMapConstructor.h
+++ b/Source/JavaScriptCore/runtime/WeakMapConstructor.h
@@ -31,12 +31,13 @@
namespace JSC {
class WeakMapPrototype;
+class GetterSetter;
class WeakMapConstructor : public InternalFunction {
public:
typedef InternalFunction Base;
- static WeakMapConstructor* create(VM& vm, Structure* structure, WeakMapPrototype* prototype)
+ static WeakMapConstructor* create(VM& vm, Structure* structure, WeakMapPrototype* prototype, GetterSetter*)
{
WeakMapConstructor* constructor = new (NotNull, allocateCell<WeakMapConstructor>(vm.heap)) WeakMapConstructor(vm, structure);
constructor->finishCreation(vm, prototype);
diff --git a/Source/JavaScriptCore/runtime/WeakMapData.cpp b/Source/JavaScriptCore/runtime/WeakMapData.cpp
index 224be8a46..1332e8e06 100644
--- a/Source/JavaScriptCore/runtime/WeakMapData.cpp
+++ b/Source/JavaScriptCore/runtime/WeakMapData.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 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
@@ -36,7 +36,7 @@
namespace JSC {
-const ClassInfo WeakMapData::s_info = { "WeakMapData", 0, 0, 0, CREATE_METHOD_TABLE(WeakMapData) };
+const ClassInfo WeakMapData::s_info = { "WeakMapData", 0, 0, CREATE_METHOD_TABLE(WeakMapData) };
WeakMapData::WeakMapData(VM& vm)
: Base(vm, vm.weakMapDataStructure.get())
@@ -54,6 +54,12 @@ void WeakMapData::destroy(JSCell* cell)
static_cast<WeakMapData*>(cell)->~WeakMapData();
}
+size_t WeakMapData::estimatedSize(JSCell* cell)
+{
+ WeakMapData* thisObj = jsCast<WeakMapData*>(cell);
+ return Base::estimatedSize(cell) + (thisObj->m_map.capacity() * (sizeof(JSObject*) + sizeof(WriteBarrier<Unknown>)));
+}
+
void WeakMapData::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
Base::visitChildren(cell, visitor);
@@ -63,8 +69,8 @@ void WeakMapData::visitChildren(JSCell* cell, SlotVisitor& visitor)
// Rough approximation of the external storage needed for the hashtable.
// This isn't exact, but it is close enough, and proportional to the actual
- // external mermory usage.
- visitor.reportExtraMemoryUsage(thisObj, thisObj->m_map.capacity() * (sizeof(JSObject*) + sizeof(WriteBarrier<Unknown>)));
+ // external memory usage.
+ visitor.reportExtraMemoryVisited(thisObj->m_map.capacity() * (sizeof(JSObject*) + sizeof(WriteBarrier<Unknown>)));
}
void WeakMapData::set(VM& vm, JSObject* key, JSValue value)
diff --git a/Source/JavaScriptCore/runtime/WeakMapData.h b/Source/JavaScriptCore/runtime/WeakMapData.h
index 0cb7b735a..e048a43b8 100644
--- a/Source/JavaScriptCore/runtime/WeakMapData.h
+++ b/Source/JavaScriptCore/runtime/WeakMapData.h
@@ -34,9 +34,10 @@
namespace JSC {
-class WeakMapData : public JSCell {
+class WeakMapData final : public JSCell {
public:
typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
static WeakMapData* create(VM& vm)
{
@@ -47,11 +48,10 @@ public:
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(CompoundType, StructureFlags), info());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
}
static const bool needsDestruction = true;
- static const bool hasImmortalStructure = true;
void set(VM&, JSObject*, JSValue);
JSValue get(JSObject*);
@@ -61,11 +61,16 @@ public:
DECLARE_INFO;
- static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
+ typedef HashMap<JSObject*, WriteBarrier<Unknown>> MapType;
+ MapType::const_iterator begin() const { return m_map.begin(); }
+ MapType::const_iterator end() const { return m_map.end(); }
+
+ int size() const { return m_map.size(); }
private:
WeakMapData(VM&);
static void destroy(JSCell*);
+ static size_t estimatedSize(JSCell*);
static void visitChildren(JSCell*, SlotVisitor&);
void finishCreation(VM&);
@@ -78,11 +83,10 @@ private:
private:
virtual void visitWeakReferences(SlotVisitor&) override;
virtual void finalizeUnconditionally() override;
- int m_liveKeyCount;
+ unsigned m_liveKeyCount;
WeakMapData* m_target;
};
DeadKeyCleaner m_deadKeyCleaner;
- typedef HashMap<JSObject*, WriteBarrier<Unknown>> MapType;
MapType m_map;
};
diff --git a/Source/JavaScriptCore/runtime/WeakMapPrototype.cpp b/Source/JavaScriptCore/runtime/WeakMapPrototype.cpp
index 3a2f9622a..210b917f9 100644
--- a/Source/JavaScriptCore/runtime/WeakMapPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/WeakMapPrototype.cpp
@@ -28,13 +28,13 @@
#include "JSCJSValueInlines.h"
#include "JSWeakMap.h"
+#include "StructureInlines.h"
#include "WeakMapData.h"
namespace JSC {
-const ClassInfo WeakMapPrototype::s_info = { "WeakMap", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(WeakMapPrototype) };
+const ClassInfo WeakMapPrototype::s_info = { "WeakMap", &Base::s_info, 0, CREATE_METHOD_TABLE(WeakMapPrototype) };
-static EncodedJSValue JSC_HOST_CALL protoFuncWeakMapClear(ExecState*);
static EncodedJSValue JSC_HOST_CALL protoFuncWeakMapDelete(ExecState*);
static EncodedJSValue JSC_HOST_CALL protoFuncWeakMapGet(ExecState*);
static EncodedJSValue JSC_HOST_CALL protoFuncWeakMapHas(ExecState*);
@@ -46,34 +46,26 @@ void WeakMapPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
ASSERT(inherits(info()));
vm.prototypeMap.addPrototype(this);
- JSC_NATIVE_FUNCTION(vm.propertyNames->clear, protoFuncWeakMapClear, DontEnum, 0);
- JSC_NATIVE_FUNCTION(vm.propertyNames->deleteKeyword, protoFuncWeakMapDelete, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->get, protoFuncWeakMapGet, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->has, protoFuncWeakMapHas, DontEnum, 1);
- JSC_NATIVE_FUNCTION(vm.propertyNames->set, protoFuncWeakMapSet, DontEnum, 2);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->deleteKeyword, protoFuncWeakMapDelete, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->get, protoFuncWeakMapGet, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, protoFuncWeakMapHas, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->set, protoFuncWeakMapSet, DontEnum, 2);
+
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "WeakMap"), DontEnum | ReadOnly);
}
static WeakMapData* getWeakMapData(CallFrame* callFrame, JSValue value)
{
if (!value.isObject()) {
throwTypeError(callFrame, WTF::ASCIILiteral("Called WeakMap function on non-object"));
- return 0;
+ return nullptr;
}
if (JSWeakMap* weakMap = jsDynamicCast<JSWeakMap*>(value))
return weakMap->weakMapData();
throwTypeError(callFrame, WTF::ASCIILiteral("Called WeakMap function on a non-WeakMap object"));
- return 0;
-}
-
-EncodedJSValue JSC_HOST_CALL protoFuncWeakMapClear(CallFrame* callFrame)
-{
- WeakMapData* map = getWeakMapData(callFrame, callFrame->thisValue());
- if (!map)
- return JSValue::encode(jsUndefined());
- map->clear();
- return JSValue::encode(jsUndefined());
+ return nullptr;
}
EncodedJSValue JSC_HOST_CALL protoFuncWeakMapDelete(CallFrame* callFrame)
@@ -82,9 +74,7 @@ EncodedJSValue JSC_HOST_CALL protoFuncWeakMapDelete(CallFrame* callFrame)
if (!map)
return JSValue::encode(jsUndefined());
JSValue key = callFrame->argument(0);
- if (!key.isObject())
- return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("A WeakMap cannot have a non-object key")));
- return JSValue::encode(jsBoolean(map->remove(asObject(key))));
+ return JSValue::encode(jsBoolean(key.isObject() && map->remove(asObject(key))));
}
EncodedJSValue JSC_HOST_CALL protoFuncWeakMapGet(CallFrame* callFrame)
@@ -94,7 +84,7 @@ EncodedJSValue JSC_HOST_CALL protoFuncWeakMapGet(CallFrame* callFrame)
return JSValue::encode(jsUndefined());
JSValue key = callFrame->argument(0);
if (!key.isObject())
- return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("A WeakMap cannot have a non-object key")));
+ return JSValue::encode(jsUndefined());
return JSValue::encode(map->get(asObject(key)));
}
@@ -104,9 +94,7 @@ EncodedJSValue JSC_HOST_CALL protoFuncWeakMapHas(CallFrame* callFrame)
if (!map)
return JSValue::encode(jsUndefined());
JSValue key = callFrame->argument(0);
- if (!key.isObject())
- return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("A WeakMap cannot have a non-object key")));
- return JSValue::encode(jsBoolean(map->contains(asObject(key))));
+ return JSValue::encode(jsBoolean(key.isObject() && map->contains(asObject(key))));
}
EncodedJSValue JSC_HOST_CALL protoFuncWeakMapSet(CallFrame* callFrame)
diff --git a/Source/JavaScriptCore/runtime/WeakRandom.h b/Source/JavaScriptCore/runtime/WeakRandom.h
deleted file mode 100644
index 3cd1016d3..000000000
--- a/Source/JavaScriptCore/runtime/WeakRandom.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- *
- *
- * Copyright (c) 2009 Ian C. Bullard
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef WeakRandom_h
-#define WeakRandom_h
-
-#include <limits.h>
-#include <wtf/StdLibExtras.h>
-
-namespace JSC {
-
-class WeakRandom {
-public:
- WeakRandom(unsigned seed)
- : m_low(seed ^ 0x49616E42)
- , m_high(seed)
- {
- }
-
- // Returns the seed provided that you've never called get() or getUint32().
- unsigned seedUnsafe() const { return m_high; }
-
- double get()
- {
- return advance() / (UINT_MAX + 1.0);
- }
-
- unsigned getUint32()
- {
- return advance();
- }
-
-private:
- unsigned advance()
- {
- m_high = (m_high << 16) + (m_high >> 16);
- m_high += m_low;
- m_low += m_high;
- return m_high;
- }
-
- unsigned m_low;
- unsigned m_high;
-};
-
-} // namespace JSC
-
-#endif // WeakRandom_h
diff --git a/Source/JavaScriptCore/runtime/WeakSetConstructor.cpp b/Source/JavaScriptCore/runtime/WeakSetConstructor.cpp
new file mode 100644
index 000000000..02fdbddb6
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/WeakSetConstructor.cpp
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "WeakSetConstructor.h"
+
+#include "Error.h"
+#include "IteratorOperations.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSGlobalObject.h"
+#include "JSWeakSet.h"
+#include "StructureInlines.h"
+#include "WeakSetPrototype.h"
+
+namespace JSC {
+
+const ClassInfo WeakSetConstructor::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(WeakSetConstructor) };
+
+void WeakSetConstructor::finishCreation(VM& vm, WeakSetPrototype* prototype)
+{
+ Base::finishCreation(vm, prototype->classInfo()->className);
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), ReadOnly | DontEnum | DontDelete);
+}
+
+static EncodedJSValue JSC_HOST_CALL callWeakSet(ExecState* exec)
+{
+ return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(exec, "WeakSet"));
+}
+
+static EncodedJSValue JSC_HOST_CALL constructWeakSet(ExecState* exec)
+{
+ JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject();
+ Structure* weakSetStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), globalObject->weakSetStructure());
+ JSWeakSet* weakSet = JSWeakSet::create(exec, weakSetStructure);
+ JSValue iterable = exec->argument(0);
+ if (iterable.isUndefinedOrNull())
+ return JSValue::encode(weakSet);
+
+ JSValue adderFunction = weakSet->JSObject::get(exec, exec->propertyNames().add);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ CallData adderFunctionCallData;
+ CallType adderFunctionCallType = getCallData(adderFunction, adderFunctionCallData);
+ if (adderFunctionCallType == CallTypeNone)
+ return JSValue::encode(throwTypeError(exec));
+
+ JSValue iteratorFunction = iterable.get(exec, exec->propertyNames().iteratorSymbol);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ CallData iteratorFunctionCallData;
+ CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData);
+ if (iteratorFunctionCallType == CallTypeNone)
+ return JSValue::encode(throwTypeError(exec));
+
+ ArgList iteratorFunctionArguments;
+ JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (!iterator.isObject())
+ return JSValue::encode(throwTypeError(exec));
+
+ while (true) {
+ JSValue next = iteratorStep(exec, iterator);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (next.isFalse())
+ return JSValue::encode(weakSet);
+
+ JSValue nextValue = iteratorValue(exec, next);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(nextValue);
+ call(exec, adderFunction, adderFunctionCallType, adderFunctionCallData, weakSet, arguments);
+ if (exec->hadException()) {
+ iteratorClose(exec, iterator);
+ return JSValue::encode(jsUndefined());
+ }
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return JSValue::encode(weakSet);
+}
+
+ConstructType WeakSetConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructWeakSet;
+ return ConstructTypeHost;
+}
+
+CallType WeakSetConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callWeakSet;
+ return CallTypeHost;
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.h b/Source/JavaScriptCore/runtime/WeakSetConstructor.h
index 8360c59b2..d9ef2bd1a 100644
--- a/Source/JavaScriptCore/runtime/ArgumentsIteratorConstructor.h
+++ b/Source/JavaScriptCore/runtime/WeakSetConstructor.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple, Inc. All rights reserved.
+ * 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
@@ -23,22 +23,23 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ArgumentsIteratorConstructor_h
-#define ArgumentsIteratorConstructor_h
+#ifndef WeakSetConstructor_h
+#define WeakSetConstructor_h
#include "InternalFunction.h"
namespace JSC {
-class ArgumentsIteratorPrototype;
+class WeakSetPrototype;
+class GetterSetter;
-class ArgumentsIteratorConstructor : public JSNonFinalObject {
+class WeakSetConstructor : public InternalFunction {
public:
- typedef JSNonFinalObject Base;
+ typedef InternalFunction Base;
- static ArgumentsIteratorConstructor* create(VM& vm, Structure* structure, ArgumentsIteratorPrototype* prototype)
+ static WeakSetConstructor* create(VM& vm, Structure* structure, WeakSetPrototype* prototype, GetterSetter*)
{
- ArgumentsIteratorConstructor* constructor = new (NotNull, allocateCell<ArgumentsIteratorConstructor>(vm.heap)) ArgumentsIteratorConstructor(vm, structure);
+ WeakSetConstructor* constructor = new (NotNull, allocateCell<WeakSetConstructor>(vm.heap)) WeakSetConstructor(vm, structure);
constructor->finishCreation(vm, prototype);
return constructor;
}
@@ -51,13 +52,15 @@ public:
}
private:
- ArgumentsIteratorConstructor(VM& vm, Structure* structure)
+ WeakSetConstructor(VM& vm, Structure* structure)
: Base(vm, structure)
{
}
- void finishCreation(VM&, ArgumentsIteratorPrototype*);
+ void finishCreation(VM&, WeakSetPrototype*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
};
}
-#endif // !defined(ArgumentsIteratorConstructor_h)
+#endif // !defined(WeakSetConstructor_h)
diff --git a/Source/JavaScriptCore/runtime/WeakSetPrototype.cpp b/Source/JavaScriptCore/runtime/WeakSetPrototype.cpp
new file mode 100644
index 000000000..8ca5bb6e7
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/WeakSetPrototype.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "WeakSetPrototype.h"
+
+#include "JSCJSValueInlines.h"
+#include "JSWeakSet.h"
+#include "StructureInlines.h"
+#include "WeakMapData.h"
+
+namespace JSC {
+
+const ClassInfo WeakSetPrototype::s_info = { "WeakSet", &Base::s_info, 0, CREATE_METHOD_TABLE(WeakSetPrototype) };
+
+static EncodedJSValue JSC_HOST_CALL protoFuncWeakSetDelete(ExecState*);
+static EncodedJSValue JSC_HOST_CALL protoFuncWeakSetHas(ExecState*);
+static EncodedJSValue JSC_HOST_CALL protoFuncWeakSetAdd(ExecState*);
+
+void WeakSetPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+ vm.prototypeMap.addPrototype(this);
+
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->deleteKeyword, protoFuncWeakSetDelete, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, protoFuncWeakSetHas, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->add, protoFuncWeakSetAdd, DontEnum, 1);
+
+ putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "WeakSet"), DontEnum | ReadOnly);
+}
+
+static WeakMapData* getWeakMapData(CallFrame* callFrame, JSValue value)
+{
+ if (!value.isObject()) {
+ throwTypeError(callFrame, WTF::ASCIILiteral("Called WeakSet function on non-object"));
+ return nullptr;
+ }
+
+ if (JSWeakSet* weakSet = jsDynamicCast<JSWeakSet*>(value))
+ return weakSet->weakMapData();
+
+ throwTypeError(callFrame, WTF::ASCIILiteral("Called WeakSet function on a non-WeakSet object"));
+ return nullptr;
+}
+
+EncodedJSValue JSC_HOST_CALL protoFuncWeakSetDelete(CallFrame* callFrame)
+{
+ WeakMapData* map = getWeakMapData(callFrame, callFrame->thisValue());
+ if (!map)
+ return JSValue::encode(jsUndefined());
+ JSValue key = callFrame->argument(0);
+ return JSValue::encode(jsBoolean(key.isObject() && map->remove(asObject(key))));
+}
+
+EncodedJSValue JSC_HOST_CALL protoFuncWeakSetHas(CallFrame* callFrame)
+{
+ WeakMapData* map = getWeakMapData(callFrame, callFrame->thisValue());
+ if (!map)
+ return JSValue::encode(jsUndefined());
+ JSValue key = callFrame->argument(0);
+ return JSValue::encode(jsBoolean(key.isObject() && map->contains(asObject(key))));
+}
+
+EncodedJSValue JSC_HOST_CALL protoFuncWeakSetAdd(CallFrame* callFrame)
+{
+ WeakMapData* map = getWeakMapData(callFrame, callFrame->thisValue());
+ if (!map)
+ return JSValue::encode(jsUndefined());
+ JSValue key = callFrame->argument(0);
+ if (!key.isObject())
+ return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("Attempted to add a non-object key to a WeakSet")));
+ map->set(callFrame->vm(), asObject(key), jsUndefined());
+ return JSValue::encode(callFrame->thisValue());
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.h b/Source/JavaScriptCore/runtime/WeakSetPrototype.h
index 21839bfa1..94d90f9c9 100644
--- a/Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.h
+++ b/Source/JavaScriptCore/runtime/WeakSetPrototype.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple, Inc. All rights reserved.
+ * 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
@@ -23,20 +23,20 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ArgumentsIteratorPrototype_h
-#define ArgumentsIteratorPrototype_h
+#ifndef WeakSetPrototype_h
+#define WeakSetPrototype_h
#include "JSObject.h"
namespace JSC {
-class ArgumentsIteratorPrototype : public JSNonFinalObject {
+class WeakSetPrototype : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
- static ArgumentsIteratorPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+ static WeakSetPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
{
- ArgumentsIteratorPrototype* prototype = new (NotNull, allocateCell<ArgumentsIteratorPrototype>(vm.heap)) ArgumentsIteratorPrototype(vm, structure);
+ WeakSetPrototype* prototype = new (NotNull, allocateCell<WeakSetPrototype>(vm.heap)) WeakSetPrototype(vm, structure);
prototype->finishCreation(vm, globalObject);
return prototype;
}
@@ -49,7 +49,7 @@ public:
}
private:
- ArgumentsIteratorPrototype(VM& vm, Structure* structure)
+ WeakSetPrototype(VM& vm, Structure* structure)
: Base(vm, structure)
{
}
@@ -58,4 +58,4 @@ private:
}
-#endif // !defined(ArgumentsIteratorPrototype_h)
+#endif // !defined(WeakSetPrototype_h)
diff --git a/Source/JavaScriptCore/runtime/WriteBarrier.h b/Source/JavaScriptCore/runtime/WriteBarrier.h
index 06161cd98..b727d185e 100644
--- a/Source/JavaScriptCore/runtime/WriteBarrier.h
+++ b/Source/JavaScriptCore/runtime/WriteBarrier.h
@@ -71,13 +71,7 @@ template<class T> inline void validateCell(T)
// We have a separate base class with no constructors for use in Unions.
template <typename T> class WriteBarrierBase {
public:
- void set(VM& vm, const JSCell* owner, T* value)
- {
- ASSERT(value);
- ASSERT(!Options::enableConcurrentJIT() || !isCompilationThread());
- validateCell(value);
- setEarlyValue(vm, owner, value);
- }
+ void set(VM&, const JSCell* owner, T* value);
// This is meant to be used like operator=, but is called copyFrom instead, in
// order to kindly inform the C++ compiler that its advice is not appreciated.
@@ -86,20 +80,11 @@ public:
m_cell = other.m_cell;
}
- void setMayBeNull(VM& vm, const JSCell* owner, T* value)
- {
- if (value)
- validateCell(value);
- setEarlyValue(vm, owner, value);
- }
+ void setMayBeNull(VM&, const JSCell* owner, T* value);
// Should only be used by JSCell during early initialisation
// when some basic types aren't yet completely instantiated
- void setEarlyValue(VM&, const JSCell* owner, T* value)
- {
- this->m_cell = reinterpret_cast<JSCell*>(value);
- Heap::writeBarrier(owner, this->m_cell);
- }
+ void setEarlyValue(VM&, const JSCell* owner, T* value);
T* get() const
{
@@ -128,8 +113,7 @@ public:
T** slot() { return reinterpret_cast<T**>(&m_cell); }
- typedef T* (WriteBarrierBase::*UnspecifiedBoolType);
- operator UnspecifiedBoolType*() const { return m_cell ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
+ explicit operator bool() const { return m_cell; }
bool operator!() const { return !m_cell; }
@@ -141,9 +125,7 @@ public:
this->m_cell = reinterpret_cast<JSCell*>(value);
}
-#if ENABLE(GC_VALIDATION)
T* unvalidatedGet() const { return reinterpret_cast<T*>(static_cast<void*>(m_cell)); }
-#endif
private:
JSCell* m_cell;
@@ -151,13 +133,7 @@ private:
template <> class WriteBarrierBase<Unknown> {
public:
- void set(VM&, const JSCell* owner, JSValue value)
- {
- ASSERT(!Options::enableConcurrentJIT() || !isCompilationThread());
- m_value = JSValue::encode(value);
- Heap::writeBarrier(owner, value);
- }
-
+ void set(VM&, const JSCell* owner, JSValue);
void setWithoutWriteBarrier(JSValue value)
{
m_value = JSValue::encode(value);
@@ -169,26 +145,22 @@ public:
}
void clear() { m_value = JSValue::encode(JSValue()); }
void setUndefined() { m_value = JSValue::encode(jsUndefined()); }
+ void setStartingValue(JSValue value) { m_value = JSValue::encode(value); }
bool isNumber() const { return get().isNumber(); }
bool isObject() const { return get().isObject(); }
bool isNull() const { return get().isNull(); }
bool isGetterSetter() const { return get().isGetterSetter(); }
+ bool isCustomGetterSetter() const { return get().isCustomGetterSetter(); }
- JSValue* slot()
+ JSValue* slot() const
{
- union {
- EncodedJSValue* v;
- JSValue* slot;
- } u;
- u.v = &m_value;
- return u.slot;
+ return bitwise_cast<JSValue*>(&m_value);
}
int32_t* tagPointer() { return &bitwise_cast<EncodedValueDescriptor*>(&m_value)->asBits.tag; }
int32_t* payloadPointer() { return &bitwise_cast<EncodedValueDescriptor*>(&m_value)->asBits.payload; }
- typedef JSValue (WriteBarrierBase::*UnspecifiedBoolType);
- operator UnspecifiedBoolType*() const { return get() ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
+ explicit operator bool() const { return !!get(); }
bool operator!() const { return !get(); }
private:
@@ -196,6 +168,7 @@ private:
};
template <typename T> class WriteBarrier : public WriteBarrierBase<T> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
WriteBarrier()
{
@@ -220,12 +193,18 @@ public:
}
};
+enum UndefinedWriteBarrierTagType { UndefinedWriteBarrierTag };
template <> class WriteBarrier<Unknown> : public WriteBarrierBase<Unknown> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
WriteBarrier()
{
this->setWithoutWriteBarrier(JSValue());
}
+ WriteBarrier(UndefinedWriteBarrierTagType)
+ {
+ this->setWithoutWriteBarrier(jsUndefined());
+ }
WriteBarrier(VM& vm, const JSCell* owner, JSValue value)
{
diff --git a/Source/JavaScriptCore/runtime/WriteBarrierInlines.h b/Source/JavaScriptCore/runtime/WriteBarrierInlines.h
new file mode 100644
index 000000000..3b332f3a0
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/WriteBarrierInlines.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 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. 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.
+ */
+
+#ifndef WriteBarrierInlines_h
+#define WriteBarrierInlines_h
+
+#include "VM.h"
+#include "WriteBarrier.h"
+
+namespace JSC {
+
+template <typename T>
+inline void WriteBarrierBase<T>::set(VM& vm, const JSCell* owner, T* value)
+{
+ ASSERT(value);
+ ASSERT(!Options::useConcurrentJIT() || !isCompilationThread());
+ validateCell(value);
+ setEarlyValue(vm, owner, value);
+}
+
+template <typename T>
+inline void WriteBarrierBase<T>::setMayBeNull(VM& vm, const JSCell* owner, T* value)
+{
+ if (value)
+ validateCell(value);
+ setEarlyValue(vm, owner, value);
+}
+
+template <typename T>
+inline void WriteBarrierBase<T>::setEarlyValue(VM& vm, const JSCell* owner, T* value)
+{
+ this->m_cell = reinterpret_cast<JSCell*>(value);
+ vm.heap.writeBarrier(owner, this->m_cell);
+}
+
+inline void WriteBarrierBase<Unknown>::set(VM& vm, const JSCell* owner, JSValue value)
+{
+ ASSERT(!Options::useConcurrentJIT() || !isCompilationThread());
+ m_value = JSValue::encode(value);
+ vm.heap.writeBarrier(owner, value);
+}
+
+} // namespace JSC
+
+#endif // WriteBarrierInlines_h