Web Replay: add infrastructure for memoizing nondeterministic DOM APIs
authorbburg@apple.com <bburg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Mar 2014 00:41:58 +0000 (00:41 +0000)
committerbburg@apple.com <bburg@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Mar 2014 00:41:58 +0000 (00:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=129445

Reviewed by Timothy Hatcher.

Source/JavaScriptCore:

There was a bug in the replay inputs code generator that would include
headers for definitions of enum classes, even though they can be safely
forward-declared.

* replay/scripts/CodeGeneratorReplayInputs.py:
(Generator.generate_includes): Only include for copy constructor if the
type is a heavy scalar (i.e., String, URL), not a normal scalar
(i.e., int, double, enum classes).

(Generator.generate_type_forward_declarations): Forward-declare scalars
that are enums or enum classes.

Source/WebCore:

Add two pieces of infrastructure to support memoization of selected DOM APIs.

The first piece is MemoizedDOMResult, a templated replay input class that knows
how to serialize a DOM API's return value, ctype, and exception code.

The second piece is the addition of a new IDL attribute called `Nondeterministic`.
When placed on a DOM function or attribute, the code generator will emit code
to save the DOM API's return value or use a memoized return value instead,
depending on the current replay state. This new emitted code path is behind
a feature flag.

No new tests, as no new inputs are addressed by this change. Per-DOM API replay
regression tests will be added when those APIs are marked as nondeterministic.

* WebCore.xcodeproj/project.pbxproj:
* bindings/scripts/CodeGeneratorJS.pm: Add support of the `Nondeterministic` attribute.
(GenerateImplementation): Handle cases for attributes and getters with exceptions.
(GenerateImplementationFunctionCall): Handle function calls with and without exceptions.
(GetNativeTypeForMemoization): Added. Converts DOMString to WTF::String.
* bindings/scripts/IDLAttributes.txt: Add new `Nondeterministic` attribute.
* bindings/scripts/test/JS/JSTestEventTarget.cpp:
(WebCore::jsTestEventTargetPrototypeFunctionItem):
(WebCore::jsTestEventTargetPrototypeFunctionDispatchEvent):
* bindings/scripts/test/JS/JSTestInterface.cpp:
(WebCore::jsTestInterfacePrototypeFunctionImplementsMethod2):
(WebCore::jsTestInterfacePrototypeFunctionSupplementalMethod2):
* bindings/scripts/test/JS/JSTestObj.cpp:
(WebCore::jsTestObjAttrWithGetterException):
(WebCore::jsTestObjStringAttrWithGetterException):
(WebCore::jsTestObjWithScriptStateAttributeRaises):
(WebCore::jsTestObjWithScriptExecutionContextAttributeRaises):
(WebCore::jsTestObjWithScriptExecutionContextAndScriptStateAttributeRaises):
(WebCore::jsTestObjNullableStringValue):
(WebCore::jsTestObjPrototypeFunctionByteMethod):
(WebCore::jsTestObjPrototypeFunctionByteMethodWithArgs):
(WebCore::jsTestObjPrototypeFunctionOctetMethod):
(WebCore::jsTestObjPrototypeFunctionOctetMethodWithArgs):
(WebCore::jsTestObjPrototypeFunctionLongMethod):
(WebCore::jsTestObjPrototypeFunctionLongMethodWithArgs):
(WebCore::jsTestObjPrototypeFunctionObjMethod):
(WebCore::jsTestObjPrototypeFunctionObjMethodWithArgs):
(WebCore::jsTestObjPrototypeFunctionMethodReturningSequence):
(WebCore::jsTestObjPrototypeFunctionMethodThatRequiresAllArgsAndThrows):
(WebCore::jsTestObjPrototypeFunctionWithScriptStateObj):
(WebCore::jsTestObjPrototypeFunctionWithScriptStateObjException):
(WebCore::jsTestObjPrototypeFunctionWithScriptExecutionContextAndScriptStateObjException):
(WebCore::jsTestObjPrototypeFunctionWithScriptExecutionContextAndScriptStateWithSpaces):
(WebCore::jsTestObjPrototypeFunctionConditionalMethod1):
(WebCore::jsTestObjConstructorFunctionClassMethodWithOptional):
(WebCore::jsTestObjPrototypeFunctionStringArrayFunction):
(WebCore::jsTestObjPrototypeFunctionDomStringListFunction):
(WebCore::jsTestObjPrototypeFunctionGetSVGDocument):
(WebCore::jsTestObjPrototypeFunctionMutablePointFunction):
(WebCore::jsTestObjPrototypeFunctionImmutablePointFunction):
(WebCore::jsTestObjPrototypeFunctionStrictFunction):
(WebCore::jsTestObjPrototypeFunctionStrictFunctionWithSequence):
(WebCore::jsTestObjPrototypeFunctionStrictFunctionWithArray):
* bindings/scripts/test/JS/JSTestTypedefs.cpp:
(WebCore::jsTestTypedefsAttrWithGetterException):
(WebCore::jsTestTypedefsStringAttrWithGetterException):
(WebCore::jsTestTypedefsPrototypeFunctionMethodWithSequenceArg):
(WebCore::jsTestTypedefsPrototypeFunctionImmutablePointFunction):
(WebCore::jsTestTypedefsPrototypeFunctionStringArrayFunction):
(WebCore::jsTestTypedefsPrototypeFunctionStringArrayFunction2):
(WebCore::jsTestTypedefsPrototypeFunctionCallWithSequenceThatRequiresInclude):

* replay/AllReplayInputs.h:
* replay/MemoizedDOMResult.cpp: Added.
(WebCore::MemoizedDOMResultBase::type):
(WebCore::MemoizedDOMResultBase::createFromEncodedResult):
(InputTraits<MemoizedDOMResultBase>::type):
(InputTraits<MemoizedDOMResultBase>::encode):
(InputTraits<MemoizedDOMResultBase>::decode):

* replay/MemoizedDOMResult.h: Added. Every specialization of MemoizedDOMResult<T>
stores a binding name, ctype, result value of type T, and optional exception code.
The ctype-specific code uses the CTypeTraits struct to abstract over enum names and
compiler types. The actual encode/decode methods just use methods from EncodingTraits<T>.

(WebCore::MemoizedDOMResultBase::MemoizedDOMResultBase):
(WebCore::MemoizedDOMResultBase::~MemoizedDOMResultBase):
(WebCore::MemoizedDOMResultBase::attribute):
(WebCore::MemoizedDOMResultBase::ctype):
(WebCore::MemoizedDOMResultBase::exceptionCode):
(WebCore::CTypeTraits::decode):
(WebCore::MemoizedDOMResultBase::convertTo):
(JSC::InputTraits<MemoizedDOMResultBase>::queue):
* replay/ReplayInputTypes.cpp: See below.
(WebCore::ReplayInputTypes::ReplayInputTypes):
* replay/ReplayInputTypes.h: See below.
* replay/SerializationMethods.cpp: We need to special-case the encoding
and decoding of MemoizedDOMResult inputs because the input is not part of
the generated per-framework replay inputs enum.
(JSC::EncodingTraits<NondeterministicInputBase>::encodeValue):
(JSC::EncodingTraits<NondeterministicInputBase>::decodeValue):

* replay/WebInputs.json: Add the EncodedCType enum as an external enum type,
so that we can use a generated EncodingTraits specialization to encode the enum.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@165521 268f45cc-cd09-0410-ab3c-d52691b4dbfc

17 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/replay/scripts/CodeGeneratorReplayInputs.py
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/IDLAttributes.txt
Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestInterface.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestTypedefs.cpp
Source/WebCore/replay/AllReplayInputs.h
Source/WebCore/replay/MemoizedDOMResult.cpp [new file with mode: 0644]
Source/WebCore/replay/MemoizedDOMResult.h [new file with mode: 0644]
Source/WebCore/replay/ReplayInputTypes.cpp
Source/WebCore/replay/ReplayInputTypes.h
Source/WebCore/replay/SerializationMethods.cpp
Source/WebCore/replay/WebInputs.json

index 8c998ac..ec6afa7 100644 (file)
@@ -1,3 +1,22 @@
+2014-03-12  Brian Burg  <bburg@apple.com>
+
+        Web Replay: add infrastructure for memoizing nondeterministic DOM APIs
+        https://bugs.webkit.org/show_bug.cgi?id=129445
+
+        Reviewed by Timothy Hatcher.
+
+        There was a bug in the replay inputs code generator that would include
+        headers for definitions of enum classes, even though they can be safely
+        forward-declared.
+
+        * replay/scripts/CodeGeneratorReplayInputs.py:
+        (Generator.generate_includes): Only include for copy constructor if the
+        type is a heavy scalar (i.e., String, URL), not a normal scalar
+        (i.e., int, double, enum classes).
+
+        (Generator.generate_type_forward_declarations): Forward-declare scalars
+        that are enums or enum classes.
+
 2014-03-12  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Disable REMOTE_INSPECTOR in earlier OS X releases
index cd65108..c6241ae 100644 (file)
@@ -630,7 +630,7 @@ class Generator:
             # headers with the relevant class declaration.
             include_for_enclosing_class = _type.is_enum() and _type.enclosing_class is not None
             # Include headers for types like URL and String which are copied, not owned or shared.
-            include_for_copyable_member = _type.mode is TypeModes.HEAVY_SCALAR or _type.mode is TypeModes.SCALAR
+            include_for_copyable_member = _type.mode is TypeModes.HEAVY_SCALAR
             if (not includes_for_types) ^ (include_for_destructor or include_for_enclosing_class or include_for_copyable_member):
                 continue
 
@@ -665,7 +665,9 @@ class Generator:
                 continue
             if _type.enclosing_class is not None:
                 continue
-            if _type.mode == TypeModes.SCALAR or _type.mode == TypeModes.HEAVY_SCALAR:
+            if _type.mode == TypeModes.HEAVY_SCALAR:
+                continue
+            if _type.mode == TypeModes.SCALAR and not (_type.is_enum() or _type.is_enum_class()):
                 continue
             if _type.is_enum():
                 declaration = "enum %s : %s;" % (_type.type_name(), _type.underlying_storage)
index 4585dd7..b005097 100644 (file)
@@ -1,3 +1,109 @@
+2014-03-12  Brian Burg  <bburg@apple.com>
+
+        Web Replay: add infrastructure for memoizing nondeterministic DOM APIs
+        https://bugs.webkit.org/show_bug.cgi?id=129445
+
+        Reviewed by Timothy Hatcher.
+
+        Add two pieces of infrastructure to support memoization of selected DOM APIs.
+
+        The first piece is MemoizedDOMResult, a templated replay input class that knows
+        how to serialize a DOM API's return value, ctype, and exception code.
+
+        The second piece is the addition of a new IDL attribute called `Nondeterministic`.
+        When placed on a DOM function or attribute, the code generator will emit code
+        to save the DOM API's return value or use a memoized return value instead,
+        depending on the current replay state. This new emitted code path is behind
+        a feature flag.
+
+        No new tests, as no new inputs are addressed by this change. Per-DOM API replay
+        regression tests will be added when those APIs are marked as nondeterministic.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/scripts/CodeGeneratorJS.pm: Add support of the `Nondeterministic` attribute.
+        (GenerateImplementation): Handle cases for attributes and getters with exceptions.
+        (GenerateImplementationFunctionCall): Handle function calls with and without exceptions.
+        (GetNativeTypeForMemoization): Added. Converts DOMString to WTF::String.
+        * bindings/scripts/IDLAttributes.txt: Add new `Nondeterministic` attribute.
+        * bindings/scripts/test/JS/JSTestEventTarget.cpp:
+        (WebCore::jsTestEventTargetPrototypeFunctionItem):
+        (WebCore::jsTestEventTargetPrototypeFunctionDispatchEvent):
+        * bindings/scripts/test/JS/JSTestInterface.cpp:
+        (WebCore::jsTestInterfacePrototypeFunctionImplementsMethod2):
+        (WebCore::jsTestInterfacePrototypeFunctionSupplementalMethod2):
+        * bindings/scripts/test/JS/JSTestObj.cpp:
+        (WebCore::jsTestObjAttrWithGetterException):
+        (WebCore::jsTestObjStringAttrWithGetterException):
+        (WebCore::jsTestObjWithScriptStateAttributeRaises):
+        (WebCore::jsTestObjWithScriptExecutionContextAttributeRaises):
+        (WebCore::jsTestObjWithScriptExecutionContextAndScriptStateAttributeRaises):
+        (WebCore::jsTestObjNullableStringValue):
+        (WebCore::jsTestObjPrototypeFunctionByteMethod):
+        (WebCore::jsTestObjPrototypeFunctionByteMethodWithArgs):
+        (WebCore::jsTestObjPrototypeFunctionOctetMethod):
+        (WebCore::jsTestObjPrototypeFunctionOctetMethodWithArgs):
+        (WebCore::jsTestObjPrototypeFunctionLongMethod):
+        (WebCore::jsTestObjPrototypeFunctionLongMethodWithArgs):
+        (WebCore::jsTestObjPrototypeFunctionObjMethod):
+        (WebCore::jsTestObjPrototypeFunctionObjMethodWithArgs):
+        (WebCore::jsTestObjPrototypeFunctionMethodReturningSequence):
+        (WebCore::jsTestObjPrototypeFunctionMethodThatRequiresAllArgsAndThrows):
+        (WebCore::jsTestObjPrototypeFunctionWithScriptStateObj):
+        (WebCore::jsTestObjPrototypeFunctionWithScriptStateObjException):
+        (WebCore::jsTestObjPrototypeFunctionWithScriptExecutionContextAndScriptStateObjException):
+        (WebCore::jsTestObjPrototypeFunctionWithScriptExecutionContextAndScriptStateWithSpaces):
+        (WebCore::jsTestObjPrototypeFunctionConditionalMethod1):
+        (WebCore::jsTestObjConstructorFunctionClassMethodWithOptional):
+        (WebCore::jsTestObjPrototypeFunctionStringArrayFunction):
+        (WebCore::jsTestObjPrototypeFunctionDomStringListFunction):
+        (WebCore::jsTestObjPrototypeFunctionGetSVGDocument):
+        (WebCore::jsTestObjPrototypeFunctionMutablePointFunction):
+        (WebCore::jsTestObjPrototypeFunctionImmutablePointFunction):
+        (WebCore::jsTestObjPrototypeFunctionStrictFunction):
+        (WebCore::jsTestObjPrototypeFunctionStrictFunctionWithSequence):
+        (WebCore::jsTestObjPrototypeFunctionStrictFunctionWithArray):
+        * bindings/scripts/test/JS/JSTestTypedefs.cpp:
+        (WebCore::jsTestTypedefsAttrWithGetterException):
+        (WebCore::jsTestTypedefsStringAttrWithGetterException):
+        (WebCore::jsTestTypedefsPrototypeFunctionMethodWithSequenceArg):
+        (WebCore::jsTestTypedefsPrototypeFunctionImmutablePointFunction):
+        (WebCore::jsTestTypedefsPrototypeFunctionStringArrayFunction):
+        (WebCore::jsTestTypedefsPrototypeFunctionStringArrayFunction2):
+        (WebCore::jsTestTypedefsPrototypeFunctionCallWithSequenceThatRequiresInclude):
+
+        * replay/AllReplayInputs.h:
+        * replay/MemoizedDOMResult.cpp: Added.
+        (WebCore::MemoizedDOMResultBase::type):
+        (WebCore::MemoizedDOMResultBase::createFromEncodedResult):
+        (InputTraits<MemoizedDOMResultBase>::type):
+        (InputTraits<MemoizedDOMResultBase>::encode):
+        (InputTraits<MemoizedDOMResultBase>::decode):
+
+        * replay/MemoizedDOMResult.h: Added. Every specialization of MemoizedDOMResult<T>
+        stores a binding name, ctype, result value of type T, and optional exception code.
+        The ctype-specific code uses the CTypeTraits struct to abstract over enum names and
+        compiler types. The actual encode/decode methods just use methods from EncodingTraits<T>.
+
+        (WebCore::MemoizedDOMResultBase::MemoizedDOMResultBase):
+        (WebCore::MemoizedDOMResultBase::~MemoizedDOMResultBase):
+        (WebCore::MemoizedDOMResultBase::attribute):
+        (WebCore::MemoizedDOMResultBase::ctype):
+        (WebCore::MemoizedDOMResultBase::exceptionCode):
+        (WebCore::CTypeTraits::decode):
+        (WebCore::MemoizedDOMResultBase::convertTo):
+        (JSC::InputTraits<MemoizedDOMResultBase>::queue):
+        * replay/ReplayInputTypes.cpp: See below.
+        (WebCore::ReplayInputTypes::ReplayInputTypes):
+        * replay/ReplayInputTypes.h: See below.
+        * replay/SerializationMethods.cpp: We need to special-case the encoding
+        and decoding of MemoizedDOMResult inputs because the input is not part of
+        the generated per-framework replay inputs enum.
+        (JSC::EncodingTraits<NondeterministicInputBase>::encodeValue):
+        (JSC::EncodingTraits<NondeterministicInputBase>::decodeValue):
+
+        * replay/WebInputs.json: Add the EncodedCType enum as an external enum type,
+        so that we can use a generated EncodingTraits specialization to encode the enum.
+
 2014-03-11  Jae Hyun Park  <jaepark@webkit.org>
 
         Make HTMLCanvasElement::is3D private
index 3d43c01..76326a8 100644 (file)
                990A1A0518ADA48400183FD1 /* ReplayInputTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 990A19F518ADA48400183FD1 /* ReplayInputTypes.h */; };
                9920398218B95BC600B39AF9 /* UserInputBridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9920398018B95BC600B39AF9 /* UserInputBridge.cpp */; };
                9920398318B95BC600B39AF9 /* UserInputBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 9920398118B95BC600B39AF9 /* UserInputBridge.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               99C7CCB318C663E40032E413 /* MemoizedDOMResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C7CCB218C663E40032E413 /* MemoizedDOMResult.h */; };
