diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog index 34845aed6708ed605a0027a46db400ae6e1cce0a..ca52ee87c5f09f4c7ffddccb62a7ca0f73bff5d4 100644 --- a/LayoutTests/ChangeLog +++ b/LayoutTests/ChangeLog @@ -1,3 +1,16 @@ +2013-09-10 Oliver Hunt + + Support WeakMap + https://bugs.webkit.org/show_bug.cgi?id=120912 + + Reviewed by Geoffrey Garen. + + Basic tests. + + * js/basic-weakmap-expected.txt: Added. + * js/basic-weakmap.html: Added. + * js/script-tests/basic-weakmap.js: Added. + 2013-09-10 Ryosuke Niwa Fix race in fast/loader/onunload-form-submit-crash.html diff --git a/LayoutTests/js/basic-weakmap-expected.txt b/LayoutTests/js/basic-weakmap-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..c101e8611ad29b7052fec08594bc854fc4484ec9 --- /dev/null +++ b/LayoutTests/js/basic-weakmap-expected.txt @@ -0,0 +1,46 @@ +Tests basic correctness of ES WeakMap object + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS WeakMap instanceof WeakMap is false +PASS WeakMap.prototype instanceof WeakMap is false +PASS new WeakMap() instanceof WeakMap is true +PASS WeakMap() threw exception TypeError: Function is not a function (evaluating 'WeakMap()'). +PASS map.set(0, 1) threw exception TypeError: Attempted to set a non-object key in a WeakMap. +PASS map.set(0.5, 1) threw exception TypeError: Attempted to set a non-object key in a WeakMap. +PASS map.set('foo', 1) threw exception TypeError: Attempted to set a non-object key in a WeakMap. +PASS map.set(true, 1) threw exception TypeError: Attempted to set a non-object key in a WeakMap. +PASS map.set(false, 1) threw exception TypeError: Attempted to set a non-object key in a WeakMap. +PASS map.set(null, 1) threw exception TypeError: Attempted to set a non-object key in a WeakMap. +PASS map.set(undefined, 1) threw exception TypeError: Attempted to set a non-object key in a WeakMap. +PASS map.get(0) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.get(0.5) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.get('foo') threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.get(true) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.get(false) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.get(null) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.get(undefined) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.has(0) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.has(0.5) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.has('foo') threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.has(true) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.has(false) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.has(null) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.has(undefined) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.delete(0) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.delete(0.5) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.delete('foo') threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.delete(true) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.delete(false) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.delete(null) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.delete(undefined) threw exception TypeError: A WeakMap cannot have a non-object key. +PASS map.set(new String('foo'), 'foo') is map +PASS map.get(new String('foo')) is undefined +PASS map.has(new String('foo')) is false +PASS Math.abs(currentObjectCount - keyLessObjectCount) < 100 is true +PASS (keyLessObjectCount - valueLessObjectCount) > 1500 is true +PASS successfullyParsed is true + +TEST COMPLETE + diff --git a/LayoutTests/js/basic-weakmap.html b/LayoutTests/js/basic-weakmap.html new file mode 100644 index 0000000000000000000000000000000000000000..08fc37e8e3de65ee558651485de45200777d0a2b --- /dev/null +++ b/LayoutTests/js/basic-weakmap.html @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/LayoutTests/js/script-tests/basic-weakmap.js b/LayoutTests/js/script-tests/basic-weakmap.js new file mode 100644 index 0000000000000000000000000000000000000000..974d9d0eb46e6cea9f073716711f956b1062f991 --- /dev/null +++ b/LayoutTests/js/script-tests/basic-weakmap.js @@ -0,0 +1,74 @@ +description("Tests basic correctness of ES WeakMap object"); + +// Currently we don't support iterators, so we throw +// on any non-throwing parameters +shouldBeFalse("WeakMap instanceof WeakMap"); +shouldBeFalse("WeakMap.prototype instanceof WeakMap"); +shouldBeTrue("new WeakMap() instanceof WeakMap"); + +shouldThrow("WeakMap()"); + +var map = new WeakMap; +shouldThrow("map.set(0, 1)") +shouldThrow("map.set(0.5, 1)") +shouldThrow("map.set('foo', 1)") +shouldThrow("map.set(true, 1)") +shouldThrow("map.set(false, 1)") +shouldThrow("map.set(null, 1)") +shouldThrow("map.set(undefined, 1)") +shouldThrow("map.get(0)") +shouldThrow("map.get(0.5)") +shouldThrow("map.get('foo')") +shouldThrow("map.get(true)") +shouldThrow("map.get(false)") +shouldThrow("map.get(null)") +shouldThrow("map.get(undefined)") +shouldThrow("map.has(0)") +shouldThrow("map.has(0.5)") +shouldThrow("map.has('foo')") +shouldThrow("map.has(true)") +shouldThrow("map.has(false)") +shouldThrow("map.has(null)") +shouldThrow("map.has(undefined)") +shouldThrow("map.delete(0)") +shouldThrow("map.delete(0.5)") +shouldThrow("map.delete('foo')") +shouldThrow("map.delete(true)") +shouldThrow("map.delete(false)") +shouldThrow("map.delete(null)") +shouldThrow("map.delete(undefined)") + +shouldBe("map.set(new String('foo'), 'foo')", "map"); +shouldBe("map.get(new String('foo'))", "undefined"); +shouldBeFalse("map.has(new String('foo'))"); + +var keys = []; +var values = []; + +var count = 2000; +for (var i = 0; i < count; i++) { + keys[i] = {} + values[i] = {v : keys[i]} + keys[i].v = values[i] +} +for (var i = 0; i < count; i++) { + map.set(keys[i], values[i]) +} +gc(); + +if (this.GCController) { + var currentObjectCount = GCController.getJSObjectCount() + keys = null; + gc(); + var keyLessObjectCount = GCController.getJSObjectCount() + // Somewhat approximate + shouldBeTrue("Math.abs(currentObjectCount - keyLessObjectCount) < 100"); + for (var i = 0; i < count; i++) { + if (map.get(values[i].v) != values[i]) + fail("Key was incorrectly removed from weak map"); + } + values = null; + gc(); + var valueLessObjectCount = GCController.getJSObjectCount() + shouldBeTrue("(keyLessObjectCount - valueLessObjectCount) > " + (count * 3 / 4)); +} diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index 96f550fc7c2a6dafd147953f5bb4170e1f0c9d05..f020c3f769af0af2bf3ed55c5748a0ca5bde418b 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -342,6 +342,7 @@ set(JavaScriptCore_SOURCES runtime/JSTypedArrayPrototypes.cpp runtime/JSTypedArrays.cpp runtime/JSVariableObject.cpp + runtime/JSWeakMap.cpp runtime/JSWithScope.cpp runtime/JSWrapperObject.cpp runtime/LiteralParser.cpp @@ -396,6 +397,9 @@ set(JavaScriptCore_SOURCES runtime/VM.cpp runtime/Watchdog.cpp runtime/WatchdogNone.cpp + runtime/WeakMapConstructor.cpp + runtime/WeakMapData.cpp + runtime/WeakMapPrototype.cpp tools/CodeProfile.cpp tools/CodeProfiling.cpp diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index 4e4c6542aeeeb7f9d28096534556f68f25884d07..4e764cf597953f305ce00d58863dc73f3b287734 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,74 @@ +2013-09-09 Oliver Hunt + + Support WeakMap + https://bugs.webkit.org/show_bug.cgi?id=120912 + + Reviewed by Geoffrey Garen. + + Add support for ES6 WeakMap. Add the cluster of boilerplate + classes around the core WeakMapData class. + + WeakMapData is a simple object->value hash table that uses a + combo of WeakReferenceHarvester to conditionally keep the weak + value reference live, and UnconditionalFinalizer to clean the + dead keys from the table post-GC. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: + * JavaScriptCore.xcodeproj/project.pbxproj: + * Target.pri: + * runtime/CommonIdentifiers.h: + * runtime/JSGlobalObject.cpp: + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::weakMapDataStructure): + * runtime/JSWeakMap.cpp: Added. + (JSC::JSWeakMap::finishCreation): + (JSC::JSWeakMap::visitChildren): + * runtime/JSWeakMap.h: Added. + (JSC::JSWeakMap::createStructure): + (JSC::JSWeakMap::create): + (JSC::JSWeakMap::weakMapData): + (JSC::JSWeakMap::JSWeakMap): + * runtime/WeakMapConstructor.cpp: Added. + (JSC::WeakMapConstructor::finishCreation): + (JSC::constructWeakMap): + (JSC::WeakMapConstructor::getConstructData): + (JSC::WeakMapConstructor::getCallData): + * runtime/WeakMapConstructor.h: Added. + (JSC::WeakMapConstructor::create): + (JSC::WeakMapConstructor::createStructure): + (JSC::WeakMapConstructor::WeakMapConstructor): + * runtime/WeakMapData.cpp: Added. + (JSC::WeakMapData::WeakMapData): + (JSC::WeakMapData::finishCreation): + (JSC::WeakMapData::destroy): + (JSC::WeakMapData::visitChildren): + (JSC::WeakMapData::set): + (JSC::WeakMapData::get): + (JSC::WeakMapData::remove): + (JSC::WeakMapData::contains): + (JSC::WeakMapData::clear): + (JSC::WeakMapData::DeadKeyCleaner::visitWeakReferences): + (JSC::WeakMapData::DeadKeyCleaner::finalizeUnconditionally): + * runtime/WeakMapData.h: Added. + (JSC::WeakMapData::create): + (JSC::WeakMapData::createStructure): + (JSC::WeakMapData::DeadKeyCleaner::DeadKeyCleaner): + * runtime/WeakMapPrototype.cpp: Added. + (JSC::WeakMapPrototype::finishCreation): + (JSC::getWeakMapData): + (JSC::protoFuncWeakMapClear): + (JSC::protoFuncWeakMapDelete): + (JSC::protoFuncWeakMapGet): + (JSC::protoFuncWeakMapHas): + (JSC::protoFuncWeakMapSet): + * runtime/WeakMapPrototype.h: Added. + (JSC::WeakMapPrototype::create): + (JSC::WeakMapPrototype::createStructure): + (JSC::WeakMapPrototype::WeakMapPrototype): + 2013-09-10 Joseph Pecoraro Web Inspector: [JSC] Caught exception is treated as uncaught diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am index b2e8f0437d425a068fe57af5fc44923ced89b184..5354557b990953cd0032c008fbfb1f562b08ed5e 100644 --- a/Source/JavaScriptCore/GNUmakefile.list.am +++ b/Source/JavaScriptCore/GNUmakefile.list.am @@ -921,6 +921,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/runtime/JSUint32Array.h \ Source/JavaScriptCore/runtime/JSUint8Array.h \ Source/JavaScriptCore/runtime/JSUint8ClampedArray.h \ + Source/JavaScriptCore/runtime/JSWeakMap.cpp \ + Source/JavaScriptCore/runtime/JSWeakMap.h \ Source/JavaScriptCore/runtime/JSWithScope.cpp \ Source/JavaScriptCore/runtime/JSNameScope.cpp \ Source/JavaScriptCore/runtime/JSNameScope.h \ @@ -1070,6 +1072,12 @@ javascriptcore_sources += \ Source/JavaScriptCore/runtime/Watchdog.h \ Source/JavaScriptCore/runtime/WatchdogNone.cpp \ Source/JavaScriptCore/runtime/WeakGCMap.h \ + Source/JavaScriptCore/runtime/WeakMapConstructor.cpp \ + Source/JavaScriptCore/runtime/WeakMapConstructor.h \ + Source/JavaScriptCore/runtime/WeakMapData.cpp \ + Source/JavaScriptCore/runtime/WeakMapData.h \ + Source/JavaScriptCore/runtime/WeakMapPrototype.cpp \ + Source/JavaScriptCore/runtime/WeakMapPrototype.h \ Source/JavaScriptCore/runtime/WeakRandom.h \ Source/JavaScriptCore/runtime/WriteBarrier.h \ Source/JavaScriptCore/tools/CodeProfile.cpp \ diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj index 23d661a681b76c946fe634a4beac7b82a72ba92d..5c5d207a037e9d3ee7a8c453174a4152d261dd10 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj +++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj @@ -493,6 +493,7 @@ + @@ -546,6 +547,9 @@ + + + @@ -934,6 +938,7 @@ + @@ -1009,6 +1014,9 @@ + + + diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters index e3af98d0fe76098dbb0ffc1f5b4d5378330b9e68..4733ae6918250cf9ed542f9fe738bbe3e5306338 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters +++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters @@ -612,6 +612,9 @@ runtime + + runtime + runtime @@ -858,6 +861,15 @@ runtime + + runtime + + + runtime + + + runtime + heap diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index ba26ec2e423f1967d836eeb522e0dc959b3648ae..fd70c38b07abbf2874718c477dbce2a9deef7c81 100644 --- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -939,6 +939,14 @@ A7C1EAF017987AB600299DB2 /* JSStackInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = A7C1EAEB17987AB600299DB2 /* JSStackInlines.h */; }; A7C1EAF117987AB600299DB2 /* StackVisitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7C1EAEC17987AB600299DB2 /* StackVisitor.cpp */; }; A7C1EAF217987AB600299DB2 /* StackVisitor.h in Headers */ = {isa = PBXBuildFile; fileRef = A7C1EAED17987AB600299DB2 /* StackVisitor.h */; settings = {ATTRIBUTES = (Private, ); }; }; + A7CA3AE317DA41AE006538AF /* WeakMapConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7CA3ADD17DA41AE006538AF /* WeakMapConstructor.cpp */; }; + A7CA3AE417DA41AE006538AF /* WeakMapConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = A7CA3ADE17DA41AE006538AF /* WeakMapConstructor.h */; }; + A7CA3AE517DA41AE006538AF /* WeakMapPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7CA3ADF17DA41AE006538AF /* WeakMapPrototype.cpp */; }; + A7CA3AE617DA41AE006538AF /* WeakMapPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A7CA3AE017DA41AE006538AF /* WeakMapPrototype.h */; }; + A7CA3AE717DA41AE006538AF /* JSWeakMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7CA3AE117DA41AE006538AF /* JSWeakMap.cpp */; }; + A7CA3AE817DA41AE006538AF /* JSWeakMap.h in Headers */ = {isa = PBXBuildFile; fileRef = A7CA3AE217DA41AE006538AF /* JSWeakMap.h */; }; + A7CA3AEB17DA5168006538AF /* WeakMapData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7CA3AE917DA5168006538AF /* WeakMapData.cpp */; }; + A7CA3AEC17DA5168006538AF /* WeakMapData.h in Headers */ = {isa = PBXBuildFile; fileRef = A7CA3AEA17DA5168006538AF /* WeakMapData.h */; }; A7D89CF217A0B8CC00773AD8 /* DFGBasicBlock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7D89CE317A0B8CC00773AD8 /* DFGBasicBlock.cpp */; }; A7D89CF317A0B8CC00773AD8 /* DFGBlockInsertionSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7D89CE417A0B8CC00773AD8 /* DFGBlockInsertionSet.cpp */; }; A7D89CF417A0B8CC00773AD8 /* DFGBlockInsertionSet.h in Headers */ = {isa = PBXBuildFile; fileRef = A7D89CE517A0B8CC00773AD8 /* DFGBlockInsertionSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -2147,6 +2155,14 @@ A7C1EAED17987AB600299DB2 /* StackVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackVisitor.h; sourceTree = ""; }; A7C225CC139981F100FF1662 /* KeywordLookupGenerator.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = KeywordLookupGenerator.py; sourceTree = ""; }; A7C225CD1399849C00FF1662 /* KeywordLookup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeywordLookup.h; sourceTree = ""; }; + A7CA3ADD17DA41AE006538AF /* WeakMapConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakMapConstructor.cpp; sourceTree = ""; }; + A7CA3ADE17DA41AE006538AF /* WeakMapConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakMapConstructor.h; sourceTree = ""; }; + A7CA3ADF17DA41AE006538AF /* WeakMapPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakMapPrototype.cpp; sourceTree = ""; }; + A7CA3AE017DA41AE006538AF /* WeakMapPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakMapPrototype.h; sourceTree = ""; }; + A7CA3AE117DA41AE006538AF /* JSWeakMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWeakMap.cpp; sourceTree = ""; }; + A7CA3AE217DA41AE006538AF /* JSWeakMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWeakMap.h; sourceTree = ""; }; + A7CA3AE917DA5168006538AF /* WeakMapData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakMapData.cpp; sourceTree = ""; }; + A7CA3AEA17DA5168006538AF /* WeakMapData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakMapData.h; sourceTree = ""; }; A7D89CE317A0B8CC00773AD8 /* DFGBasicBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGBasicBlock.cpp; path = dfg/DFGBasicBlock.cpp; sourceTree = ""; }; A7D89CE417A0B8CC00773AD8 /* DFGBlockInsertionSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGBlockInsertionSet.cpp; path = dfg/DFGBlockInsertionSet.cpp; sourceTree = ""; }; A7D89CE517A0B8CC00773AD8 /* DFGBlockInsertionSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBlockInsertionSet.h; path = dfg/DFGBlockInsertionSet.h; sourceTree = ""; }; @@ -3380,6 +3396,14 @@ 14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */, 1420BE7A10AA6DDB00F455D2 /* WeakRandom.h */, A7DCB77912E3D90500911940 /* WriteBarrier.h */, + A7CA3ADD17DA41AE006538AF /* WeakMapConstructor.cpp */, + A7CA3ADE17DA41AE006538AF /* WeakMapConstructor.h */, + A7CA3ADF17DA41AE006538AF /* WeakMapPrototype.cpp */, + A7CA3AE017DA41AE006538AF /* WeakMapPrototype.h */, + A7CA3AE117DA41AE006538AF /* JSWeakMap.cpp */, + A7CA3AE217DA41AE006538AF /* JSWeakMap.h */, + A7CA3AE917DA5168006538AF /* WeakMapData.cpp */, + A7CA3AEA17DA5168006538AF /* WeakMapData.h */, ); path = runtime; sourceTree = ""; @@ -3992,6 +4016,7 @@ 0FC0976A1468A6F700CF2442 /* DFGOSRExit.h in Headers */, 0F235BEC17178E7300690C7F /* DFGOSRExitBase.h in Headers */, 0FFB921C16D02F110055A5DB /* DFGOSRExitCompilationInfo.h in Headers */, + A7CA3AEC17DA5168006538AF /* WeakMapData.h in Headers */, 0FC0977114693AF500CF2442 /* DFGOSRExitCompiler.h in Headers */, 0F7025AA1714B0FC00382C0E /* DFGOSRExitCompilerCommon.h in Headers */, 0FEFC9AB1681A3B600567F53 /* DFGOSRExitJumpPlaceholder.h in Headers */, @@ -4212,6 +4237,7 @@ 14874AE615EBDE4A002E3587 /* JSScope.h in Headers */, A7C0C4AC168103020017011D /* JSScriptRefPrivate.h in Headers */, 0F919D11157F332C004A4E7D /* JSSegmentedVariableObject.h in Headers */, + A7CA3AE817DA41AE006538AF /* JSWeakMap.h in Headers */, A7299D9E17D12837005F5FF9 /* JSSet.h in Headers */, BC18C45E0E16F5CD00B34460 /* JSStack.h in Headers */, A7C1EAF017987AB600299DB2 /* JSStackInlines.h in Headers */, @@ -4337,6 +4363,7 @@ 0FF729BA166AD360000F5BA3 /* ProfilerCompilation.h in Headers */, 0FF729BB166AD360000F5BA3 /* ProfilerCompilationKind.h in Headers */, 0FD8A32617D51F5700CA2C40 /* DFGOSREntrypointCreationPhase.h in Headers */, + A7CA3AE417DA41AE006538AF /* WeakMapConstructor.h in Headers */, 0FF729BC166AD360000F5BA3 /* ProfilerCompiledBytecode.h in Headers */, 0FF729BD166AD360000F5BA3 /* ProfilerDatabase.h in Headers */, 0FF729BE166AD360000F5BA3 /* ProfilerExecutionCounter.h in Headers */, @@ -4402,6 +4429,7 @@ BC18C46A0E16F5CD00B34460 /* StringPrototype.h in Headers */, 142E313B134FF0A600AFADB5 /* Strong.h in Headers */, 145722861437E140005FDE26 /* StrongInlines.h in Headers */, + A7CA3AE617DA41AE006538AF /* WeakMapPrototype.h in Headers */, BCDE3AB80E6C82F5001453A7 /* Structure.h in Headers */, 7E4EE7090EBB7963005934AA /* StructureChain.h in Headers */, 0FD2C92416D01EE900C7803F /* StructureInlines.h in Headers */, @@ -4986,6 +5014,7 @@ 147F39CC107EC37600427A48 /* FunctionPrototype.cpp in Sources */, C2D58C3415912FEE0021A844 /* GCActivityCallback.cpp in Sources */, 0F766D2F15A8DCE0008F363E /* GCAwareJITStubRoutine.cpp in Sources */, + A7CA3AEB17DA5168006538AF /* WeakMapData.cpp in Sources */, C2239D1A16262BDD005AC5FD /* GCThread.cpp in Sources */, C21122E115DD9AB300790E3A /* GCThreadSharedData.cpp in Sources */, 0F93329F14CA7DCA0085F3C6 /* GetByIdStatus.cpp in Sources */, @@ -5127,6 +5156,7 @@ 14469DE2107EC7E700650446 /* NumberConstructor.cpp in Sources */, 14469DE3107EC7E700650446 /* NumberObject.cpp in Sources */, 14469DE4107EC7E700650446 /* NumberPrototype.cpp in Sources */, + A7CA3AE317DA41AE006538AF /* WeakMapConstructor.cpp in Sources */, 86F3EEBE168CDE930077B92A /* ObjCCallbackFunction.mm in Sources */, 14469DE5107EC7E700650446 /* ObjectConstructor.cpp in Sources */, 14469DE6107EC7E700650446 /* ObjectPrototype.cpp in Sources */, @@ -5160,9 +5190,11 @@ ADE39FFF16DD144B0003CD4A /* PropertyTable.cpp in Sources */, 1474C33C16AA2D9B0062F01D /* PrototypeMap.cpp in Sources */, 0F9332A314CA7DD70085F3C6 /* PutByIdStatus.cpp in Sources */, + A7CA3AE517DA41AE006538AF /* WeakMapPrototype.cpp in Sources */, 0FF60AC316740F8800029779 /* ReduceWhitespace.cpp in Sources */, 14280841107EC0930013E7B2 /* RegExp.cpp in Sources */, A1712B3B11C7B212007A5315 /* RegExpCache.cpp in Sources */, + A7CA3AE717DA41AE006538AF /* JSWeakMap.cpp in Sources */, 8642C510151C06A90046D4EF /* RegExpCachedResult.cpp in Sources */, 0FD8A32B17D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.cpp in Sources */, 14280842107EC0930013E7B2 /* RegExpConstructor.cpp in Sources */, diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri index 1ec5c79a71243819322d3a5fb7ac700fd4eb38c6..2fbf7fa6af6ce55ebdcd22b17b513ac1ac9f637c 100644 --- a/Source/JavaScriptCore/Target.pri +++ b/Source/JavaScriptCore/Target.pri @@ -350,6 +350,7 @@ SOURCES += \ runtime/JSTypedArrayPrototypes.cpp \ runtime/JSTypedArrays.cpp \ runtime/JSVariableObject.cpp \ + runtime/JSWeakMap.cpp \ runtime/JSWithScope.cpp \ runtime/JSWrapperObject.cpp \ runtime/LiteralParser.cpp \ @@ -404,6 +405,9 @@ SOURCES += \ runtime/VM.cpp \ runtime/Watchdog.cpp \ runtime/WatchdogNone.cpp \ + runtime/WeakMapConstructor.cpp \ + runtime/WeakMapData.cpp \ + runtime/WeakMapPrototype.cpp \ tools/CodeProfile.cpp \ tools/CodeProfiling.cpp \ yarr/YarrJIT.cpp \ diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.h b/Source/JavaScriptCore/runtime/CommonIdentifiers.h index 6480f0f7e286902ea3a2998c614124f25ce37dc5..5422c7a4f8b80e64322c13948edad2071ce0465d 100644 --- a/Source/JavaScriptCore/runtime/CommonIdentifiers.h +++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.h @@ -143,6 +143,7 @@ macro(size) \ macro(Map)\ macro(Set)\ + macro(WeakMap)\ macro(add) #define JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(macro) \ diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index 05fe8574d261bb64e6333507adde5d8864dbaf90..371d3e78830bab7b8e0b50f96f6b1ec0d2817f3c 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -71,6 +71,7 @@ #include "JSTypedArrayConstructors.h" #include "JSTypedArrayPrototypes.h" #include "JSTypedArrays.h" +#include "JSWeakMap.h" #include "JSWithScope.h" #include "LegacyProfiler.h" #include "Lookup.h" @@ -99,6 +100,9 @@ #include "StrictEvalActivation.h" #include "StringConstructor.h" #include "StringPrototype.h" +#include "WeakMapConstructor.h" +#include "WeakMapData.h" +#include "WeakMapPrototype.h" #if ENABLE(PROMISES) #include "JSPromise.h" @@ -309,6 +313,7 @@ void JSGlobalObject::reset(JSValue prototype) m_mapDataStructure.set(exec->vm(), this, MapData::createStructure(exec->vm(), this, jsNull())); + m_weakMapDataStructure.set(exec->vm(), this, WeakMapData::createStructure(exec->vm(), this, jsNull())); #define CREATE_PROTOTYPE_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName) \ m_ ## lowerName ## Prototype.set(exec->vm(), this, capitalName##Prototype::create(exec, this, capitalName##Prototype::createStructure(exec->vm(), this, m_objectPrototype.get()))); \ @@ -640,6 +645,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) #undef VISIT_SIMPLE_TYPE visitor.append(&thisObject->m_mapDataStructure); + visitor.append(&thisObject->m_weakMapDataStructure); for (unsigned i = NUMBER_OF_TYPED_ARRAY_TYPES; i--;) { visitor.append(&thisObject->m_typedArrays[i].prototype); diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index da61894c66621b7ec74df878b46cf0c382f13e31..82ff29ca75cc36f2d5b6e7cc1845ea72693de324 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -80,6 +80,7 @@ struct HashTable; macro(Number, number, numberObject, NumberObject, Number) \ macro(Error, error, error, ErrorInstance, Error) \ macro(JSArrayBuffer, arrayBuffer, arrayBuffer, JSArrayBuffer, ArrayBuffer) \ + macro(WeakMap, weakMap, weakMap, JSWeakMap, WeakMap) \ #define DECLARE_SIMPLE_BUILTIN_TYPE(capitalName, lowerName, properName, instanceType, jsName) \ class JS ## capitalName; \ @@ -200,6 +201,7 @@ protected: #endif // ENABLE(PROMISES) WriteBarrier m_mapDataStructure; + WriteBarrier m_weakMapDataStructure; #define DEFINE_STORAGE_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName) \ WriteBarrier m_ ## lowerName ## Prototype; \ @@ -398,6 +400,7 @@ public: Structure* internalFunctionStructure() const { return m_internalFunctionStructure.get(); } Structure* mapStructure() const { return m_mapStructure.get(); } Structure* mapDataStructure() const { return m_mapDataStructure.get(); } + Structure* weakMapDataStructure() const { return m_weakMapDataStructure.get(); } Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); } Structure* regExpStructure() const { return m_regExpStructure.get(); } Structure* setStructure() const { return m_setStructure.get(); } diff --git a/Source/JavaScriptCore/runtime/JSWeakMap.cpp b/Source/JavaScriptCore/runtime/JSWeakMap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe6b790b0fe58d226ab10163aae56e1c4da36491 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSWeakMap.cpp @@ -0,0 +1,50 @@ +/* + * 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 "JSWeakMap.h" + +#include "JSCJSValueInlines.h" +#include "SlotVisitorInlines.h" +#include "WeakMapData.h" + +namespace JSC { + +const ClassInfo JSWeakMap::s_info = { "WeakMap", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSWeakMap) }; + +void JSWeakMap::finishCreation(VM& vm, JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + m_weakMapData.set(vm, this, WeakMapData::create(vm, globalObject)); +} + +void JSWeakMap::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + Base::visitChildren(cell, visitor); + JSWeakMap* thisObj = jsCast(cell); + visitor.append(&thisObj->m_weakMapData); +} + +} diff --git a/Source/JavaScriptCore/runtime/JSWeakMap.h b/Source/JavaScriptCore/runtime/JSWeakMap.h new file mode 100644 index 0000000000000000000000000000000000000000..93c2d84885d39aa9df43e50698295b19c6b7ad70 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSWeakMap.h @@ -0,0 +1,80 @@ +/* + * 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 JSWeakMap_h +#define JSWeakMap_h + +#include "JSObject.h" + +namespace JSC { + +class WeakMapData; + +class JSWeakMap : 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 JSWeakMap* create(ExecState* exec, Structure* structure) + { + VM& vm = exec->vm(); + JSWeakMap* instance = new (NotNull, allocateCell(vm.heap)) JSWeakMap(vm, structure); + instance->finishCreation(vm, structure->globalObject()); + return instance; + } + + 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: + + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; + + JSWeakMap(VM& vm, Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(VM&, JSGlobalObject*); + static void visitChildren(JSCell*, SlotVisitor&); + + WriteBarrier m_weakMapData; +}; + +} + +#endif // !defined(JSWeakMap_h) diff --git a/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp b/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1ff1dd5deea83c5442ca800f38c311c462149d0 --- /dev/null +++ b/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp @@ -0,0 +1,64 @@ +/* + * 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 "WeakMapConstructor.h" + +#include "JSCJSValueInlines.h" +#include "JSCellInlines.h" +#include "JSGlobalObject.h" +#include "JSWeakMap.h" +#include "WeakMapPrototype.h" + +namespace JSC { + +const ClassInfo WeakMapConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(WeakMapConstructor) }; + +void WeakMapConstructor::finishCreation(ExecState* exec, WeakMapPrototype* prototype) +{ + Base::finishCreation(exec->vm(), prototype->classInfo()->className); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().prototype, prototype, DontEnum | DontDelete | ReadOnly); + putDirectWithoutTransition(exec->vm(), exec->propertyNames().length, jsNumber(0), ReadOnly | DontEnum | DontDelete); +} + +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)); +} + +ConstructType WeakMapConstructor::getConstructData(JSCell*, ConstructData& constructData) +{ + constructData.native.function = constructWeakMap; + return ConstructTypeHost; +} + +CallType WeakMapConstructor::getCallData(JSCell*, CallData&) +{ + return CallTypeNone; +} + +} diff --git a/Source/JavaScriptCore/runtime/WeakMapConstructor.h b/Source/JavaScriptCore/runtime/WeakMapConstructor.h new file mode 100644 index 0000000000000000000000000000000000000000..2c485efaad0a658b257a268adcde0109b2008363 --- /dev/null +++ b/Source/JavaScriptCore/runtime/WeakMapConstructor.h @@ -0,0 +1,65 @@ +/* + * 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 WeakMapConstructor_h +#define WeakMapConstructor_h + +#include "InternalFunction.h" + +namespace JSC { + +class WeakMapPrototype; + +class WeakMapConstructor : public InternalFunction { +public: + typedef InternalFunction Base; + + static WeakMapConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, WeakMapPrototype* prototype) + { + WeakMapConstructor* constructor = new (NotNull, allocateCell(*exec->heap())) WeakMapConstructor(globalObject, structure); + constructor->finishCreation(exec, prototype); + return constructor; + } + + DECLARE_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + +private: + WeakMapConstructor(JSGlobalObject* globalObject, Structure* structure) + : Base(globalObject, structure) + { + } + void finishCreation(ExecState*, WeakMapPrototype*); + static ConstructType getConstructData(JSCell*, ConstructData&); + static CallType getCallData(JSCell*, CallData&); +}; + +} + +#endif // !defined(WeakMapConstructor_h) diff --git a/Source/JavaScriptCore/runtime/WeakMapData.cpp b/Source/JavaScriptCore/runtime/WeakMapData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4706d1b07c67627efe9e68f4628dc039337cefa6 --- /dev/null +++ b/Source/JavaScriptCore/runtime/WeakMapData.cpp @@ -0,0 +1,145 @@ +/* + * 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 "WeakMapData.h" + +#include "CopiedAllocator.h" +#include "CopyVisitorInlines.h" +#include "ExceptionHelpers.h" +#include "JSCJSValueInlines.h" +#include "SlotVisitorInlines.h" + +#include + + +namespace JSC { + +const ClassInfo WeakMapData::s_info = { "WeakMapData", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(WeakMapData) }; + +WeakMapData::WeakMapData(VM& vm, JSGlobalObject* globalObject) + : Base(vm, globalObject->weakMapDataStructure()) + , m_deadKeyCleaner(this) +{ +} + +void WeakMapData::finishCreation(VM& vm) +{ + Base::finishCreation(vm); +} + +void WeakMapData::destroy(JSCell* cell) +{ + static_cast(cell)->~WeakMapData(); +} + +void WeakMapData::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + Base::visitChildren(cell, visitor); + WeakMapData* thisObj = jsCast(cell); + visitor.addUnconditionalFinalizer(&thisObj->m_deadKeyCleaner); + visitor.addWeakReferenceHarvester(&thisObj->m_deadKeyCleaner); + + // 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->m_map.capacity() * (sizeof(JSObject*) + sizeof(WriteBarrier))); +} + +void WeakMapData::set(CallFrame* callFrame, JSObject* key, JSValue value) +{ + // Here we force the write barrier on the key. + auto result = m_map.add(WriteBarrier(callFrame->vm(), this, key).get(), WriteBarrier()); + result.iterator->value.set(callFrame->vm(), this, value); +} + +JSValue WeakMapData::get(JSObject* key) +{ + auto iter = m_map.find(key); + if (iter == m_map.end()) + return jsUndefined(); + return iter->value.get(); +} + +bool WeakMapData::remove(JSObject* key) +{ + auto iter = m_map.find(key); + if (iter == m_map.end()) + return false; + + m_map.remove(iter); + return true; +} + +bool WeakMapData::contains(JSObject* key) +{ + return m_map.contains(key); +} + +void WeakMapData::clear() +{ + m_map.clear(); +} + +void WeakMapData::DeadKeyCleaner::visitWeakReferences(SlotVisitor& visitor) +{ + m_liveKeyCount = 0; + for (auto it = m_target->m_map.begin(), end = m_target->m_map.end(); it != end; ++it) { + if (!Heap::isMarked(it->key)) + continue; + m_liveKeyCount++; + visitor.append(&it->value); + } + RELEASE_ASSERT(m_liveKeyCount <= m_target->m_map.size()); +} + +void WeakMapData::DeadKeyCleaner::finalizeUnconditionally() +{ + if (m_liveKeyCount > m_target->m_map.size() / 2) { + RELEASE_ASSERT(m_liveKeyCount <= m_target->m_map.size()); + int deadCount = m_target->m_map.size() - m_liveKeyCount; + if (!deadCount) + return; + Vector deadEntries; + deadEntries.reserveCapacity(deadCount); + for (auto it = m_target->m_map.begin(), end = m_target->m_map.end(); it != end; ++it) { + if (Heap::isMarked(it->key)) + continue; + deadEntries.uncheckedAppend(it->key); + } + for (size_t i = 0; i < deadEntries.size(); i++) + m_target->m_map.remove(deadEntries[i]); + } else { + MapType newMap; + for (auto it = m_target->m_map.begin(), end = m_target->m_map.end(); it != end; ++it) { + if (!Heap::isMarked(it->key)) + continue; + newMap.add(it->key, it->value); + } + m_target->m_map.swap(newMap); + } +} + +} diff --git a/Source/JavaScriptCore/runtime/WeakMapData.h b/Source/JavaScriptCore/runtime/WeakMapData.h new file mode 100644 index 0000000000000000000000000000000000000000..e1639857913f3264c9f246da3672c3fb926a5357 --- /dev/null +++ b/Source/JavaScriptCore/runtime/WeakMapData.h @@ -0,0 +1,93 @@ +/* + * 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 WeakMapData_h +#define WeakMapData_h + +#include "CallFrame.h" +#include "JSCJSValue.h" +#include "JSDestructibleObject.h" + +#include +#include +#include + +namespace JSC { + +class WeakImpl; +class WeakMapData; + +class WeakMapData : public JSDestructibleObject { +public: + typedef JSDestructibleObject Base; + + static WeakMapData* create(VM& vm, JSGlobalObject* globalObject) + { + WeakMapData* weakMapData = new (NotNull, allocateCell(vm.heap)) WeakMapData(vm, globalObject); + weakMapData->finishCreation(vm); + return weakMapData; + } + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + void set(CallFrame*, JSObject*, JSValue); + JSValue get(JSObject*); + bool remove(JSObject*); + void removeDead(JSObject*); + bool contains(JSObject*); + void clear(); + + DECLARE_INFO; + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; + +private: + WeakMapData(VM&, JSGlobalObject*); + static void destroy(JSCell*); + static void visitChildren(JSCell*, SlotVisitor&); + void finishCreation(VM&); + + class DeadKeyCleaner : public UnconditionalFinalizer, public WeakReferenceHarvester { + public: + DeadKeyCleaner(WeakMapData* target) + : m_target(target) + { + } + private: + virtual void visitWeakReferences(SlotVisitor&); + virtual void finalizeUnconditionally(); + int m_liveKeyCount; + WeakMapData* m_target; + }; + DeadKeyCleaner m_deadKeyCleaner; + typedef HashMap> MapType; + MapType m_map; +}; + +} + +#endif /* !defined(WeakMapData_h) */ diff --git a/Source/JavaScriptCore/runtime/WeakMapPrototype.cpp b/Source/JavaScriptCore/runtime/WeakMapPrototype.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ff2ffa36ba2db5fc42a500898a150310ded3f7fd --- /dev/null +++ b/Source/JavaScriptCore/runtime/WeakMapPrototype.cpp @@ -0,0 +1,126 @@ +/* + * 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 "WeakMapPrototype.h" + +#include "JSCJSValueInlines.h" +#include "JSWeakMap.h" +#include "WeakMapData.h" + +namespace JSC { + +const ClassInfo WeakMapPrototype::s_info = { "WeakMap", &Base::s_info, 0, 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*); +static EncodedJSValue JSC_HOST_CALL protoFuncWeakMapSet(ExecState*); + +void WeakMapPrototype::finishCreation(ExecState* exec, JSGlobalObject* globalObject) +{ + VM& vm = exec->vm(); + + Base::finishCreation(vm); + ASSERT(inherits(info())); + vm.prototypeMap.addPrototype(this); + + JSC_NATIVE_FUNCTION(exec->propertyNames().clear, protoFuncWeakMapClear, DontEnum, 0); + JSC_NATIVE_FUNCTION(exec->propertyNames().deleteKeyword, protoFuncWeakMapDelete, DontEnum, 1); + JSC_NATIVE_FUNCTION(exec->propertyNames().get, protoFuncWeakMapGet, DontEnum, 1); + JSC_NATIVE_FUNCTION(exec->propertyNames().has, protoFuncWeakMapHas, DontEnum, 1); + JSC_NATIVE_FUNCTION(exec->propertyNames().set, protoFuncWeakMapSet, DontEnum, 2); +} + +static WeakMapData* getWeakMapData(CallFrame* callFrame, JSValue value) +{ + if (!value.isObject()) { + throwTypeError(callFrame, WTF::ASCIILiteral("Called WeakMap function on non-object")); + return 0; + } + + if (JSWeakMap* weakMap = jsDynamicCast(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()); +} + +EncodedJSValue JSC_HOST_CALL protoFuncWeakMapDelete(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("A WeakMap cannot have a non-object key"))); + return JSValue::encode(jsBoolean(map->remove(asObject(key)))); +} + +EncodedJSValue JSC_HOST_CALL protoFuncWeakMapGet(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("A WeakMap cannot have a non-object key"))); + return JSValue::encode(map->get(asObject(key))); +} + +EncodedJSValue JSC_HOST_CALL protoFuncWeakMapHas(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("A WeakMap cannot have a non-object key"))); + return JSValue::encode(jsBoolean(map->contains(asObject(key)))); +} + +EncodedJSValue JSC_HOST_CALL protoFuncWeakMapSet(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 set a non-object key in a WeakMap"))); + map->set(callFrame, asObject(key), callFrame->argument(1)); + return JSValue::encode(callFrame->thisValue()); +} + +} diff --git a/Source/JavaScriptCore/runtime/WeakMapPrototype.h b/Source/JavaScriptCore/runtime/WeakMapPrototype.h new file mode 100644 index 0000000000000000000000000000000000000000..785e49e936bc48c15fd1d2401a78203a4a45605d --- /dev/null +++ b/Source/JavaScriptCore/runtime/WeakMapPrototype.h @@ -0,0 +1,61 @@ +/* + * 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 WeakMapPrototype_h +#define WeakMapPrototype_h + +#include "JSObject.h" + +namespace JSC { + +class WeakMapPrototype : public JSNonFinalObject { +public: + typedef JSNonFinalObject Base; + + static WeakMapPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure) + { + WeakMapPrototype* prototype = new (NotNull, allocateCell(*exec->heap())) WeakMapPrototype(exec, structure); + prototype->finishCreation(exec, 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: + WeakMapPrototype(ExecState* exec, Structure* structure) + : Base(exec->vm(), structure) + { + } + void finishCreation(ExecState*, JSGlobalObject*); +}; + +} + +#endif // !defined(WeakMapPrototype_h)