+               99C7CCB518C6B8990032E413 /* MemoizedDOMResult.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99C7CCB418C6B8990032E413 /* MemoizedDOMResult.cpp */; };
                99CC0B4D18BE9849006CEBCC /* AllReplayInputs.h in Headers */ = {isa = PBXBuildFile; fileRef = 99CC0B3818BE9849006CEBCC /* AllReplayInputs.h */; };
                99CC0B4E18BE9849006CEBCC /* CapturingInputCursor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 99CC0B3918BE9849006CEBCC /* CapturingInputCursor.cpp */; };
                99CC0B4F18BE9849006CEBCC /* CapturingInputCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 99CC0B3A18BE9849006CEBCC /* CapturingInputCursor.h */; };
                990A19F518ADA48400183FD1 /* ReplayInputTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReplayInputTypes.h; sourceTree = "<group>"; };
                9920398018B95BC600B39AF9 /* UserInputBridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserInputBridge.cpp; sourceTree = "<group>"; };
                9920398118B95BC600B39AF9 /* UserInputBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserInputBridge.h; sourceTree = "<group>"; };
+               99C7CCB218C663E40032E413 /* MemoizedDOMResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoizedDOMResult.h; sourceTree = "<group>"; };
+               99C7CCB418C6B8990032E413 /* MemoizedDOMResult.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoizedDOMResult.cpp; sourceTree = "<group>"; };
                99CC0B3818BE9849006CEBCC /* AllReplayInputs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AllReplayInputs.h; sourceTree = "<group>"; };
                99CC0B3918BE9849006CEBCC /* CapturingInputCursor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CapturingInputCursor.cpp; sourceTree = "<group>"; };
                99CC0B3A18BE9849006CEBCC /* CapturingInputCursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CapturingInputCursor.h; sourceTree = "<group>"; };
                                99CC0B3B18BE9849006CEBCC /* EventLoopInputDispatcher.cpp */,
                                99CC0B3C18BE9849006CEBCC /* EventLoopInputDispatcher.h */,
                                99CC0B3D18BE9849006CEBCC /* FunctorInputCursor.h */,
+                               99C7CCB418C6B8990032E413 /* MemoizedDOMResult.cpp */,
+                               99C7CCB218C663E40032E413 /* MemoizedDOMResult.h */,
                                99CC0B3E18BE9849006CEBCC /* ReplayController.cpp */,
                                99CC0B3F18BE9849006CEBCC /* ReplayController.h */,
                                99CC0B4018BE9849006CEBCC /* ReplayingInputCursor.cpp */,
                                977B386C122883E900B81FF8 /* HTMLEntitySearch.h in Headers */,
                                977B386D122883E900B81FF8 /* HTMLEntityTable.h in Headers */,
                                A81369D4097374F600D74463 /* HTMLFieldSetElement.h in Headers */,
+                               99C7CCB318C663E40032E413 /* MemoizedDOMResult.h in Headers */,
                                A8CFF7A60A156978000A4234 /* HTMLFontElement.h in Headers */,
                                977B386F122883E900B81FF8 /* HTMLFormattingElementList.h in Headers */,
                                A81369CE097374F600D74463 /* HTMLFormControlElement.h in Headers */,
                                B237C8A70D344D110013F707 /* SVGFontData.cpp in Sources */,
                                B2A1F2AA0CEF0ABF00442F6A /* SVGFontElement.cpp in Sources */,
                                B2227A140D00BF220071B782 /* SVGFontFaceElement.cpp in Sources */,
+                               99C7CCB518C6B8990032E413 /* MemoizedDOMResult.cpp in Sources */,
                                B2227A170D00BF220071B782 /* SVGFontFaceFormatElement.cpp in Sources */,
                                B2227A1A0D00BF220071B782 /* SVGFontFaceNameElement.cpp in Sources */,
                                B2227A1D0D00BF220071B782 /* SVGFontFaceSrcElement.cpp in Sources */,
index 61a9a81..4dc55ba 100644 (file)
@@ -3,7 +3,7 @@
 # Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
 # Copyright (C) 2006, 2007 Samuel Weinig <sam@webkit.org>
 # Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
-# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved.
+# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2013, 2014 Apple Inc. All rights reserved.
 # Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
 # Copyright (C) Research In Motion Limited 2010. All rights reserved.
 # Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
@@ -2118,6 +2118,7 @@ sub GenerateImplementation
             $codeGenerator->AssertNotSequenceType($type);
             my $getFunctionName = GetAttributeGetterName($interfaceName, $className, $attribute);
             my $implGetterFunctionName = $codeGenerator->WK_lcfirst($attribute->signature->extendedAttributes->{"ImplementedAs"} || $name);
+            my $getterExceptions = $attribute->signature->extendedAttributes->{"GetterRaisesException"};
 
             my $attributeConditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
             push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
@@ -2151,6 +2152,12 @@ sub GenerateImplementation
                 push(@implContent, "    UNUSED_PARAM(slotBase);\n");
             }
 
+            my @arguments = ();
+            if ($getterExceptions && !HasCustomGetter($attribute->signature->extendedAttributes)) {
+                push(@arguments, "ec");
+                push(@implContent, "    ExceptionCode ec = 0;\n");
+            }
+
             # Global constructors can be disabled at runtime.
             if ($attribute->signature->type =~ /Constructor$/) {
                 if ($attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) {
@@ -2181,6 +2188,38 @@ sub GenerateImplementation
                 push(@implContent, "        return JSValue::encode(jsUndefined());\n");
             }
 
+            if ($attribute->signature->extendedAttributes->{"Nondeterministic"}) {
+                $implIncludes{"<replay/InputCursor.h>"} = 1;
+                push(@implContent, "#if ENABLE(WEB_REPLAY)\n");
+                push(@implContent, "    JSGlobalObject* globalObject = exec->lexicalGlobalObject();\n");
+                push(@implContent, "    InputCursor& cursor = globalObject->inputCursor();\n");
+
+                $implIncludes{"MemoizedDOMResult.h"} = 1;
+                my $nativeType = GetNativeType($type);
+                my $memoizedType = GetNativeTypeForMemoization($type);
+                my $exceptionCode = $getterExceptions ? "ec" : "0";
+                push(@implContent, "    DEFINE_STATIC_LOCAL(const AtomicString, bindingName, (\"$interfaceName.$name\", AtomicString::ConstructFromLiteral));\n");
+                push(@implContent, "    if (cursor.isCapturing()) {\n");
+                push(@implContent, "        $memoizedType memoizedResult = castedThis->impl().$implGetterFunctionName(" . join(", ", @arguments) . ");\n");
+                push(@implContent, "        cursor.appendInput<MemoizedDOMResult<$memoizedType>>(bindingName, memoizedResult, $exceptionCode);\n");
+                push(@implContent, "        JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "memoizedResult", "castedThis") . ";\n");
+                push(@implContent, "        setDOMException(exec, ec);\n") if $getterExceptions;
+                push(@implContent, "        return JSValue::encode(result);\n");
+                push(@implContent, "     }\n");
+                push(@implContent, "\n");
+                push(@implContent, "     if (cursor.isReplaying()) {\n");
+                push(@implContent, "        $memoizedType memoizedResult;\n");
+                push(@implContent, "        MemoizedDOMResultBase* input = cursor.fetchInput<MemoizedDOMResultBase>();\n");
+                push(@implContent, "        if (input && input->convertTo<$memoizedType>(memoizedResult)) {\n");
+                # FIXME: the generated code should report an error if an input cannot be fetched or converted.
+                push(@implContent, "            JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "memoizedResult", "castedThis") . ";\n");
+                push(@implContent, "            setDOMException(exec, input->exceptionCode());\n") if $getterExceptions;
+                push(@implContent, "            return JSValue::encode(result);\n");
+                push(@implContent, "        }\n");
+                push(@implContent, "    }\n");
+                push(@implContent, "#endif\n");
+            } # attribute Nondeterministic
+
             if (HasCustomGetter($attribute->signature->extendedAttributes)) {
                 push(@implContent, "    return JSValue::encode(castedThis->$implGetterFunctionName(exec));\n");
             } elsif ($attribute->signature->extendedAttributes->{"CheckSecurityForNode"}) {
@@ -2273,9 +2312,6 @@ sub GenerateImplementation
                 push(@implContent, "    return JSValue::encode(result);\n");
 
             } else {
-                my @arguments = ("ec");
-                push(@implContent, "    ExceptionCode ec = 0;\n");
-
                 if ($isNullable) {
                     push(@implContent, "    bool isNull = false;\n");
                     unshift(@arguments, "isNull");
@@ -2285,10 +2321,10 @@ sub GenerateImplementation
 
                 if ($svgPropertyOrListPropertyType) {
                     push(@implContent, "    $svgPropertyOrListPropertyType impl(*castedThis->impl());\n");
-                    push(@implContent, "    JSC::JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
+                    push(@implContent, "    JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
                 } else {
                     push(@implContent, "    $interfaceName& impl = castedThis->impl();\n");
-                    push(@implContent, "    JSC::JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
+                    push(@implContent, "    JSValue result = " . NativeToJSValue($attribute->signature, 0, $interfaceName, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
                 }
 
                 if ($isNullable) {
@@ -3501,11 +3537,26 @@ sub GenerateImplementationFunctionCall()
     my $svgPropertyType = shift;
     my $interfaceName = shift;
 
+    my $nondeterministic = $function->signature->extendedAttributes->{"Nondeterministic"};
     my $raisesException = $function->signature->extendedAttributes->{"RaisesException"};
 
     if ($function->signature->type eq "void") {
-        push(@implContent, $indent . "$functionString;\n");
-        push(@implContent, $indent . "setDOMException(exec, ec);\n") if $raisesException;
+        if ($nondeterministic) {
+            $implIncludes{"<replay/InputCursor.h>"} = 1;
+            push(@implContent, "#if ENABLE(WEB_REPLAY)\n");
+            push(@implContent, $indent . "InputCursor& cursor = exec->lexicalGlobalObject()->inputCursor();\n");
+            push(@implContent, $indent . "if (!cursor.isReplaying()) {\n");
+            push(@implContent, $indent . "    $functionString;\n");
+            push(@implContent, $indent . "    setDOMException(exec, ec);\n") if $raisesException;
+            push(@implContent, $indent . "}\n");
+            push(@implContent, "#else\n");
+            push(@implContent, $indent . "$functionString;\n");
+            push(@implContent, $indent . "setDOMException(exec, ec);\n") if $raisesException;
+            push(@implContent, "#endif\n");
+        } else {
+            push(@implContent, $indent . "$functionString;\n");
+            push(@implContent, $indent . "setDOMException(exec, ec);\n") if $raisesException;
+        }
 
         if ($svgPropertyType and !$function->isStatic) {
             if ($raisesException) {
@@ -3519,8 +3570,39 @@ sub GenerateImplementationFunctionCall()
         push(@implContent, $indent . "return JSValue::encode(jsUndefined());\n");
     } else {
         my $thisObject = $function->isStatic ? 0 : "castedThis";
-        push(@implContent, "\n" . $indent . "JSC::JSValue result = " . NativeToJSValue($function->signature, 1, $interfaceName, $functionString, $thisObject) . ";\n");
-        push(@implContent, $indent . "setDOMException(exec, ec);\n") if $raisesException;
+        if ($nondeterministic) {
+            $implIncludes{"MemoizedDOMResult.h"} = 1;
+            $implIncludes{"<replay/InputCursor.h>"} = 1;
+            my $nativeType = GetNativeTypeFromSignature($function->signature);
+            my $memoizedType = GetNativeTypeForMemoization($function->signature->type);
+            my $bindingName = $interfaceName . "." . $function->signature->name;
+            push(@implContent, $indent . "JSValue result;\n");
+            push(@implContent, "#if ENABLE(WEB_REPLAY)\n");
+            push(@implContent, $indent . "InputCursor& cursor = exec->lexicalGlobalObject()->inputCursor();\n");
+            push(@implContent, $indent . "DEFINE_STATIC_LOCAL(const AtomicString, bindingName, (\"$bindingName\", AtomicString::ConstructFromLiteral));\n");
+            push(@implContent, $indent . "if (cursor.isCapturing()) {\n");
+            push(@implContent, $indent . "    $nativeType memoizedResult = $functionString;\n");
+            my $exceptionCode = $raisesException ? "ec" : "0";
+            push(@implContent, $indent . "    cursor.appendInput<MemoizedDOMResult<$memoizedType>>(bindingName, memoizedResult, $exceptionCode);\n");
+            push(@implContent, $indent . "    result = " . NativeToJSValue($function->signature, 1, $interfaceName, "memoizedResult", $thisObject) . ";\n");
+            push(@implContent, $indent . "} else if (cursor.isReplaying()) {\n");
+            push(@implContent, $indent . "    MemoizedDOMResultBase* input = cursor.fetchInput<MemoizedDOMResultBase>();\n");
+            push(@implContent, $indent . "    $memoizedType memoizedResult;\n");
+            # FIXME: the generated code should report an error if an input cannot be fetched or converted.
+            push(@implContent, $indent . "    if (input && input->convertTo<$memoizedType>(memoizedResult)) {\n");
+            push(@implContent, $indent . "        result = " . NativeToJSValue($function->signature, 1, $interfaceName, "memoizedResult", $thisObject) . ";\n");
+            push(@implContent, $indent . "        ec = input->exceptionCode();\n") if $raisesException;
+            push(@implContent, $indent . "    } else\n");
+            push(@implContent, $indent . "        result = " . NativeToJSValue($function->signature, 1, $interfaceName, $functionString, $thisObject) . ";\n");
+            push(@implContent, $indent . "} else\n");
+            push(@implContent, $indent . "    result = " . NativeToJSValue($function->signature, 1, $interfaceName, $functionString, $thisObject) . ";\n");
+            push(@implContent, "#else\n");
+            push(@implContent, $indent . "result = " . NativeToJSValue($function->signature, 1, $interfaceName, $functionString, $thisObject) . ";\n");
+            push(@implContent, "#endif\n");
+        } else {
+            push(@implContent, $indent . "JSValue result = " . NativeToJSValue($function->signature, 1, $interfaceName, $functionString, $thisObject) . ";\n");
+        }
+        push(@implContent, "\n" . $indent . "setDOMException(exec, ec);\n") if $raisesException;
 
         if ($codeGenerator->ExtendedAttributeContains($function->signature->extendedAttributes->{"CallWith"}, "ScriptState")) {
             push(@implContent, $indent . "if (UNLIKELY(exec->hadException()))\n");
@@ -3608,6 +3690,14 @@ sub GetNativeTypeForCallbacks
     return GetNativeType($type);
 }
 
+sub GetNativeTypeForMemoization
+{
+    my $type = shift;
+    return "String" if $type eq "DOMString";
+
+    return GetNativeType($type);
+}
+
 sub GetSVGPropertyTypes
 {
     my $implType = shift;
index 5e793a5..5ef725c 100644 (file)
@@ -85,6 +85,7 @@ MasqueradesAsUndefined
 NamedConstructor=*
 NewImpurePropertyFiresWatchpoints
 NoInterfaceObject
+Nondeterministic
 NotEnumerable
 NotDeletable
 ObjCCustomImplementation
index bc8bc57..4f4b566 100644 (file)
@@ -210,8 +210,7 @@ EncodedJSValue JSC_HOST_CALL jsTestEventTargetPrototypeFunctionItem(ExecState* e
     }
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
-
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.item(index)));
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.item(index)));
     return JSValue::encode(result);
 }
 
@@ -259,8 +258,8 @@ EncodedJSValue JSC_HOST_CALL jsTestEventTargetPrototypeFunctionDispatchEvent(Exe
     Event* evt(toEvent(exec->argument(0)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
+    JSValue result = jsBoolean(impl.dispatchEvent(evt, ec));
 
-    JSC::JSValue result = jsBoolean(impl.dispatchEvent(evt, ec));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
index 02c7499..e305d51 100644 (file)
@@ -685,8 +685,8 @@ EncodedJSValue JSC_HOST_CALL jsTestInterfacePrototypeFunctionImplementsMethod2(E
     TestObj* objArg(toTestObj(exec->argument(1)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.implementsMethod2(scriptContext, strArg, objArg, ec)));
 
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.implementsMethod2(scriptContext, strArg, objArg, ec)));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -751,8 +751,8 @@ EncodedJSValue JSC_HOST_CALL jsTestInterfacePrototypeFunctionSupplementalMethod2
     TestObj* objArg(toTestObj(exec->argument(1)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(TestSupplemental::supplementalMethod2(&impl, scriptContext, strArg, objArg, ec)));
 
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(TestSupplemental::supplementalMethod2(&impl, scriptContext, strArg, objArg, ec)));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
index 217604a..71f4bef 100644 (file)
@@ -939,7 +939,7 @@ EncodedJSValue jsTestObjAttrWithGetterException(ExecState* exec, JSObject* slotB
     }
     ExceptionCode ec = 0;
     TestObj& impl = castedThis->impl();
-    JSC::JSValue result = jsNumber(impl.attrWithGetterException(ec));
+    JSValue result = jsNumber(impl.attrWithGetterException(ec));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -978,7 +978,7 @@ EncodedJSValue jsTestObjStringAttrWithGetterException(ExecState* exec, JSObject*
     }
     ExceptionCode ec = 0;
     TestObj& impl = castedThis->impl();
-    JSC::JSValue result = jsStringWithCache(exec, impl.stringAttrWithGetterException(ec));
+    JSValue result = jsStringWithCache(exec, impl.stringAttrWithGetterException(ec));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -1072,7 +1072,7 @@ EncodedJSValue jsTestObjWithScriptStateAttributeRaises(ExecState* exec, JSObject
     }
     ExceptionCode ec = 0;
     TestObj& impl = castedThis->impl();
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.withScriptStateAttributeRaises(exec, ec)));
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.withScriptStateAttributeRaises(exec, ec)));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -1095,7 +1095,7 @@ EncodedJSValue jsTestObjWithScriptExecutionContextAttributeRaises(ExecState* exe
     if (!scriptContext)
         return JSValue::encode(jsUndefined());
     TestObj& impl = castedThis->impl();
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.withScriptExecutionContextAttributeRaises(scriptContext, ec)));
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.withScriptExecutionContextAttributeRaises(scriptContext, ec)));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -1139,7 +1139,7 @@ EncodedJSValue jsTestObjWithScriptExecutionContextAndScriptStateAttributeRaises(
     if (!scriptContext)
         return JSValue::encode(jsUndefined());
     TestObj& impl = castedThis->impl();
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.withScriptExecutionContextAndScriptStateAttributeRaises(exec, scriptContext, ec)));
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.withScriptExecutionContextAndScriptStateAttributeRaises(exec, scriptContext, ec)));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -1658,7 +1658,7 @@ EncodedJSValue jsTestObjNullableStringValue(ExecState* exec, JSObject* slotBase,
     ExceptionCode ec = 0;
     bool isNull = false;
     TestObj& impl = castedThis->impl();
-    JSC::JSValue result = jsNumber(impl.nullableStringValue(isNull, ec));
+    JSValue result = jsNumber(impl.nullableStringValue(isNull, ec));
     if (isNull)
         return JSValue::encode(jsNull());
     setDOMException(exec, ec);
@@ -2673,8 +2673,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionByteMethod(ExecState* exe
         return throwVMTypeError(exec);
     ASSERT_GC_OBJECT_INHERITS(castedThis, JSTestObj::info());
     TestObj& impl = castedThis->impl();
-
-    JSC::JSValue result = jsNumber(impl.byteMethod());
+    JSValue result = jsNumber(impl.byteMethod());
     return JSValue::encode(result);
 }
 
@@ -2697,8 +2696,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionByteMethodWithArgs(ExecSt
     TestObj* objArg(toTestObj(exec->argument(2)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
-
-    JSC::JSValue result = jsNumber(impl.byteMethodWithArgs(byteArg, strArg, objArg));
+    JSValue result = jsNumber(impl.byteMethodWithArgs(byteArg, strArg, objArg));
     return JSValue::encode(result);
 }
 
@@ -2710,8 +2708,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionOctetMethod(ExecState* ex
         return throwVMTypeError(exec);
     ASSERT_GC_OBJECT_INHERITS(castedThis, JSTestObj::info());
     TestObj& impl = castedThis->impl();
-
-    JSC::JSValue result = jsNumber(impl.octetMethod());
+    JSValue result = jsNumber(impl.octetMethod());
     return JSValue::encode(result);
 }
 
@@ -2734,8 +2731,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionOctetMethodWithArgs(ExecS
     TestObj* objArg(toTestObj(exec->argument(2)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
-
-    JSC::JSValue result = jsNumber(impl.octetMethodWithArgs(octetArg, strArg, objArg));
+    JSValue result = jsNumber(impl.octetMethodWithArgs(octetArg, strArg, objArg));
     return JSValue::encode(result);
 }
 
@@ -2747,8 +2743,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionLongMethod(ExecState* exe
         return throwVMTypeError(exec);
     ASSERT_GC_OBJECT_INHERITS(castedThis, JSTestObj::info());
     TestObj& impl = castedThis->impl();
-
-    JSC::JSValue result = jsNumber(impl.longMethod());
+    JSValue result = jsNumber(impl.longMethod());
     return JSValue::encode(result);
 }
 
@@ -2771,8 +2766,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionLongMethodWithArgs(ExecSt
     TestObj* objArg(toTestObj(exec->argument(2)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
-
-    JSC::JSValue result = jsNumber(impl.longMethodWithArgs(longArg, strArg, objArg));
+    JSValue result = jsNumber(impl.longMethodWithArgs(longArg, strArg, objArg));
     return JSValue::encode(result);
 }
 
@@ -2784,8 +2778,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionObjMethod(ExecState* exec
         return throwVMTypeError(exec);
     ASSERT_GC_OBJECT_INHERITS(castedThis, JSTestObj::info());
     TestObj& impl = castedThis->impl();
-
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.objMethod()));
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.objMethod()));
     return JSValue::encode(result);
 }
 
@@ -2808,8 +2801,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionObjMethodWithArgs(ExecSta
     TestObj* objArg(toTestObj(exec->argument(2)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
-
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.objMethodWithArgs(longArg, strArg, objArg)));
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.objMethodWithArgs(longArg, strArg, objArg)));
     return JSValue::encode(result);
 }
 
@@ -2843,8 +2835,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionMethodReturningSequence(E
     int longArg(toInt32(exec, exec->argument(0), NormalConversion));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
-
-    JSC::JSValue result = jsArray(exec, castedThis->globalObject(), impl.methodReturningSequence(longArg));
+    JSValue result = jsArray(exec, castedThis->globalObject(), impl.methodReturningSequence(longArg));
     return JSValue::encode(result);
 }
 
@@ -2884,8 +2875,8 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionMethodThatRequiresAllArgs
     TestObj* objArg(toTestObj(exec->argument(1)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.methodThatRequiresAllArgsAndThrows(strArg, objArg, ec)));
 
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.methodThatRequiresAllArgsAndThrows(strArg, objArg, ec)));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -3011,8 +3002,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionWithScriptStateObj(ExecSt
         return throwVMTypeError(exec);
     ASSERT_GC_OBJECT_INHERITS(castedThis, JSTestObj::info());
     TestObj& impl = castedThis->impl();
-
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.withScriptStateObj(exec)));
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.withScriptStateObj(exec)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
     return JSValue::encode(result);
@@ -3041,8 +3031,8 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionWithScriptStateObjExcepti
     ASSERT_GC_OBJECT_INHERITS(castedThis, JSTestObj::info());
     TestObj& impl = castedThis->impl();
     ExceptionCode ec = 0;
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.withScriptStateObjException(exec, ec)));
 
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.withScriptStateObjException(exec, ec)));
     setDOMException(exec, ec);
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
@@ -3091,8 +3081,8 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionWithScriptExecutionContex
     ScriptExecutionContext* scriptContext = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();
     if (!scriptContext)
         return JSValue::encode(jsUndefined());
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.withScriptExecutionContextAndScriptStateObjException(exec, scriptContext, ec)));
 
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.withScriptExecutionContextAndScriptStateObjException(exec, scriptContext, ec)));
     setDOMException(exec, ec);
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
@@ -3110,8 +3100,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionWithScriptExecutionContex
     ScriptExecutionContext* scriptContext = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();
     if (!scriptContext)
         return JSValue::encode(jsUndefined());
-
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.withScriptExecutionContextAndScriptStateWithSpaces(exec, scriptContext)));
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.withScriptExecutionContextAndScriptStateWithSpaces(exec, scriptContext)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
     return JSValue::encode(result);
@@ -3353,8 +3342,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionConditionalMethod1(ExecSt
         return throwVMTypeError(exec);
     ASSERT_GC_OBJECT_INHERITS(castedThis, JSTestObj::info());
     TestObj& impl = castedThis->impl();
-
-    JSC::JSValue result = jsStringWithCache(exec, impl.conditionalMethod1());
+    JSValue result = jsStringWithCache(exec, impl.conditionalMethod1());
     return JSValue::encode(result);
 }
 
@@ -3633,16 +3621,14 @@ EncodedJSValue JSC_HOST_CALL jsTestObjConstructorFunctionClassMethodWithOptional
 
     size_t argsCount = exec->argumentCount();
     if (argsCount <= 0) {
-
-        JSC::JSValue result = jsNumber(TestObj::classMethodWithOptional());
+        JSValue result = jsNumber(TestObj::classMethodWithOptional());
         return JSValue::encode(result);
     }
 
     int arg(toInt32(exec, exec->argument(0), NormalConversion));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
-
-    JSC::JSValue result = jsNumber(TestObj::classMethodWithOptional(arg));
+    JSValue result = jsNumber(TestObj::classMethodWithOptional(arg));
     return JSValue::encode(result);
 }
 
@@ -3761,8 +3747,8 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionStringArrayFunction(ExecS
     Vector<String> values(toNativeArray<String>(exec, exec->argument(0)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
+    JSValue result = jsArray(exec, castedThis->globalObject(), impl.stringArrayFunction(values, ec));
 
-    JSC::JSValue result = jsArray(exec, castedThis->globalObject(), impl.stringArrayFunction(values, ec));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -3781,8 +3767,8 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionDomStringListFunction(Exe
     RefPtr<DOMStringList> values(toDOMStringList(exec, exec->argument(0)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.domStringListFunction(values, ec)));
 
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.domStringListFunction(values, ec)));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -3798,8 +3784,8 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionGetSVGDocument(ExecState*
     ExceptionCode ec = 0;
     if (!shouldAllowAccessToNode(exec, impl.getSVGDocument(ec)))
         return JSValue::encode(jsNull());
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.getSVGDocument(ec)));
 
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.getSVGDocument(ec)));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -3880,8 +3866,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionMutablePointFunction(Exec
         return throwVMTypeError(exec);
     ASSERT_GC_OBJECT_INHERITS(castedThis, JSTestObj::info());
     TestObj& impl = castedThis->impl();
-
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(SVGPropertyTearOff<SVGPoint>::create(impl.mutablePointFunction())));
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(SVGPropertyTearOff<SVGPoint>::create(impl.mutablePointFunction())));
     return JSValue::encode(result);
 }
 
@@ -3893,8 +3878,7 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionImmutablePointFunction(Ex
         return throwVMTypeError(exec);
     ASSERT_GC_OBJECT_INHERITS(castedThis, JSTestObj::info());
     TestObj& impl = castedThis->impl();
-
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(SVGPropertyTearOff<SVGPoint>::create(impl.immutablePointFunction())));
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(SVGPropertyTearOff<SVGPoint>::create(impl.immutablePointFunction())));
     return JSValue::encode(result);
 }
 
@@ -3930,8 +3914,8 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionStrictFunction(ExecState*
     int b(toInt32(exec, exec->argument(2), NormalConversion));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.strictFunction(str, a, b, ec)));
 
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.strictFunction(str, a, b, ec)));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -3955,8 +3939,8 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionStrictFunctionWithSequenc
     Vector<unsigned> a(toNativeArray<unsigned>(exec, exec->argument(1)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.strictFunctionWithSequence(objArg, a, ec)));
 
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.strictFunctionWithSequence(objArg, a, ec)));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -3980,8 +3964,8 @@ EncodedJSValue JSC_HOST_CALL jsTestObjPrototypeFunctionStrictFunctionWithArray(E
     Vector<int> array(toNativeArray<int>(exec, exec->argument(1)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.strictFunctionWithArray(objArg, array, ec)));
 
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(impl.strictFunctionWithArray(objArg, array, ec)));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
index 292b3af..469e188 100644 (file)
@@ -245,7 +245,7 @@ EncodedJSValue jsTestTypedefsAttrWithGetterException(ExecState* exec, JSObject*
     }
     ExceptionCode ec = 0;
     TestTypedefs& impl = castedThis->impl();
-    JSC::JSValue result = jsNumber(impl.attrWithGetterException(ec));
+    JSValue result = jsNumber(impl.attrWithGetterException(ec));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -284,7 +284,7 @@ EncodedJSValue jsTestTypedefsStringAttrWithGetterException(ExecState* exec, JSOb
     }
     ExceptionCode ec = 0;
     TestTypedefs& impl = castedThis->impl();
-    JSC::JSValue result = jsStringWithCache(exec, impl.stringAttrWithGetterException(ec));
+    JSValue result = jsStringWithCache(exec, impl.stringAttrWithGetterException(ec));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -506,8 +506,7 @@ EncodedJSValue JSC_HOST_CALL jsTestTypedefsPrototypeFunctionMethodWithSequenceAr
     Vector<RefPtr<SerializedScriptValue>> sequenceArg((toRefPtrNativeArray<SerializedScriptValue, JSSerializedScriptValue>(exec, exec->argument(0), &toSerializedScriptValue)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
-
-    JSC::JSValue result = jsNumber(impl.methodWithSequenceArg(sequenceArg));
+    JSValue result = jsNumber(impl.methodWithSequenceArg(sequenceArg));
     return JSValue::encode(result);
 }
 
@@ -573,8 +572,7 @@ EncodedJSValue JSC_HOST_CALL jsTestTypedefsPrototypeFunctionImmutablePointFuncti
         return throwVMTypeError(exec);
     ASSERT_GC_OBJECT_INHERITS(castedThis, JSTestTypedefs::info());
     TestTypedefs& impl = castedThis->impl();
-
-    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(SVGPropertyTearOff<SVGPoint>::create(impl.immutablePointFunction())));
+    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(SVGPropertyTearOff<SVGPoint>::create(impl.immutablePointFunction())));
     return JSValue::encode(result);
 }
 
@@ -592,8 +590,8 @@ EncodedJSValue JSC_HOST_CALL jsTestTypedefsPrototypeFunctionStringArrayFunction(
     Vector<String> values(toNativeArray<String>(exec, exec->argument(0)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
+    JSValue result = jsArray(exec, castedThis->globalObject(), impl.stringArrayFunction(values, ec));
 
-    JSC::JSValue result = jsArray(exec, castedThis->globalObject(), impl.stringArrayFunction(values, ec));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -612,8 +610,8 @@ EncodedJSValue JSC_HOST_CALL jsTestTypedefsPrototypeFunctionStringArrayFunction2
     Vector<String> values(toNativeArray<String>(exec, exec->argument(0)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
+    JSValue result = jsArray(exec, castedThis->globalObject(), impl.stringArrayFunction2(values, ec));
 
-    JSC::JSValue result = jsArray(exec, castedThis->globalObject(), impl.stringArrayFunction2(values, ec));
     setDOMException(exec, ec);
     return JSValue::encode(result);
 }
@@ -631,8 +629,7 @@ EncodedJSValue JSC_HOST_CALL jsTestTypedefsPrototypeFunctionCallWithSequenceThat
     Vector<RefPtr<TestEventTarget>> sequenceArg((toRefPtrNativeArray<TestEventTarget, JSTestEventTarget>(exec, exec->argument(0), &toTestEventTarget)));
     if (UNLIKELY(exec->hadException()))
         return JSValue::encode(jsUndefined());
-
-    JSC::JSValue result = jsBoolean(impl.callWithSequenceThatRequiresInclude(sequenceArg));
+    JSValue result = jsBoolean(impl.callWithSequenceThatRequiresInclude(sequenceArg));
     return JSValue::encode(result);
 }
 
index 7a951e2..2151c2e 100644 (file)
@@ -36,6 +36,7 @@
 
 #if ENABLE(WEB_REPLAY)
 
+#include "MemoizedDOMResult.h"
 #include "WebReplayInputs.h"
 #include <JavaScriptCore/JSReplayInputs.h>
 
diff --git a/Source/WebCore/replay/MemoizedDOMResult.cpp b/Source/WebCore/replay/MemoizedDOMResult.cpp
new file mode 100644 (file)
index 0000000..ada7de3
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * HOLDER 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 "MemoizedDOMResult.h"
+
+#if ENABLE(WEB_REPLAY)
+
+#include "ReplayInputTypes.h"
+#include "SerializationMethods.h"
+#include "WebReplayInputs.h"
+
+namespace WebCore {
+
+const AtomicString& MemoizedDOMResultBase::type() const
+{
+    return inputTypes().MemoizedDOMResult;
+}
+
+std::unique_ptr<MemoizedDOMResultBase> MemoizedDOMResultBase::createFromEncodedResult(const String& attribute, EncodedCType ctype, EncodedValue encodedValue, ExceptionCode exceptionCode)
+{
+    switch (ctype) {
+#define CREATE_DECODE_SWITCH_CASE(name, type) \
+    case CTypeTraits<type>::encodedType: { \
+        CTypeTraits<type>::CType result; \
+        if (!EncodingTraits<type>::decodeValue(encodedValue, result)) \
+            return nullptr; \
+        return std::make_unique<MemoizedDOMResult<type>>(attribute, result, exceptionCode); \
+    } \
+\
+
+FOR_EACH_MEMOIZED_CTYPE(CREATE_DECODE_SWITCH_CASE)
+#undef CREATE_DECODE_SWITCH_CASE
+    }
+}
+
+} // namespace WebCore
+
+namespace JSC {
+
+using WebCore::EncodedCType;
+using WebCore::ExceptionCode;
+using WebCore::MemoizedDOMResult;
+using WebCore::SerializedScriptValue;
+
+const AtomicString& InputTraits<MemoizedDOMResultBase>::type()
+{
+    return WebCore::inputTypes().MemoizedDOMResult;
+}
+
+void InputTraits<MemoizedDOMResultBase>::encode(EncodedValue& encodedValue, const MemoizedDOMResultBase& input)
+{
+    encodedValue.put<String>(ASCIILiteral("attribute"), input.attribute());
+    encodedValue.put<EncodedCType>(ASCIILiteral("ctype"), input.ctype());
+    encodedValue.put<EncodedValue>(ASCIILiteral("result"), input.encodedResult());
+    if (input.exceptionCode())
+        encodedValue.put<ExceptionCode>(ASCIILiteral("exceptionCode"), input.exceptionCode());
+}
+
+bool InputTraits<MemoizedDOMResultBase>::decode(EncodedValue& encodedValue, std::unique_ptr<MemoizedDOMResultBase>& input)
+{
+    String attribute;
+    if (!encodedValue.get<String>(ASCIILiteral("attribute"), attribute))
+        return false;
+
+    EncodedCType ctype;
+    if (!encodedValue.get<EncodedCType>(ASCIILiteral("ctype"), ctype))
+        return false;
+
+    EncodedValue encodedResult;
+    if (!encodedValue.get<EncodedValue>(ASCIILiteral("result"), encodedResult))
+        return false;
+
+    ExceptionCode exceptionCode = 0;
+    encodedValue.get<ExceptionCode>(ASCIILiteral("exceptionCode"), exceptionCode);
+
+    std::unique_ptr<MemoizedDOMResultBase> decodedInput = MemoizedDOMResultBase::createFromEncodedResult(attribute, ctype, encodedResult, exceptionCode);
+    if (!decodedInput)
+        return false;
+    input = std::move(decodedInput);
+    return true;
+}
+
+} // namespace JSC
+
+#endif // ENABLE(WEB_REPLAY)
diff --git a/Source/WebCore/replay/MemoizedDOMResult.h b/Source/WebCore/replay/MemoizedDOMResult.h
new file mode 100644 (file)
index 0000000..65bcee6
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2012 University of Washington. 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.
+ * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * HOLDER 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 MemoizedDOMResult_h
+#define MemoizedDOMResult_h
+
+#if ENABLE(WEB_REPLAY)
+
+#include <replay/EncodedValue.h>
+#include <replay/NondeterministicInput.h>
+
+namespace WebCore {
+
+class SerializedScriptValue;
+
+typedef int ExceptionCode;
+
+// Add new memoized ctypes here. The first argument is the enum value,
+// which cannot conflict with built-in primitive types. The second is
+// the actual C type that is used to specialize CTypeTraits. New enum
+// values should also be added to the definition in WebInputs.json.
+#define FOR_EACH_MEMOIZED_CTYPE(macro) \
+    macro(Boolean, bool) \
+    macro(Int, int) \
+    macro(String, String) \
+    macro(Unsigned, unsigned) \
+    \
+// end of FOR_EACH_MEMOIZED_CTYPE
+
+// We encode this enum so that we can recover MemoizedType when decoding the input
+// and then call the correct specialized MemoizedDOMResult<T> constructor.
+enum class EncodedCType {
+#define CREATE_ENUM_VALUE(name, type) name,
+
+FOR_EACH_MEMOIZED_CTYPE(CREATE_ENUM_VALUE)
+#undef CREATE_ENUM_VALUE
+};
+
+class MemoizedDOMResultBase : public NondeterministicInputBase {
+public:
+    MemoizedDOMResultBase(const String& attribute, EncodedCType ctype, ExceptionCode exceptionCode = 0)
+        : m_attribute(attribute)
+        , m_ctype(ctype)
+        , m_exceptionCode(exceptionCode) { }
+
+    virtual ~MemoizedDOMResultBase() { }
+
+    static std::unique_ptr<MemoizedDOMResultBase> createFromEncodedResult(const String& attribute, EncodedCType, EncodedValue, ExceptionCode);
+
+    template<typename T>
+    bool convertTo(T& decodedValue);
+
+    virtual EncodedValue encodedResult() const = 0;
+    virtual InputQueue queue() const final override { return InputQueue::ScriptMemoizedData; }
+    virtual const AtomicString& type() const final override;
+
+    const String& attribute() const { return m_attribute; }
+    EncodedCType ctype() const { return m_ctype; }
+    ExceptionCode exceptionCode() const { return m_exceptionCode; }
+private:
+    String m_attribute;
+    EncodedCType m_ctype;
+    ExceptionCode m_exceptionCode;
+};
+
+template<typename T>
+struct CTypeTraits {
+    static bool decode(EncodedValue& encodedValue, T& decodedValue)
+    {
+        return EncodingTraits<T>::decodeValue(encodedValue, decodedValue);
+    }
+};
+
+#define CREATE_CTYPE_TRAITS(_name, _type) \
+template<> \
+struct CTypeTraits<_type> { \
+    typedef _type CType; \
+    static const EncodedCType encodedType = EncodedCType::_name; \
+}; \
+
+FOR_EACH_MEMOIZED_CTYPE(CREATE_CTYPE_TRAITS)
+#undef CREATE_CTYPE_TRAITS
+
+template<typename MemoizedType>
+class MemoizedDOMResult final : public MemoizedDOMResultBase {
+public:
+    MemoizedDOMResult(const String& attribute, typename CTypeTraits<MemoizedType>::CType result, ExceptionCode exceptionCode)
+        : MemoizedDOMResultBase(attribute, CTypeTraits<MemoizedType>::encodedType, exceptionCode)
+        , m_result(result) { }
+    virtual ~MemoizedDOMResult() { }
+
+    virtual EncodedValue encodedResult() const override
+    {
+        return EncodingTraits<MemoizedType>::encodeValue(m_result);
+    }
+
+    typename CTypeTraits<MemoizedType>::CType result() const { return m_result; }
+private:
+    typename CTypeTraits<MemoizedType>::CType m_result;
+};
+
+// This is used by clients of the memoized DOM result to get out the memoized
+// value without performing a cast to MemoizedDOMResult<T> and calling result().
+template<typename T>
+bool MemoizedDOMResultBase::convertTo(T& convertedValue)
+{
+    // Type tag doesn't match; fail to decode the value.
+    if (m_ctype != CTypeTraits<T>::encodedType)
+        return false;
+
+    MemoizedDOMResult<T>& castedResult = static_cast<MemoizedDOMResult<T>&>(*this);
+    convertedValue = castedResult.result();
+    return true;
+}
+
+} // namespace WebCore
+
+using WebCore::MemoizedDOMResultBase;
+
+namespace JSC {
+
+template<>
+struct InputTraits<MemoizedDOMResultBase> {
+    static InputQueue queue() { return InputQueue::ScriptMemoizedData; }
+    static const AtomicString& type();
+
+    static void encode(EncodedValue&, const MemoizedDOMResultBase& input);
+    static bool decode(EncodedValue&, std::unique_ptr<MemoizedDOMResultBase>& input);
+};
+
+} // namespace JSC
+
+#endif // ENABLE(WEB_REPLAY)
+
+#endif // MemoizedDOMResult_h
index 98b14f1..796819e 100644 (file)
@@ -39,6 +39,7 @@ ReplayInputTypes::ReplayInputTypes()
     : dummy(0)
 JS_REPLAY_INPUT_NAMES_FOR_EACH(INITIALIZE_INPUT_TYPE)
 WEB_REPLAY_INPUT_NAMES_FOR_EACH(INITIALIZE_INPUT_TYPE)
+INITIALIZE_INPUT_TYPE(MemoizedDOMResult)
 {
     UNUSED_PARAM(dummy);
 }
index b198423..c4126f2 100644 (file)
@@ -46,6 +46,7 @@ public:
 #define DECLARE_REPLAY_INPUT_TYPES(name) AtomicString name;
     JS_REPLAY_INPUT_NAMES_FOR_EACH(DECLARE_REPLAY_INPUT_TYPES)
     WEB_REPLAY_INPUT_NAMES_FOR_EACH(DECLARE_REPLAY_INPUT_TYPES)
+    DECLARE_REPLAY_INPUT_TYPES(MemoizedDOMResult);
 #undef DECLARE_REPLAY_INPUT_TYPES
 };
 
index b86178b..1f15043 100644 (file)
@@ -63,6 +63,12 @@ EncodedValue EncodingTraits<NondeterministicInputBase>::encodeValue(const Nondet
     WEB_REPLAY_INPUT_NAMES_FOR_EACH(ENCODE_IF_TYPE_TAG_MATCHES)
 #undef ENCODE_IF_TYPE_TAG_MATCHES
 
+    // The macro won't work here because of the class template argument.
+    if (type == inputTypes().MemoizedDOMResult) {
+        InputTraits<MemoizedDOMResultBase>::encode(encodedValue, static_cast<const MemoizedDOMResultBase&>(input));
+        return encodedValue;
+    }
+
     ASSERT_NOT_REACHED();
     return EncodedValue();
 }
@@ -87,6 +93,15 @@ bool EncodingTraits<NondeterministicInputBase>::decodeValue(EncodedValue& encode
     WEB_REPLAY_INPUT_NAMES_FOR_EACH(DECODE_IF_TYPE_TAG_MATCHES)
 #undef DECODE_IF_TYPE_TAG_MATCHES
 
+    if (type == inputTypes().MemoizedDOMResult) {
+        std::unique_ptr<MemoizedDOMResultBase> decodedInput;
+        if (!InputTraits<MemoizedDOMResultBase>::decode(encodedValue, decodedInput))
+            return false;
+
+        input = std::move(decodedInput);
+        return true;
+    }
+
     return false;
 }
 
index 5e651e1..28f0d7b 100644 (file)
                 "header": "platform/URL.h"
             },
             {
+                "name": "EncodedCType", "mode": "SCALAR", "storage": "uint8_t",
+                "flags": ["ENUM_CLASS"],
+                "values": [
+                    "Boolean",
+                    "Int",
+                    "String",
+                    "Unsigned"
+                ],
+                "header": "replay/MemoizedDOMResult.h"
+            },
+            {
                 "name": "SecurityOrigin", "mode": "SHARED",
                 "header": "page/SecurityOrigin.h"
             },