DFG string conversions and allocations should be inlined
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Mar 2013 18:09:22 +0000 (18:09 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Mar 2013 18:09:22 +0000 (18:09 +0000)
https://bugs.webkit.org/show_bug.cgi?id=112376

Source/JavaScriptCore:

Reviewed by Geoffrey Garen.

This turns new String(), String(), String.prototype.valueOf(), and
String.prototype.toString() into intrinsics. It gives the DFG the ability to handle
conversions from StringObject to JSString and vice-versa, and also gives it the
ability to handle cases where a variable may be either a StringObject or a JSString.
To do this, I added StringObject to value profiling (and removed the stale
distinction between Myarguments and Foreignarguments). I also cleaned up ToPrimitive
handling, using some of the new functionality but also taking advantage of the
existence of Identity(String:@a).

This is a 2% SunSpider speed-up. Also there are some speed-ups on V8v7 and Kraken.
On microbenchmarks that stress new String() this is a 14x speed-up.

* CMakeLists.txt:
* DerivedSources.make:
* DerivedSources.pri:
* GNUmakefile.list.am:
* bytecode/CodeBlock.h:
(CodeBlock):
(JSC::CodeBlock::hasExitSite):
(JSC):
* bytecode/DFGExitProfile.cpp:
(JSC::DFG::ExitProfile::hasExitSite):
(DFG):
* bytecode/DFGExitProfile.h:
(ExitProfile):
(JSC::DFG::ExitProfile::hasExitSite):
* bytecode/ExitKind.cpp:
(JSC::exitKindToString):
* bytecode/ExitKind.h:
* bytecode/SpeculatedType.cpp:
(JSC::dumpSpeculation):
(JSC::speculationToAbbreviatedString):
(JSC::speculationFromClassInfo):
* bytecode/SpeculatedType.h:
(JSC):
(JSC::isStringObjectSpeculation):
(JSC::isStringOrStringObjectSpeculation):
* create_hash_table:
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::executeEffects):
* dfg/DFGAbstractState.h:
(JSC::DFG::AbstractState::filterEdgeByUse):
* dfg/DFGByteCodeParser.cpp:
(ByteCodeParser):
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::emitArgumentPhantoms):
(DFG):
(JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::putStructureStoreElimination):
* dfg/DFGEdge.h:
(JSC::DFG::Edge::shift):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::isStringPrototypeMethodSane):
(FixupPhase):
(JSC::DFG::FixupPhase::canOptimizeStringObjectAccess):
(JSC::DFG::FixupPhase::observeUseKindOnNode):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::hasGlobalExitSite):
(Graph):
(JSC::DFG::Graph::hasExitSite):
(JSC::DFG::Graph::clobbersWorld):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToToString):
(Node):
(JSC::DFG::Node::hasStructure):
(JSC::DFG::Node::shouldSpeculateStringObject):
(JSC::DFG::Node::shouldSpeculateStringOrStringObject):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileToStringOnCell):
(DFG):
(JSC::DFG::SpeculativeJIT::compileNewStringObject):
(JSC::DFG::SpeculativeJIT::speculateObject):
(JSC::DFG::SpeculativeJIT::speculateObjectOrOther):
(JSC::DFG::SpeculativeJIT::speculateString):
(JSC::DFG::SpeculativeJIT::speculateStringObject):
(JSC::DFG::SpeculativeJIT::speculateStringOrStringObject):
(JSC::DFG::SpeculativeJIT::speculate):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
(SpeculativeJIT):
(JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
(DFG):
(JSC::DFG::SpeculativeJIT::speculateStringObjectForStructure):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
* interpreter/CallFrame.h:
(JSC::ExecState::regExpPrototypeTable):
* runtime/CommonIdentifiers.h:
* runtime/Intrinsic.h:
* runtime/JSDestructibleObject.h:
(JSDestructibleObject):
(JSC::JSDestructibleObject::classInfoOffset):
* runtime/JSGlobalData.cpp:
(JSC):
(JSC::JSGlobalData::JSGlobalData):
(JSC::JSGlobalData::~JSGlobalData):
* runtime/JSGlobalData.h:
(JSGlobalData):
* runtime/JSObject.cpp:
* runtime/JSObject.h:
(JSC):
* runtime/JSWrapperObject.h:
(JSC::JSWrapperObject::allocationSize):
(JSWrapperObject):
(JSC::JSWrapperObject::internalValueOffset):
(JSC::JSWrapperObject::internalValueCellOffset):
* runtime/StringPrototype.cpp:
(JSC):
(JSC::StringPrototype::finishCreation):
(JSC::StringPrototype::create):
* runtime/StringPrototype.h:
(StringPrototype):

LayoutTests:

Reviewed by Geoffrey Garen.

* fast/js/dfg-to-string-bad-toString-expected.txt: Added.
* fast/js/dfg-to-string-bad-toString.html: Added.
* fast/js/dfg-to-string-bad-valueOf-expected.txt: Added.
* fast/js/dfg-to-string-bad-valueOf.html: Added.
* fast/js/dfg-to-string-int-expected.txt: Added.
* fast/js/dfg-to-string-int-or-string-expected.txt: Added.
* fast/js/dfg-to-string-int-or-string.html: Added.
* fast/js/dfg-to-string-int.html: Added.
* fast/js/dfg-to-string-side-effect-clobbers-toString-expected.txt: Added.
* fast/js/dfg-to-string-side-effect-clobbers-toString.html: Added.
* fast/js/dfg-to-string-side-effect-expected.txt: Added.
* fast/js/dfg-to-string-side-effect.html: Added.
* fast/js/dfg-to-string-toString-becomes-bad-expected.txt: Added.
* fast/js/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype-expected.txt: Added.
* fast/js/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype.html: Added.
* fast/js/dfg-to-string-toString-becomes-bad.html: Added.
* fast/js/dfg-to-string-toString-in-string-expected.txt: Added.
* fast/js/dfg-to-string-toString-in-string.html: Added.
* fast/js/dfg-to-string-valueOf-becomes-bad-expected.txt: Added.
* fast/js/dfg-to-string-valueOf-becomes-bad.html: Added.
* fast/js/dfg-to-string-valueOf-in-string-expected.txt: Added.
* fast/js/dfg-to-string-valueOf-in-string.html: Added.
* fast/js/jsc-test-list:
* fast/js/regress/script-tests/string-concat-object.js: Added.
(foo):
* fast/js/regress/script-tests/string-concat-pair-object.js: Added.
(foo):
* fast/js/regress/script-tests/string-concat-pair-simple.js: Added.
(foo):
* fast/js/regress/script-tests/string-concat-simple.js: Added.
(foo):
* fast/js/regress/script-tests/string-cons-repeat.js: Added.
(foo):
* fast/js/regress/script-tests/string-cons-tower.js: Added.
(foo):
* fast/js/regress/string-concat-object-expected.txt: Added.
* fast/js/regress/string-concat-object.html: Added.
* fast/js/regress/string-concat-pair-object-expected.txt: Added.
* fast/js/regress/string-concat-pair-object.html: Added.
* fast/js/regress/string-concat-pair-simple-expected.txt: Added.
* fast/js/regress/string-concat-pair-simple.html: Added.
* fast/js/regress/string-concat-simple-expected.txt: Added.
* fast/js/regress/string-concat-simple.html: Added.
* fast/js/regress/string-cons-repeat-expected.txt: Added.
* fast/js/regress/string-cons-repeat.html: Added.
* fast/js/regress/string-cons-tower-expected.txt: Added.
* fast/js/regress/string-cons-tower.html: Added.
* fast/js/script-tests/dfg-to-string-bad-toString.js: Added.
(String.prototype.toString):
(foo):
* fast/js/script-tests/dfg-to-string-bad-valueOf.js: Added.
(String.prototype.valueOf):
(foo):
* fast/js/script-tests/dfg-to-string-int-or-string.js: Added.
(foo):
* fast/js/script-tests/dfg-to-string-int.js: Added.
(foo):
* fast/js/script-tests/dfg-to-string-side-effect-clobbers-toString.js: Added.
(foo):
* fast/js/script-tests/dfg-to-string-side-effect.js: Added.
(foo):
* fast/js/script-tests/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype.js: Added.
(foo):
(.String.prototype.toString):
* fast/js/script-tests/dfg-to-string-toString-becomes-bad.js: Added.
(foo):
(.String.prototype.toString):
* fast/js/script-tests/dfg-to-string-toString-in-string.js: Added.
(foo):
(.argument.toString):
* fast/js/script-tests/dfg-to-string-valueOf-becomes-bad.js: Added.
(foo):
(.String.prototype.valueOf):
* fast/js/script-tests/dfg-to-string-valueOf-in-string.js: Added.
(foo):
(.argument.valueOf):

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

94 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/js/dfg-to-string-bad-toString-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-bad-toString.html [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-bad-valueOf-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-bad-valueOf.html [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-int-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-int-or-string-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-int-or-string.html [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-int.html [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-side-effect-clobbers-toString-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-side-effect-clobbers-toString.html [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-side-effect-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-side-effect.html [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-toString-becomes-bad-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype.html [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-toString-becomes-bad.html [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-toString-in-string-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-toString-in-string.html [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-valueOf-becomes-bad-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-valueOf-becomes-bad.html [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-valueOf-in-string-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/dfg-to-string-valueOf-in-string.html [new file with mode: 0644]
LayoutTests/fast/js/jsc-test-list
LayoutTests/fast/js/regress/script-tests/string-concat-object.js [new file with mode: 0644]
LayoutTests/fast/js/regress/script-tests/string-concat-pair-object.js [new file with mode: 0644]
LayoutTests/fast/js/regress/script-tests/string-concat-pair-simple.js [new file with mode: 0644]
LayoutTests/fast/js/regress/script-tests/string-concat-simple.js [new file with mode: 0644]
LayoutTests/fast/js/regress/script-tests/string-cons-repeat.js [new file with mode: 0644]
LayoutTests/fast/js/regress/script-tests/string-cons-tower.js [new file with mode: 0644]
LayoutTests/fast/js/regress/string-concat-object-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/regress/string-concat-object.html [new file with mode: 0644]
LayoutTests/fast/js/regress/string-concat-pair-object-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/regress/string-concat-pair-object.html [new file with mode: 0644]
LayoutTests/fast/js/regress/string-concat-pair-simple-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/regress/string-concat-pair-simple.html [new file with mode: 0644]
LayoutTests/fast/js/regress/string-concat-simple-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/regress/string-concat-simple.html [new file with mode: 0644]
LayoutTests/fast/js/regress/string-cons-repeat-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/regress/string-cons-repeat.html [new file with mode: 0644]
LayoutTests/fast/js/regress/string-cons-tower-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/regress/string-cons-tower.html [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-to-string-bad-toString.js [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-to-string-bad-valueOf.js [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-to-string-int-or-string.js [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-to-string-int.js [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-to-string-side-effect-clobbers-toString.js [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-to-string-side-effect.js [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype.js [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-to-string-toString-becomes-bad.js [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-to-string-toString-in-string.js [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-to-string-valueOf-becomes-bad.js [new file with mode: 0644]
LayoutTests/fast/js/script-tests/dfg-to-string-valueOf-in-string.js [new file with mode: 0644]
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/DerivedSources.make
Source/JavaScriptCore/DerivedSources.pri
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/DFGExitProfile.cpp
Source/JavaScriptCore/bytecode/DFGExitProfile.h
Source/JavaScriptCore/bytecode/ExitKind.cpp
Source/JavaScriptCore/bytecode/ExitKind.h
Source/JavaScriptCore/bytecode/SpeculatedType.cpp
Source/JavaScriptCore/bytecode/SpeculatedType.h
Source/JavaScriptCore/create_hash_table
Source/JavaScriptCore/dfg/DFGAbstractState.cpp
Source/JavaScriptCore/dfg/DFGAbstractState.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
Source/JavaScriptCore/dfg/DFGEdge.h
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGUseKind.cpp
Source/JavaScriptCore/dfg/DFGUseKind.h
Source/JavaScriptCore/interpreter/CallFrame.h
Source/JavaScriptCore/runtime/Intrinsic.h
Source/JavaScriptCore/runtime/JSDestructibleObject.h
Source/JavaScriptCore/runtime/JSGlobalData.cpp
Source/JavaScriptCore/runtime/JSGlobalData.h
Source/JavaScriptCore/runtime/JSObject.cpp
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/JSWrapperObject.h
Source/JavaScriptCore/runtime/StringPrototype.cpp
Source/JavaScriptCore/runtime/StringPrototype.h

index 24e02d9..1ffa4e3 100644 (file)
@@ -1,3 +1,87 @@
+2013-03-18  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG string conversions and allocations should be inlined
+        https://bugs.webkit.org/show_bug.cgi?id=112376
+
+        Reviewed by Geoffrey Garen.
+
+        * fast/js/dfg-to-string-bad-toString-expected.txt: Added.
+        * fast/js/dfg-to-string-bad-toString.html: Added.
+        * fast/js/dfg-to-string-bad-valueOf-expected.txt: Added.
+        * fast/js/dfg-to-string-bad-valueOf.html: Added.
+        * fast/js/dfg-to-string-int-expected.txt: Added.
+        * fast/js/dfg-to-string-int-or-string-expected.txt: Added.
+        * fast/js/dfg-to-string-int-or-string.html: Added.
+        * fast/js/dfg-to-string-int.html: Added.
+        * fast/js/dfg-to-string-side-effect-clobbers-toString-expected.txt: Added.
+        * fast/js/dfg-to-string-side-effect-clobbers-toString.html: Added.
+        * fast/js/dfg-to-string-side-effect-expected.txt: Added.
+        * fast/js/dfg-to-string-side-effect.html: Added.
+        * fast/js/dfg-to-string-toString-becomes-bad-expected.txt: Added.
+        * fast/js/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype-expected.txt: Added.
+        * fast/js/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype.html: Added.
+        * fast/js/dfg-to-string-toString-becomes-bad.html: Added.
+        * fast/js/dfg-to-string-toString-in-string-expected.txt: Added.
+        * fast/js/dfg-to-string-toString-in-string.html: Added.
+        * fast/js/dfg-to-string-valueOf-becomes-bad-expected.txt: Added.
+        * fast/js/dfg-to-string-valueOf-becomes-bad.html: Added.
+        * fast/js/dfg-to-string-valueOf-in-string-expected.txt: Added.
+        * fast/js/dfg-to-string-valueOf-in-string.html: Added.
+        * fast/js/jsc-test-list:
+        * fast/js/regress/script-tests/string-concat-object.js: Added.
+        (foo):
+        * fast/js/regress/script-tests/string-concat-pair-object.js: Added.
+        (foo):
+        * fast/js/regress/script-tests/string-concat-pair-simple.js: Added.
+        (foo):
+        * fast/js/regress/script-tests/string-concat-simple.js: Added.
+        (foo):
+        * fast/js/regress/script-tests/string-cons-repeat.js: Added.
+        (foo):
+        * fast/js/regress/script-tests/string-cons-tower.js: Added.
+        (foo):
+        * fast/js/regress/string-concat-object-expected.txt: Added.
+        * fast/js/regress/string-concat-object.html: Added.
+        * fast/js/regress/string-concat-pair-object-expected.txt: Added.
+        * fast/js/regress/string-concat-pair-object.html: Added.
+        * fast/js/regress/string-concat-pair-simple-expected.txt: Added.
+        * fast/js/regress/string-concat-pair-simple.html: Added.
+        * fast/js/regress/string-concat-simple-expected.txt: Added.
+        * fast/js/regress/string-concat-simple.html: Added.
+        * fast/js/regress/string-cons-repeat-expected.txt: Added.
+        * fast/js/regress/string-cons-repeat.html: Added.
+        * fast/js/regress/string-cons-tower-expected.txt: Added.
+        * fast/js/regress/string-cons-tower.html: Added.
+        * fast/js/script-tests/dfg-to-string-bad-toString.js: Added.
+        (String.prototype.toString):
+        (foo):
+        * fast/js/script-tests/dfg-to-string-bad-valueOf.js: Added.
+        (String.prototype.valueOf):
+        (foo):
+        * fast/js/script-tests/dfg-to-string-int-or-string.js: Added.
+        (foo):
+        * fast/js/script-tests/dfg-to-string-int.js: Added.
+        (foo):
+        * fast/js/script-tests/dfg-to-string-side-effect-clobbers-toString.js: Added.
+        (foo):
+        * fast/js/script-tests/dfg-to-string-side-effect.js: Added.
+        (foo):
+        * fast/js/script-tests/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype.js: Added.
+        (foo):
+        (.String.prototype.toString):
+        * fast/js/script-tests/dfg-to-string-toString-becomes-bad.js: Added.
+        (foo):
+        (.String.prototype.toString):
+        * fast/js/script-tests/dfg-to-string-toString-in-string.js: Added.
+        (foo):
+        (.argument.toString):
+        * fast/js/script-tests/dfg-to-string-valueOf-becomes-bad.js: Added.
+        (foo):
+        (.String.prototype.valueOf):
+        * fast/js/script-tests/dfg-to-string-valueOf-in-string.js: Added.
+        (foo):
+        (.argument.valueOf):
+
 2013-03-18  Dean Jackson  <dino@apple.com>
 
         Only add wordspacing when kerning to actual word ends
diff --git a/LayoutTests/fast/js/dfg-to-string-bad-toString-expected.txt b/LayoutTests/fast/js/dfg-to-string-bad-toString-expected.txt
new file mode 100644 (file)
index 0000000..83f7ff6
--- /dev/null
@@ -0,0 +1,109 @@
+Tests that we do ToString conversions correctly when String.prototype.valueOf is not what we wanted.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-to-string-bad-toString.html b/LayoutTests/fast/js/dfg-to-string-bad-toString.html
new file mode 100644 (file)
index 0000000..f5d1f02
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-to-string-bad-toString.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/dfg-to-string-bad-valueOf-expected.txt b/LayoutTests/fast/js/dfg-to-string-bad-valueOf-expected.txt
new file mode 100644 (file)
index 0000000..83f7ff6
--- /dev/null
@@ -0,0 +1,109 @@
+Tests that we do ToString conversions correctly when String.prototype.valueOf is not what we wanted.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-to-string-bad-valueOf.html b/LayoutTests/fast/js/dfg-to-string-bad-valueOf.html
new file mode 100644 (file)
index 0000000..cb05084
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-to-string-bad-valueOf.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/dfg-to-string-int-expected.txt b/LayoutTests/fast/js/dfg-to-string-int-expected.txt
new file mode 100644 (file)
index 0000000..01b38c4
--- /dev/null
@@ -0,0 +1,109 @@
+Tests that we do ToString conversions correctly when String.prototype.valueOf is not what we wanted.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS "" + foo(42) is "42"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-to-string-int-or-string-expected.txt b/LayoutTests/fast/js/dfg-to-string-int-or-string-expected.txt
new file mode 100644 (file)
index 0000000..bceb787
--- /dev/null
@@ -0,0 +1,1009 @@
+Tests that we do ToString conversions correctly when String.prototype.valueOf is not what we wanted.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS "" + foo(i % 2 ? 42 : "hello") is i % 2 ? "42" : "hello"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-to-string-int-or-string.html b/LayoutTests/fast/js/dfg-to-string-int-or-string.html
new file mode 100644 (file)
index 0000000..fcfb0e2
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-to-string-int-or-string.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/dfg-to-string-int.html b/LayoutTests/fast/js/dfg-to-string-int.html
new file mode 100644 (file)
index 0000000..06eb90c
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-to-string-int.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/dfg-to-string-side-effect-clobbers-toString-expected.txt b/LayoutTests/fast/js/dfg-to-string-side-effect-clobbers-toString-expected.txt
new file mode 100644 (file)
index 0000000..a44bb5f
--- /dev/null
@@ -0,0 +1,259 @@
+Tests what happens when you do ToString twice, and it has a side effect that clobbers the toString method in between the two ToStrings.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+PASS foo(new String("hello"), sideEffect) is "hellohello"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello150"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello151"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello152"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello153"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello154"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello155"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello156"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello157"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello158"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello159"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello160"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello161"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello162"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello163"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello164"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello165"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello166"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello167"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello168"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello169"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello170"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello171"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello172"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello173"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello174"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello175"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello176"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello177"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello178"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello179"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello180"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello181"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello182"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello183"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello184"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello185"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello186"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello187"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello188"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello189"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello190"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello191"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello192"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello193"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello194"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello195"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello196"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello197"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello198"
+hi!
+PASS foo(new String("hello"), sideEffect) is "hello199"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-to-string-side-effect-clobbers-toString.html b/LayoutTests/fast/js/dfg-to-string-side-effect-clobbers-toString.html
new file mode 100644 (file)
index 0000000..ac8844c
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-to-string-side-effect-clobbers-toString.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/dfg-to-string-side-effect-expected.txt b/LayoutTests/fast/js/dfg-to-string-side-effect-expected.txt
new file mode 100644 (file)
index 0000000..2857a29
--- /dev/null
@@ -0,0 +1,209 @@
+Tests that we do ToString conversions correctly when String.prototype.valueOf is not what we wanted.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+hello
+PASS "" + foo({toString:function() { debug("hello"); return 42; }}) is "42"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-to-string-side-effect.html b/LayoutTests/fast/js/dfg-to-string-side-effect.html
new file mode 100644 (file)
index 0000000..e393e73
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-to-string-side-effect.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/dfg-to-string-toString-becomes-bad-expected.txt b/LayoutTests/fast/js/dfg-to-string-toString-becomes-bad-expected.txt
new file mode 100644 (file)
index 0000000..4f0adc2
--- /dev/null
@@ -0,0 +1,159 @@
+Tests that we do ToString conversions correctly when String.prototype.valueOf is initially fine but then gets clobbered.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype-expected.txt b/LayoutTests/fast/js/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype-expected.txt
new file mode 100644 (file)
index 0000000..ff87307
--- /dev/null
@@ -0,0 +1,159 @@
+Tests that we do ToString conversions correctly when String.prototype.valueOf is initially fine but then gets clobbered, and was a dictionary all along.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype.html b/LayoutTests/fast/js/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype.html
new file mode 100644 (file)
index 0000000..71c87ca
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/dfg-to-string-toString-becomes-bad.html b/LayoutTests/fast/js/dfg-to-string-toString-becomes-bad.html
new file mode 100644 (file)
index 0000000..eb86dee
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-to-string-toString-becomes-bad.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/dfg-to-string-toString-in-string-expected.txt b/LayoutTests/fast/js/dfg-to-string-toString-in-string-expected.txt
new file mode 100644 (file)
index 0000000..b9a89d4
--- /dev/null
@@ -0,0 +1,159 @@
+Tests that we do ToString conversions correctly when String.prototype.valueOf is fine but we define our own on the String object itself.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS "" + foo(argument) is "42"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-to-string-toString-in-string.html b/LayoutTests/fast/js/dfg-to-string-toString-in-string.html
new file mode 100644 (file)
index 0000000..f36f024
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-to-string-toString-in-string.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/dfg-to-string-valueOf-becomes-bad-expected.txt b/LayoutTests/fast/js/dfg-to-string-valueOf-becomes-bad-expected.txt
new file mode 100644 (file)
index 0000000..4f0adc2
--- /dev/null
@@ -0,0 +1,159 @@
+Tests that we do ToString conversions correctly when String.prototype.valueOf is initially fine but then gets clobbered.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "hello"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS "" + foo("hello") is "42"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-to-string-valueOf-becomes-bad.html b/LayoutTests/fast/js/dfg-to-string-valueOf-becomes-bad.html
new file mode 100644 (file)
index 0000000..be67574
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-to-string-valueOf-becomes-bad.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/dfg-to-string-valueOf-in-string-expected.txt b/LayoutTests/fast/js/dfg-to-string-valueOf-in-string-expected.txt
new file mode 100644 (file)
index 0000000..307dd7b
--- /dev/null
@@ -0,0 +1,159 @@
+Tests that we do ToString conversions correctly when String.prototype.valueOf is fine but we define our own on the String object itself.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS "" + foo(argument) is "hello"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/dfg-to-string-valueOf-in-string.html b/LayoutTests/fast/js/dfg-to-string-valueOf-in-string.html
new file mode 100644 (file)
index 0000000..7e60263
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/dfg-to-string-valueOf-in-string.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
index cec65a6..adce18c 100644 (file)
@@ -194,6 +194,17 @@ fast/js/dfg-side-effect-assignment-osr-exit
 fast/js/dfg-sqrt-backwards-propagation
 fast/js/dfg-string-stricteq
 fast/js/dfg-tear-off-arguments-not-activation
+fast/js/dfg-to-string-bad-toString
+fast/js/dfg-to-string-bad-valueOf
+fast/js/dfg-to-string-int-or-string
+fast/js/dfg-to-string-int
+fast/js/dfg-to-string-side-effect
+fast/js/dfg-to-string-side-effect-clobbers-toString
+fast/js/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype
+fast/js/dfg-to-string-toString-becomes-bad
+fast/js/dfg-to-string-toString-in-string
+fast/js/dfg-to-string-valueOf-becomes-bad
+fast/js/dfg-to-string-valueOf-in-string
 fast/js/dfg-uint16array
 fast/js/dfg-uint32-to-number-in-middle-of-copy-propagation
 fast/js/dfg-uint32-to-number-on-captured-variable
diff --git a/LayoutTests/fast/js/regress/script-tests/string-concat-object.js b/LayoutTests/fast/js/regress/script-tests/string-concat-object.js
new file mode 100644 (file)
index 0000000..7243c41
--- /dev/null
@@ -0,0 +1,10 @@
+function foo(a) {
+    return "foo" + new String(a) + "bar";
+}
+
+var result;
+for (var i = 0; i < 100000; ++i)
+    result = foo("hello");
+
+if (result != "foohellobar")
+    throw "Error: bad result: " + result;
diff --git a/LayoutTests/fast/js/regress/script-tests/string-concat-pair-object.js b/LayoutTests/fast/js/regress/script-tests/string-concat-pair-object.js
new file mode 100644 (file)
index 0000000..efc53c2
--- /dev/null
@@ -0,0 +1,10 @@
+function foo(a) {
+    return "foo" + new String(a);
+}
+
+var result;
+for (var i = 0; i < 100000; ++i)
+    result = foo("hello");
+
+if (result != "foohello")
+    throw "Error: bad result: " + result;
diff --git a/LayoutTests/fast/js/regress/script-tests/string-concat-pair-simple.js b/LayoutTests/fast/js/regress/script-tests/string-concat-pair-simple.js
new file mode 100644 (file)
index 0000000..731d46b
--- /dev/null
@@ -0,0 +1,10 @@
+function foo(a) {
+    return "foo" + a;
+}
+
+var result;
+for (var i = 0; i < 1000000; ++i)
+    result = foo("hello");
+
+if (result != "foohello")
+    throw "Error: bad result: " + result;
diff --git a/LayoutTests/fast/js/regress/script-tests/string-concat-simple.js b/LayoutTests/fast/js/regress/script-tests/string-concat-simple.js
new file mode 100644 (file)
index 0000000..6f662dc
--- /dev/null
@@ -0,0 +1,10 @@
+function foo(a) {
+    return "foo" + a + "bar";
+}
+
+var result;
+for (var i = 0; i < 1000000; ++i)
+    result = foo("hello");
+
+if (result != "foohellobar")
+    throw "Error: bad result: " + result;
diff --git a/LayoutTests/fast/js/regress/script-tests/string-cons-repeat.js b/LayoutTests/fast/js/regress/script-tests/string-cons-repeat.js
new file mode 100644 (file)
index 0000000..7251a2e
--- /dev/null
@@ -0,0 +1,10 @@
+function foo(a) {
+    return new String(a);
+}
+
+var result;
+for (var i = 0; i < 1000000; ++i)
+    result = foo("hello");
+
+if (result != "hello")
+    throw new "Error: bad result: " + result;
diff --git a/LayoutTests/fast/js/regress/script-tests/string-cons-tower.js b/LayoutTests/fast/js/regress/script-tests/string-cons-tower.js
new file mode 100644 (file)
index 0000000..fe6832e
--- /dev/null
@@ -0,0 +1,12 @@
+function foo(a) {
+    for (var i = 0; i < 100; ++i)
+        a = new String(a);
+    return a;
+}
+
+var result;
+for (var i = 0; i < 10000; ++i)
+    result = foo("hello");
+
+if (result != "hello")
+    throw new "Error: bad result: " + result;
diff --git a/LayoutTests/fast/js/regress/string-concat-object-expected.txt b/LayoutTests/fast/js/regress/string-concat-object-expected.txt
new file mode 100644 (file)
index 0000000..d3ea923
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/string-concat-object
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/regress/string-concat-object.html b/LayoutTests/fast/js/regress/string-concat-object.html
new file mode 100644 (file)
index 0000000..7bcfcf7
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/string-concat-object.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/regress/string-concat-pair-object-expected.txt b/LayoutTests/fast/js/regress/string-concat-pair-object-expected.txt
new file mode 100644 (file)
index 0000000..0dcd1da
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/string-concat-pair-object
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/regress/string-concat-pair-object.html b/LayoutTests/fast/js/regress/string-concat-pair-object.html
new file mode 100644 (file)
index 0000000..1bb965b
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/string-concat-pair-object.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/regress/string-concat-pair-simple-expected.txt b/LayoutTests/fast/js/regress/string-concat-pair-simple-expected.txt
new file mode 100644 (file)
index 0000000..e99a985
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/string-concat-pair-simple
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/regress/string-concat-pair-simple.html b/LayoutTests/fast/js/regress/string-concat-pair-simple.html
new file mode 100644 (file)
index 0000000..b9ec152
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/string-concat-pair-simple.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/regress/string-concat-simple-expected.txt b/LayoutTests/fast/js/regress/string-concat-simple-expected.txt
new file mode 100644 (file)
index 0000000..60f2ab5
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/string-concat-simple
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/regress/string-concat-simple.html b/LayoutTests/fast/js/regress/string-concat-simple.html
new file mode 100644 (file)
index 0000000..baa964f
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/string-concat-simple.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/regress/string-cons-repeat-expected.txt b/LayoutTests/fast/js/regress/string-cons-repeat-expected.txt
new file mode 100644 (file)
index 0000000..498fdf1
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/string-cons-repeat
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/regress/string-cons-repeat.html b/LayoutTests/fast/js/regress/string-cons-repeat.html
new file mode 100644 (file)
index 0000000..f069021
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/string-cons-repeat.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/regress/string-cons-tower-expected.txt b/LayoutTests/fast/js/regress/string-cons-tower-expected.txt
new file mode 100644 (file)
index 0000000..c339c79
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/string-cons-tower
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/regress/string-cons-tower.html b/LayoutTests/fast/js/regress/string-cons-tower.html
new file mode 100644 (file)
index 0000000..38e23b8
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/string-cons-tower.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/script-tests/dfg-to-string-bad-toString.js b/LayoutTests/fast/js/script-tests/dfg-to-string-bad-toString.js
new file mode 100644 (file)
index 0000000..cd81762
--- /dev/null
@@ -0,0 +1,14 @@
+description(
+"Tests that we do ToString conversions correctly when String.prototype.valueOf is not what we wanted."
+);
+
+String.prototype.toString = function() { return 42; }
+
+function foo(a) {
+    for (var i = 0; i < 100; ++i)
+        a = new String(a);
+    return a;
+}
+
+for (var i = 0; i < 100; ++i)
+    shouldBe("\"\" + foo(\"hello\")", "\"42\"");
diff --git a/LayoutTests/fast/js/script-tests/dfg-to-string-bad-valueOf.js b/LayoutTests/fast/js/script-tests/dfg-to-string-bad-valueOf.js
new file mode 100644 (file)
index 0000000..484e591
--- /dev/null
@@ -0,0 +1,14 @@
+description(
+"Tests that we do ToString conversions correctly when String.prototype.valueOf is not what we wanted."
+);
+
+String.prototype.valueOf = function() { return 42; }
+
+function foo(a) {
+    for (var i = 0; i < 100; ++i)
+        a = new String(a);
+    return a;
+}
+
+for (var i = 0; i < 100; ++i)
+    shouldBe("\"\" + foo(\"hello\")", "\"42\"");
diff --git a/LayoutTests/fast/js/script-tests/dfg-to-string-int-or-string.js b/LayoutTests/fast/js/script-tests/dfg-to-string-int-or-string.js
new file mode 100644 (file)
index 0000000..163c2bb
--- /dev/null
@@ -0,0 +1,12 @@
+description(
+"Tests that we do ToString conversions correctly when String.prototype.valueOf is not what we wanted."
+);
+
+function foo(a) {
+    for (var i = 0; i < 100; ++i)
+        a = new String(a);
+    return a;
+}
+
+for (var i = 0; i < 1000; ++i)
+    shouldBe("\"\" + foo(i % 2 ? 42 : \"hello\")", "i % 2 ? \"42\" : \"hello\"");
diff --git a/LayoutTests/fast/js/script-tests/dfg-to-string-int.js b/LayoutTests/fast/js/script-tests/dfg-to-string-int.js
new file mode 100644 (file)
index 0000000..ecc53bb
--- /dev/null
@@ -0,0 +1,12 @@
+description(
+"Tests that we do ToString conversions correctly when String.prototype.valueOf is not what we wanted."
+);
+
+function foo(a) {
+    for (var i = 0; i < 100; ++i)
+        a = new String(a);
+    return a;
+}
+
+for (var i = 0; i < 100; ++i)
+    shouldBe("\"\" + foo(42)", "\"42\"");
diff --git a/LayoutTests/fast/js/script-tests/dfg-to-string-side-effect-clobbers-toString.js b/LayoutTests/fast/js/script-tests/dfg-to-string-side-effect-clobbers-toString.js
new file mode 100644 (file)
index 0000000..4d46a31
--- /dev/null
@@ -0,0 +1,17 @@
+description(
+"Tests what happens when you do ToString twice, and it has a side effect that clobbers the toString method in between the two ToStrings."
+);
+
+function foo(s, sideEffect) {
+    var a = String(s);
+    sideEffect(s);
+    var b = String(s);
+    return a + b;
+}
+
+var count = 0;
+for (var i = 0; i < 200; ++i) {
+    var code = "(function(s) { " + (i < 150 ? "return " + i + ";" : "count++; debug(\"hi!\"); s.toString = function() { return " + i + "; };") + " })";
+    var sideEffect = eval(code);
+    shouldBe("foo(new String(\"hello\"), sideEffect)", i < 150 ? "\"hellohello\"" : "\"hello" + i + "\"");
+}
diff --git a/LayoutTests/fast/js/script-tests/dfg-to-string-side-effect.js b/LayoutTests/fast/js/script-tests/dfg-to-string-side-effect.js
new file mode 100644 (file)
index 0000000..e881011
--- /dev/null
@@ -0,0 +1,12 @@
+description(
+"Tests that we do ToString conversions correctly when String.prototype.valueOf is not what we wanted."
+);
+
+function foo(a) {
+    for (var i = 0; i < 100; ++i)
+        a = new String(a);
+    return a;
+}
+
+for (var i = 0; i < 100; ++i)
+    shouldBe("\"\" + foo({toString:function() { debug(\"hello\"); return 42; }})", "\"42\"");
diff --git a/LayoutTests/fast/js/script-tests/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype.js b/LayoutTests/fast/js/script-tests/dfg-to-string-toString-becomes-bad-with-dictionary-string-prototype.js
new file mode 100644 (file)
index 0000000..9ceee2d
--- /dev/null
@@ -0,0 +1,26 @@
+description(
+"Tests that we do ToString conversions correctly when String.prototype.valueOf is initially fine but then gets clobbered, and was a dictionary all along."
+);
+
+delete String.prototype.trim;
+delete String.prototype.toLowerCase;
+delete String.prototype.toLocaleUpperCase;
+
+for (var i = 0; i < 1000; ++i)
+    String.prototype["a" + i] = 42;
+
+function foo(a) {
+    for (var i = 0; i < 100; ++i)
+        a = new String(a);
+    return a;
+}
+
+var expected = "\"hello\"";
+for (var i = 0; i < 150; ++i) {
+    if (i == 100) {
+        String.prototype.toString = function() { return 42; }
+        expected = "\"42\"";
+    }
+    shouldBe("\"\" + foo(\"hello\")", expected);
+}
+
diff --git a/LayoutTests/fast/js/script-tests/dfg-to-string-toString-becomes-bad.js b/LayoutTests/fast/js/script-tests/dfg-to-string-toString-becomes-bad.js
new file mode 100644 (file)
index 0000000..2bad025
--- /dev/null
@@ -0,0 +1,19 @@
+description(
+"Tests that we do ToString conversions correctly when String.prototype.valueOf is initially fine but then gets clobbered."
+);
+
+function foo(a) {
+    for (var i = 0; i < 100; ++i)
+        a = new String(a);
+    return a;
+}
+
+var expected = "\"hello\"";
+for (var i = 0; i < 150; ++i) {
+    if (i == 100) {
+        String.prototype.toString = function() { return 42; }
+        expected = "\"42\"";
+    }
+    shouldBe("\"\" + foo(\"hello\")", expected);
+}
+
diff --git a/LayoutTests/fast/js/script-tests/dfg-to-string-toString-in-string.js b/LayoutTests/fast/js/script-tests/dfg-to-string-toString-in-string.js
new file mode 100644 (file)
index 0000000..be69a89
--- /dev/null
@@ -0,0 +1,21 @@
+description(
+"Tests that we do ToString conversions correctly when String.prototype.valueOf is fine but we define our own on the String object itself."
+);
+
+function foo(a) {
+    for (var i = 0; i < 100; ++i)
+        a = new String(a);
+    return a;
+}
+
+var argument = new String("hello");
+var expected = "\"hello\"";
+for (var i = 0; i < 150; ++i) {
+    if (i == 100) {
+        argument = new String("hello");
+        argument.toString = function() { return 42; }
+        expected = "\"42\"";
+    }
+    shouldBe("\"\" + foo(argument)", expected);
+}
+
diff --git a/LayoutTests/fast/js/script-tests/dfg-to-string-valueOf-becomes-bad.js b/LayoutTests/fast/js/script-tests/dfg-to-string-valueOf-becomes-bad.js
new file mode 100644 (file)
index 0000000..594e142
--- /dev/null
@@ -0,0 +1,19 @@
+description(
+"Tests that we do ToString conversions correctly when String.prototype.valueOf is initially fine but then gets clobbered."
+);
+
+function foo(a) {
+    for (var i = 0; i < 100; ++i)
+        a = new String(a);
+    return a;
+}
+
+var expected = "\"hello\"";
+for (var i = 0; i < 150; ++i) {
+    if (i == 100) {
+        String.prototype.valueOf = function() { return 42; }
+        expected = "\"42\"";
+    }
+    shouldBe("\"\" + foo(\"hello\")", expected);
+}
+
diff --git a/LayoutTests/fast/js/script-tests/dfg-to-string-valueOf-in-string.js b/LayoutTests/fast/js/script-tests/dfg-to-string-valueOf-in-string.js
new file mode 100644 (file)
index 0000000..ce06960
--- /dev/null
@@ -0,0 +1,19 @@
+description(
+"Tests that we do ToString conversions correctly when String.prototype.valueOf is fine but we define our own on the String object itself."
+);
+
+function foo(a) {
+    for (var i = 0; i < 100; ++i)
+        a = new String(a);
+    return a;
+}
+
+var argument = new String("hello");
+for (var i = 0; i < 150; ++i) {
+    if (i == 100) {
+        argument = new String("hello");
+        argument.valueOf = function() { return 42; }
+    }
+    shouldBe("\"\" + foo(argument)", "\"hello\"");
+}
+
index 8b3b66f..7805d66 100644 (file)
@@ -333,7 +333,6 @@ set(JavaScriptCore_LUT_FILES
     runtime/RegExpObject.cpp
     runtime/RegExpPrototype.cpp
     runtime/StringConstructor.cpp
-    runtime/StringPrototype.cpp
 )
 
 set(JavaScriptCore_LIBRARIES
index 5040431..da3702b 100644 (file)
@@ -1,3 +1,139 @@
+2013-03-15  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG string conversions and allocations should be inlined
+        https://bugs.webkit.org/show_bug.cgi?id=112376
+
+        Reviewed by Geoffrey Garen.
+        
+        This turns new String(), String(), String.prototype.valueOf(), and
+        String.prototype.toString() into intrinsics. It gives the DFG the ability to handle
+        conversions from StringObject to JSString and vice-versa, and also gives it the
+        ability to handle cases where a variable may be either a StringObject or a JSString.
+        To do this, I added StringObject to value profiling (and removed the stale
+        distinction between Myarguments and Foreignarguments). I also cleaned up ToPrimitive
+        handling, using some of the new functionality but also taking advantage of the
+        existence of Identity(String:@a).
+        
+        This is a 2% SunSpider speed-up. Also there are some speed-ups on V8v7 and Kraken.
+        On microbenchmarks that stress new String() this is a 14x speed-up.
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * DerivedSources.pri:
+        * GNUmakefile.list.am:
+        * bytecode/CodeBlock.h:
+        (CodeBlock):
+        (JSC::CodeBlock::hasExitSite):
+        (JSC):
+        * bytecode/DFGExitProfile.cpp:
+        (JSC::DFG::ExitProfile::hasExitSite):
+        (DFG):
+        * bytecode/DFGExitProfile.h:
+        (ExitProfile):
+        (JSC::DFG::ExitProfile::hasExitSite):
+        * bytecode/ExitKind.cpp:
+        (JSC::exitKindToString):
+        * bytecode/ExitKind.h:
+        * bytecode/SpeculatedType.cpp:
+        (JSC::dumpSpeculation):
+        (JSC::speculationToAbbreviatedString):
+        (JSC::speculationFromClassInfo):
+        * bytecode/SpeculatedType.h:
+        (JSC):
+        (JSC::isStringObjectSpeculation):
+        (JSC::isStringOrStringObjectSpeculation):
+        * create_hash_table:
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::executeEffects):
+        * dfg/DFGAbstractState.h:
+        (JSC::DFG::AbstractState::filterEdgeByUse):
+        * dfg/DFGByteCodeParser.cpp:
+        (ByteCodeParser):
+        (JSC::DFG::ByteCodeParser::handleCall):
+        (JSC::DFG::ByteCodeParser::emitArgumentPhantoms):
+        (DFG):
+        (JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::CSEPhase::putStructureStoreElimination):
+        * dfg/DFGEdge.h:
+        (JSC::DFG::Edge::shift):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::isStringPrototypeMethodSane):
+        (FixupPhase):
+        (JSC::DFG::FixupPhase::canOptimizeStringObjectAccess):
+        (JSC::DFG::FixupPhase::observeUseKindOnNode):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::hasGlobalExitSite):
+        (Graph):
+        (JSC::DFG::Graph::hasExitSite):
+        (JSC::DFG::Graph::clobbersWorld):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::convertToToString):
+        (Node):
+        (JSC::DFG::Node::hasStructure):
+        (JSC::DFG::Node::shouldSpeculateStringObject):
+        (JSC::DFG::Node::shouldSpeculateStringOrStringObject):
+        * dfg/DFGNodeType.h:
+        (DFG):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileToStringOnCell):
+        (DFG):
+        (JSC::DFG::SpeculativeJIT::compileNewStringObject):
+        (JSC::DFG::SpeculativeJIT::speculateObject):
+        (JSC::DFG::SpeculativeJIT::speculateObjectOrOther):
+        (JSC::DFG::SpeculativeJIT::speculateString):
+        (JSC::DFG::SpeculativeJIT::speculateStringObject):
+        (JSC::DFG::SpeculativeJIT::speculateStringOrStringObject):
+        (JSC::DFG::SpeculativeJIT::speculate):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        (SpeculativeJIT):
+        (JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
+        (DFG):
+        (JSC::DFG::SpeculativeJIT::speculateStringObjectForStructure):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::fillSpeculateCell):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::fillSpeculateCell):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGUseKind.cpp:
+        (WTF::printInternal):
+        * dfg/DFGUseKind.h:
+        (JSC::DFG::typeFilterFor):
+        * interpreter/CallFrame.h:
+        (JSC::ExecState::regExpPrototypeTable):
+        * runtime/CommonIdentifiers.h:
+        * runtime/Intrinsic.h:
+        * runtime/JSDestructibleObject.h:
+        (JSDestructibleObject):
+        (JSC::JSDestructibleObject::classInfoOffset):
+        * runtime/JSGlobalData.cpp:
+        (JSC):
+        (JSC::JSGlobalData::JSGlobalData):
+        (JSC::JSGlobalData::~JSGlobalData):
+        * runtime/JSGlobalData.h:
+        (JSGlobalData):
+        * runtime/JSObject.cpp:
+        * runtime/JSObject.h:
+        (JSC):
+        * runtime/JSWrapperObject.h:
+        (JSC::JSWrapperObject::allocationSize):
+        (JSWrapperObject):
+        (JSC::JSWrapperObject::internalValueOffset):
+        (JSC::JSWrapperObject::internalValueCellOffset):
+        * runtime/StringPrototype.cpp:
+        (JSC):
+        (JSC::StringPrototype::finishCreation):
+        (JSC::StringPrototype::create):
+        * runtime/StringPrototype.h:
+        (StringPrototype):
+
 2013-03-18  Filip Pizlo  <fpizlo@apple.com>
 
         ObjectPrototype properties should be eagerly created rather than lazily via static tables
index 55a76e2..517063d 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
+# Copyright (C) 2006, 2007, 2008, 2009, 2011, 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
@@ -55,7 +55,6 @@ all : \
     RegExpJitTables.h \
     RegExpObject.lut.h \
     StringConstructor.lut.h \
-    StringPrototype.lut.h \
     docs/bytecode.html \
     udis86_itab.h \
 #
index d637569..c27c15f 100644 (file)
@@ -24,7 +24,6 @@ LUT_FILES += \
     runtime/RegExpObject.cpp \
     runtime/RegExpPrototype.cpp \
     runtime/StringConstructor.cpp \
-    runtime/StringPrototype.cpp \
 
 KEYWORDLUT_FILES += \
     parser/Keywords.table
index f418387..14117fc 100644 (file)
@@ -28,7 +28,6 @@ javascriptcore_built_nosources += \
        DerivedSources/JavaScriptCore/RegExpObject.lut.h \
        DerivedSources/JavaScriptCore/RegExpPrototype.lut.h \
        DerivedSources/JavaScriptCore/StringConstructor.lut.h \
-       DerivedSources/JavaScriptCore/StringPrototype.lut.h \
        DerivedSources/JavaScriptCore/LLIntDesiredOffsets.h \
        DerivedSources/JavaScriptCore/LLIntAssembly.h
 
index f5f5312..1c7c58a 100644 (file)
@@ -787,6 +787,8 @@ namespace JSC {
             ASSERT(JITCode::isBaselineCode(getJITType()));
             return m_exitProfile.add(site);
         }
+        
+        bool hasExitSite(const DFG::FrequentExitSite& site) const { return m_exitProfile.hasExitSite(site); }
 
         DFG::ExitProfile& exitProfile() { return m_exitProfile; }
         
@@ -1389,7 +1391,7 @@ namespace JSC {
             return baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame);
         return baselineCodeBlock;
     }
-    
+
     inline int CodeBlock::argumentIndexAfterCapture(size_t argument)
     {
         if (argument >= static_cast<size_t>(symbolTable()->parameterCount()))
index 9f7e901..d36878f 100644 (file)
@@ -70,6 +70,18 @@ Vector<FrequentExitSite> ExitProfile::exitSitesFor(unsigned bytecodeIndex)
     return result;
 }
 
+bool ExitProfile::hasExitSite(const FrequentExitSite& site) const
+{
+    if (!m_frequentExitSites)
+        return false;
+    
+    for (unsigned i = m_frequentExitSites->size(); i--;) {
+        if (m_frequentExitSites->at(i) == site)
+            return true;
+    }
+    return false;
+}
+
 QueryableExitProfile::QueryableExitProfile(const ExitProfile& profile)
 {
     if (!profile.m_frequentExitSites)
index 61466f4..fe7b2f9 100644 (file)
@@ -133,6 +133,20 @@ public:
     // meant to only be used from debugging/profiling code.
     Vector<FrequentExitSite> exitSitesFor(unsigned bytecodeIndex);
     
+    // This is O(n) and should be called on less-frequently executed code paths
+    // in the compiler. It should be strictly cheaper than building a
+    // QueryableExitProfile, if you really expect this to be called infrequently
+    // and you believe that there are few exit sites.
+    bool hasExitSite(const FrequentExitSite&) const;
+    bool hasExitSite(ExitKind kind) const
+    {
+        return hasExitSite(FrequentExitSite(kind));
+    }
+    bool hasExitSite(unsigned bytecodeIndex, ExitKind kind) const
+    {
+        return hasExitSite(FrequentExitSite(bytecodeIndex, kind));
+    }
+    
 private:
     friend class QueryableExitProfile;
     
index faa6348..a8d9045 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 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
@@ -64,6 +64,8 @@ const char* exitKindToString(ExitKind kind)
         return "InadequateCoverage";
     case ArgumentsEscaped:
         return "ArgumentsEscaped";
+    case NotStringObject:
+        return "NotStringObject";
     case Uncountable:
         return "Uncountable";
     case UncountableWatchpoint:
index f28995f..8b34f4e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 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
@@ -44,6 +44,7 @@ enum ExitKind {
     StoreToHoleOrOutOfBounds, // We're simultaneously speculating that we're in bounds and not accessing a hole, and one of those things didn't pan out.
     InadequateCoverage, // We exited because we ended up in code that didn't have profiling coverage.
     ArgumentsEscaped, // We exited because arguments escaped but we didn't expect them to.
+    NotStringObject, // We exited because we shouldn't have attempted to optimize string object access.
     Uncountable, // We exited for none of the above reasons, and we should not count it. Most uses of this should be viewed as a FIXME.
     UncountableWatchpoint // We exited because of a watchpoint, which isn't counted because watchpoints do tracking themselves.
 };
index 7b78592..0e33b65 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 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
@@ -33,6 +33,7 @@
 #include "JSArray.h"
 #include "JSFunction.h"
 #include "Operations.h"
+#include "StringObject.h"
 #include "ValueProfile.h"
 #include <wtf/BoundsCheckedPointer.h>
 #include <wtf/StringPrintStream.h>
@@ -120,18 +121,18 @@ void dumpSpeculation(PrintStream& out, SpeculatedType value)
     else
         isTop = false;
     
-    if (value & SpecMyArguments)
-        myOut.print("Myarguments");
+    if (value & SpecArguments)
+        myOut.print("Arguments");
     else
         isTop = false;
     
-    if (value & SpecForeignArguments)
-        myOut.print("Foreignarguments");
+    if (value & SpecString)
+        myOut.print("String");
     else
         isTop = false;
     
-    if (value & SpecString)
-        myOut.print("String");
+    if (value & SpecStringObject)
+        myOut.print("Stringobject");
     else
         isTop = false;
     
@@ -197,10 +198,12 @@ static const char* speculationToAbbreviatedString(SpeculatedType prediction)
         return "<Float32array>";
     if (isFloat64ArraySpeculation(prediction))
         return "<Float64array>";
-    if (isMyArgumentsSpeculation(prediction))
-        return "<Myarguments>";
     if (isArgumentsSpeculation(prediction))
         return "<Arguments>";
+    if (isStringObjectSpeculation(prediction))
+        return "<StringObject>";
+    if (isStringOrStringObjectSpeculation(prediction))
+        return "<StringOrStringObject>";
     if (isObjectSpeculation(prediction))
         return "<Object>";
     if (isCellSpeculation(prediction))
@@ -232,11 +235,13 @@ SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo)
         return SpecArray;
     
     if (classInfo == &Arguments::s_info)
-        return SpecArguments; // Cannot distinguish between MyArguments and ForeignArguments at this stage. That happens in the flow analysis.
+        return SpecArguments;
+    
+    if (classInfo == &StringObject::s_info)
+        return SpecStringObject;
     
     if (classInfo->isSubClassOf(&JSFunction::s_info))
         return SpecFunction;
-
     
     if (classInfo->typedArrayStorageType != TypedArrayNone) {
         switch (classInfo->typedArrayStorageType) {
index 5854f5c..b50b7ce 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 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
@@ -49,9 +49,8 @@ static const SpeculatedType SpecUint16Array       = 0x00000200; // It's definite
 static const SpeculatedType SpecUint32Array       = 0x00000400; // It's definitely an Uint32Array or one of its subclasses.
 static const SpeculatedType SpecFloat32Array      = 0x00000800; // It's definitely an Uint16Array or one of its subclasses.
 static const SpeculatedType SpecFloat64Array      = 0x00001000; // It's definitely an Uint16Array or one of its subclasses.
-static const SpeculatedType SpecMyArguments       = 0x00002000; // It's definitely an Arguments object, and it's definitely the one for my current frame.
-static const SpeculatedType SpecForeignArguments  = 0x00004000; // It's definitely an Arguments object, and it's definitely not mine.
-static const SpeculatedType SpecArguments         = 0x00006000; // It's definitely an Arguments object.
+static const SpeculatedType SpecArguments         = 0x00002000; // It's definitely an Arguments object.
+static const SpeculatedType SpecStringObject      = 0x00004000; // It's definitely a StringObject.
 static const SpeculatedType SpecObjectOther       = 0x00008000; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
 static const SpeculatedType SpecObject            = 0x0000ffff; // Bitmask used for testing for any kind of object prediction.
 static const SpeculatedType SpecString            = 0x00010000; // It's definitely a JSString.
@@ -214,9 +213,14 @@ inline bool isArrayOrOtherSpeculation(SpeculatedType value)
     return !!(value & (SpecArray | SpecOther)) && !(value & ~(SpecArray | SpecOther));
 }
 
-inline bool isMyArgumentsSpeculation(SpeculatedType value)
+inline bool isStringObjectSpeculation(SpeculatedType value)
 {
-    return value == SpecMyArguments;
+    return value == SpecStringObject;
+}
+
+inline bool isStringOrStringObjectSpeculation(SpeculatedType value)
+{
+    return !!value && !(value & ~(SpecString | SpecStringObject));
 }
 
 inline bool isInt32Speculation(SpeculatedType value)
index cb2809d..875018c 100755 (executable)
@@ -271,8 +271,6 @@ sub output() {
         }
 
         my $intrinsic = "NoIntrinsic";
-        $intrinsic = "CharCodeAtIntrinsic" if ($key eq "charCodeAt");
-        $intrinsic = "CharAtIntrinsic" if ($key eq "charAt");
         $intrinsic = "FromCharCodeIntrinsic" if ($key eq "fromCharCode");
         if ($name eq "mathTable") {
             $intrinsic = "MinIntrinsic" if ($key eq "min");
index a9e718c..74358ac 100644 (file)
@@ -33,6 +33,7 @@
 #include "GetByIdStatus.h"
 #include "Operations.h"
 #include "PutByIdStatus.h"
+#include "StringObject.h"
 
 namespace JSC { namespace DFG {
 
@@ -769,7 +770,7 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
             RELEASE_ASSERT_NOT_REACHED();
             break;
         }
-        forNode(node).set(SpecString);
+        forNode(node).set(m_graph.m_globalData.stringStructure.get());
         break;
     }
             
@@ -857,7 +858,7 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
         
     case StringCharAt:
         node->setCanExit(true);
-        forNode(node).set(SpecString);
+        forNode(node).set(m_graph.m_globalData.stringStructure.get());
         break;
             
     case GetByVal: {
@@ -876,7 +877,7 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
             forNode(node).makeTop();
             break;
         case Array::String:
-            forNode(node).set(SpecString);
+            forNode(node).set(m_graph.m_globalData.stringStructure.get());
             break;
         case Array::Arguments:
             forNode(node).makeTop();
@@ -1031,11 +1032,8 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
             break;
         }
         
-        if (node->child1().useKind() == Int32Use) {
-            forNode(node).set(SpecInt32);
-            break;
-        }
-
+        ASSERT(node->child1().useKind() == UntypedUse);
+        
         AbstractValue& source = forNode(node->child1());
         AbstractValue& destination = forNode(node);
         
@@ -1060,6 +1058,8 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
         // ToPrimitive will currently forget string constants. But that's not a big
         // deal since we don't do any optimization on those currently.
         
+        clobberWorld(node->codeOrigin, indexInBlock);
+        
         SpeculatedType type = source.m_type;
         if (type & ~(SpecNumber | SpecString | SpecBoolean)) {
             type &= (SpecNumber | SpecString | SpecBoolean);
@@ -1068,9 +1068,38 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node)
         destination.set(type);
         break;
     }
+        
+    case ToString: {
+        switch (node->child1().useKind()) {
+        case StringObjectUse:
+            // This also filters that the StringObject has the primordial StringObject
+            // structure.
+            forNode(node->child1()).filter(m_graph.globalObjectFor(node->codeOrigin)->stringObjectStructure());
+            node->setCanExit(true); // We could be more precise but it's likely not worth it.
+            break;
+        case StringOrStringObjectUse:
+            node->setCanExit(true); // We could be more precise but it's likely not worth it.
+            break;
+        case CellUse:
+        case UntypedUse:
+            clobberWorld(node->codeOrigin, indexInBlock);
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+        forNode(node).set(m_graph.m_globalData.stringStructure.get());
+        break;
+    }
+        
+    case NewStringObject: {
+        ASSERT(node->structure()->classInfo() == &StringObject::s_info);
+        forNode(node).set(node->structure());
+        break;
+    }
             
     case StrCat:
-        forNode(node).set(SpecString);
+        forNode(node).set(m_graph.m_globalData.stringStructure.get());
         break;
             
     case NewArray:
index e6334e1..de1f17d 100644 (file)
@@ -190,6 +190,7 @@ public:
         case KnownInt32Use:
         case KnownNumberUse:
         case KnownCellUse:
+        case KnownStringUse:
             ASSERT(!(forNode(edge).m_type & ~typeFilterFor(edge.useKind())));
             break;
         default:
index ab25c23..634d105 100644 (file)
@@ -39,6 +39,7 @@
 #include "PreciseJumpTargets.h"
 #include "PutByIdStatus.h"
 #include "ResolveGlobalStatus.h"
+#include "StringConstructor.h"
 #include <wtf/CommaPrinter.h>
 #include <wtf/HashMap.h>
 #include <wtf/MathExtras.h>
@@ -164,6 +165,7 @@ private:
     // Handle calls. This resolves issues surrounding inlining and intrinsics.
     void handleCall(Interpreter*, Instruction* currentInstruction, NodeType op, CodeSpecializationKind);
     void emitFunctionChecks(const CallLinkStatus&, Node* callTarget, int registerOffset, CodeSpecializationKind);
+    void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind);
     // Handle inlining. Return true if it succeeded, false if we need to plant a call.
     bool handleInlining(bool usesResult, Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind);
     // Handle setting the result of an intrinsic.
@@ -1206,9 +1208,14 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn
     }
 
     if (InternalFunction* function = callLinkStatus.internalFunction()) {
-        if (handleConstantInternalFunction(usesResult, resultOperand, function, registerOffset, argumentCountIncludingThis, prediction, kind))
+        if (handleConstantInternalFunction(usesResult, resultOperand, function, registerOffset, argumentCountIncludingThis, prediction, kind)) {
+            // This phantoming has to be *after* the code for the intrinsic, to signify that
+            // the inputs must be kept alive whatever exits the intrinsic may do.
+            addToGraph(Phantom, callTarget);
+            emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, kind);
             return;
-            
+        }
+        
         // Can only handle this using the generic call handler.
         addCall(interpreter, currentInstruction, op);
         return;
@@ -1219,14 +1226,10 @@ void ByteCodeParser::handleCall(Interpreter* interpreter, Instruction* currentIn
         emitFunctionChecks(callLinkStatus, callTarget, registerOffset, kind);
             
         if (handleIntrinsic(usesResult, resultOperand, intrinsic, registerOffset, argumentCountIncludingThis, prediction)) {
-            // Need to keep all inputs alive for OSR, and need to ensure that we get
-            // backwards propagation of NodeUsedAsValue. Note that inlining doesn't
-            // need to do this because it already Flushes the arguments, which has a
-            // similar effect.
+            // This phantoming has to be *after* the code for the intrinsic, to signify that
+            // the inputs must be kept alive whatever exits the intrinsic may do.
             addToGraph(Phantom, callTarget);
-            for (int i = 0; i < argumentCountIncludingThis; ++i)
-                addToGraph(Phantom, get(registerOffset + argumentToOperand(i)));
-            
+            emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, kind);
             return;
         }
     } else if (handleInlining(usesResult, callTarget, resultOperand, callLinkStatus, registerOffset, argumentCountIncludingThis, nextOffset, kind))
@@ -1261,6 +1264,12 @@ void ByteCodeParser::emitFunctionChecks(const CallLinkStatus& callLinkStatus, No
     }
 }
 
+void ByteCodeParser::emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind kind)
+{
+    for (int i = kind == CodeForCall ? 0 : 1; i < argumentCountIncludingThis; ++i)
+        addToGraph(Phantom, get(registerOffset + argumentToOperand(i)));
+}
+
 bool ByteCodeParser::handleInlining(bool usesResult, Node* callTargetNode, int resultOperand, const CallLinkStatus& callLinkStatus, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind kind)
 {
     // First, the really simple checks: do we have an actual JS function?
@@ -1628,7 +1637,6 @@ bool ByteCodeParser::handleConstantInternalFunction(
     // is good enough.
     
     UNUSED_PARAM(prediction); // Remove this once we do more things.
-    UNUSED_PARAM(kind); // Remove this once we do more things.
     
     if (function->classInfo() == &ArrayConstructor::s_info) {
         if (argumentCountIncludingThis == 2) {
@@ -1644,6 +1652,19 @@ bool ByteCodeParser::handleConstantInternalFunction(
             usesResult, resultOperand,
             addToGraph(Node::VarArg, NewArray, OpInfo(ArrayWithUndecided), OpInfo(0)));
         return true;
+    } else if (function->classInfo() == &StringConstructor::s_info) {
+        Node* result;
+        
+        if (argumentCountIncludingThis <= 1)
+            result = cellConstant(m_globalData->smallStrings.emptyString());
+        else
+            result = addToGraph(ToString, get(registerOffset + argumentToOperand(1)));
+        
+        if (kind == CodeForConstruct)
+            result = addToGraph(NewStringObject, OpInfo(function->globalObject()->stringObjectStructure()), result);
+        
+        setIntrinsicResult(usesResult, resultOperand, result);
+        return true;
     }
     
     return false;
index 800ef51..2b23e19 100644 (file)
@@ -576,6 +576,8 @@ private:
             case AllocatePropertyStorage:
             case ReallocatePropertyStorage:
             case TypeOf:
+            case ToString:
+            case NewStringObject:
                 return 0;
                 
             case GetIndexedPropertyStorage:
index caa3b21..eb835b0 100644 (file)
@@ -148,7 +148,7 @@ private:
     friend class AdjacencyList;
     
 #if USE(JSVALUE64)
-    static uint32_t shift() { return 5; }
+    static uint32_t shift() { return 6; }
     
     static uintptr_t makeWord(Node* node, UseKind useKind, ProofStatus proofStatus)
     {
index 4b0bbf3..6e8d922 100644 (file)
@@ -526,13 +526,69 @@ private:
         }
             
         case ToPrimitive: {
-            if (node->child1()->shouldSpeculateInteger())
+            if (node->child1()->shouldSpeculateInteger()) {
                 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
+                node->convertToIdentity();
+                break;
+            }
+            
+            if (node->child1()->shouldSpeculateString()) {
+                setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
+                node->convertToIdentity();
+                break;
+            }
+            
+            if (node->child1()->shouldSpeculateStringObject()
+                && canOptimizeStringObjectAccess(node->codeOrigin)) {
+                setUseKindAndUnboxIfProfitable<StringObjectUse>(node->child1());
+                node->convertToToString();
+                break;
+            }
+            
+            if (node->child1()->shouldSpeculateStringOrStringObject()
+                && canOptimizeStringObjectAccess(node->codeOrigin)) {
+                setUseKindAndUnboxIfProfitable<StringOrStringObjectUse>(node->child1());
+                node->convertToToString();
+                break;
+            }
+            
             // FIXME: Add string speculation here.
             // https://bugs.webkit.org/show_bug.cgi?id=110175
             break;
         }
             
+        case ToString: {
+            if (node->child1()->shouldSpeculateString()) {
+                setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
+                node->convertToIdentity();
+                break;
+            }
+            
+            if (node->child1()->shouldSpeculateStringObject()
+                && canOptimizeStringObjectAccess(node->codeOrigin)) {
+                setUseKindAndUnboxIfProfitable<StringObjectUse>(node->child1());
+                break;
+            }
+            
+            if (node->child1()->shouldSpeculateStringOrStringObject()
+                && canOptimizeStringObjectAccess(node->codeOrigin)) {
+                setUseKindAndUnboxIfProfitable<StringOrStringObjectUse>(node->child1());
+                break;
+            }
+            
+            if (node->child1()->shouldSpeculateCell()) {
+                setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
+                break;
+            }
+            
+            break;
+        }
+            
+        case NewStringObject: {
+            setUseKindAndUnboxIfProfitable<KnownStringUse>(node->child1());
+            break;
+        }
+            
         case NewArray: {
             for (unsigned i = m_graph.varArgNumChildren(node); i--;) {
                 node->setIndexingType(
@@ -806,6 +862,58 @@ private:
 #endif
     }
     
+    bool isStringPrototypeMethodSane(Structure* stringPrototypeStructure, const Identifier& ident)
+    {
+        unsigned attributesUnused;
+        JSCell* specificValue;
+        PropertyOffset offset = stringPrototypeStructure->get(
+            globalData(), ident, attributesUnused, specificValue);
+        if (!isValidOffset(offset))
+            return false;
+        
+        if (!specificValue)
+            return false;
+        
+        if (!specificValue->inherits(&JSFunction::s_info))
+            return false;
+        
+        JSFunction* function = jsCast<JSFunction*>(specificValue);
+        if (function->executable()->intrinsicFor(CodeForCall) != StringPrototypeValueOfIntrinsic)
+            return false;
+        
+        return true;
+    }
+    
+    bool canOptimizeStringObjectAccess(const CodeOrigin& codeOrigin)
+    {
+        if (m_graph.hasExitSite(codeOrigin, NotStringObject))
+            return false;
+        
+        Structure* stringObjectStructure = m_graph.globalObjectFor(codeOrigin)->stringObjectStructure();
+        ASSERT(stringObjectStructure->storedPrototype().isObject());
+        ASSERT(stringObjectStructure->storedPrototype().asCell()->classInfo() == &StringPrototype::s_info);
+        
+        JSObject* stringPrototypeObject = asObject(stringObjectStructure->storedPrototype());
+        Structure* stringPrototypeStructure = stringPrototypeObject->structure();
+        if (stringPrototypeStructure->transitionWatchpointSetHasBeenInvalidated())
+            return false;
+        
+        if (stringPrototypeStructure->isDictionary())
+            return false;
+        
+        // We're being conservative here. We want DFG's ToString on StringObject to be
+        // used in both numeric contexts (that would call valueOf()) and string contexts
+        // (that would call toString()). We don't want the DFG to have to distinguish
+        // between the two, just because that seems like it would get confusing. So we
+        // just require both methods to be sane.
+        if (!isStringPrototypeMethodSane(stringPrototypeStructure, globalData().propertyNames->valueOf))
+            return false;
+        if (!isStringPrototypeMethodSane(stringPrototypeStructure, globalData().propertyNames->toString))
+            return false;
+        
+        return true;
+    }
+    
     void fixupSetLocalsInBlock(BasicBlock* block)
     {
         if (!block)
@@ -974,6 +1082,9 @@ private:
         case CellUse:
         case ObjectUse:
         case StringUse:
+        case KnownStringUse:
+        case StringObjectUse:
+        case StringOrStringObjectUse:
             if (alwaysUnboxSimplePrimitives()
                 || isCellSpeculation(variable->prediction()))
                 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
index 605a5a2..45bf669 100644 (file)
@@ -376,6 +376,16 @@ public:
         return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock);
     }
     
+    bool hasGlobalExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind)
+    {
+        return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(exitKind));
+    }
+    
+    bool hasExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind)
+    {
+        return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(codeOrigin.bytecodeIndex, exitKind));
+    }
+    
     int argumentsRegisterFor(const CodeOrigin& codeOrigin)
     {
         if (!codeOrigin.inlineCallFrame)
@@ -522,6 +532,18 @@ public:
         case PutByVal:
         case PutByValAlias:
             return !byValIsPure(node);
+        case ToString:
+            switch (node->child1().useKind()) {
+            case StringObjectUse:
+            case StringOrStringObjectUse:
+                return false;
+            case CellUse:
+            case UntypedUse:
+                return true;
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+                return true;
+            }
         default:
             RELEASE_ASSERT_NOT_REACHED();
             return true; // If by some oddity we hit this case in release build it's safer to have CSE assume the worst.
index 06e9915..505d7a2 100644 (file)
@@ -349,6 +349,12 @@ struct Node {
         children.setChild1(Edge(phi));
     }
     
+    void convertToToString()
+    {
+        ASSERT(m_op == ToPrimitive);
+        m_op = ToString;
+    }
+    
     JSCell* weakConstant()
     {
         ASSERT(op() == WeakJSConstant);
@@ -844,6 +850,7 @@ struct Node {
         case ForwardStructureTransitionWatchpoint:
         case ArrayifyToStructure:
         case NewObject:
+        case NewStringObject:
             return true;
         default:
             return false;
@@ -1120,6 +1127,16 @@ struct Node {
         return isStringSpeculation(prediction());
     }
  
+    bool shouldSpeculateStringObject()
+    {
+        return isStringObjectSpeculation(prediction());
+    }
+    
+    bool shouldSpeculateStringOrStringObject()
+    {
+        return isStringOrStringObjectSpeculation(prediction());
+    }
+    
     bool shouldSpeculateFinalObject()
     {
         return isFinalObjectSpeculation(prediction());
index afada5d..775928c 100644 (file)
@@ -222,6 +222,8 @@ namespace JSC { namespace DFG {
     macro(TypeOf, NodeResultJS) \
     macro(LogicalNot, NodeResultBoolean) \
     macro(ToPrimitive, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \
+    macro(ToString, NodeResultJS | NodeMustGenerate | NodeMightClobber) \
+    macro(NewStringObject, NodeResultJS) \
     macro(StrCat, NodeResultJS | NodeMustGenerate | NodeHasVarArgs | NodeClobbersWorld) \
     \
     /* Nodes used for activations. Activation support works by having it anchored at */\
index 4ccb911..10bcc9b 100644 (file)
@@ -1547,6 +1547,30 @@ StringImpl* DFG_OPERATION operationResolveRope(ExecState* exec, JSString* string
     return string->value(exec).impl();
 }
 
+JSCell* DFG_OPERATION operationNewStringObject(ExecState* exec, JSString* string, Structure* structure)
+{
+    JSGlobalData& globalData = exec->globalData();
+    NativeCallFrameTracer tracer(&globalData, exec);
+    
+    return StringObject::create(exec, structure, string);
+}
+
+JSCell* DFG_OPERATION operationToStringOnCell(ExecState* exec, JSCell* cell)
+{
+    JSGlobalData& globalData = exec->globalData();
+    NativeCallFrameTracer tracer(&globalData, exec);
+    
+    return JSValue(cell).toString(exec);
+}
+
+JSCell* DFG_OPERATION operationToString(ExecState* exec, EncodedJSValue value)
+{
+    JSGlobalData& globalData = exec->globalData();
+    NativeCallFrameTracer tracer(&globalData, exec);
+
+    return JSValue::decode(value).toString(exec);
+}
+
 double DFG_OPERATION operationFModOnInts(int32_t a, int32_t b)
 {
     return fmod(a, b);
index 99ed55a..9d57d55 100644 (file)
@@ -85,6 +85,8 @@ typedef JSCell* DFG_OPERATION (*C_DFGOperation_E)(ExecState*);
 typedef JSCell* DFG_OPERATION (*C_DFGOperation_EC)(ExecState*, JSCell*);
 typedef JSCell* DFG_OPERATION (*C_DFGOperation_ECC)(ExecState*, JSCell*, JSCell*);
 typedef JSCell* DFG_OPERATION (*C_DFGOperation_EIcf)(ExecState*, InlineCallFrame*);
+typedef JSCell* DFG_OPERATION (*C_DFGOperation_EJ)(ExecState*, EncodedJSValue);
+typedef JSCell* DFG_OPERATION (*C_DFGOperation_EJssSt)(ExecState*, JSString*, Structure*);
 typedef JSCell* DFG_OPERATION (*C_DFGOperation_EOZ)(ExecState*, JSObject*, int32_t);
 typedef JSCell* DFG_OPERATION (*C_DFGOperation_ESt)(ExecState*, Structure*);
 typedef double DFG_OPERATION (*D_DFGOperation_DD)(double, double);
@@ -212,6 +214,9 @@ char* DFG_OPERATION operationEnsureContiguous(ExecState*, JSCell*);
 char* DFG_OPERATION operationRageEnsureContiguous(ExecState*, JSCell*);
 char* DFG_OPERATION operationEnsureArrayStorage(ExecState*, JSCell*);
 StringImpl* DFG_OPERATION operationResolveRope(ExecState*, JSString*);
+JSCell* DFG_OPERATION operationNewStringObject(ExecState*, JSString*, Structure*);
+JSCell* DFG_OPERATION operationToStringOnCell(ExecState*, JSCell*);
+JSCell* DFG_OPERATION operationToString(ExecState*, EncodedJSValue);
 
 // This method is used to lookup an exception hander, keyed by faultLocation, which is
 // the return location from one of the calls out to one of the helper operations above.
index 815cbe2..8a4e0de 100644 (file)
@@ -413,7 +413,8 @@ private:
         }
         
         case StringCharAt:
-        case StrCat: {
+        case StrCat:
+        case ToString: {
             changed |= setPrediction(SpecString);
             break;
         }
@@ -439,6 +440,11 @@ private:
             break;
         }
             
+        case NewStringObject: {
+            changed |= setPrediction(SpecStringObject);
+            break;
+        }
+            
         case CreateArguments: {
             changed |= setPrediction(SpecArguments);
             break;
index 345b275..4f83dad 100644 (file)
@@ -3922,6 +3922,115 @@ GPRReg SpeculativeJIT::temporaryRegisterForPutByVal(GPRTemporary& temporary, Arr
     return temporary.gpr();
 }
 
+void SpeculativeJIT::compileToStringOnCell(Node* node)
+{
+    SpeculateCellOperand op1(this, node->child1());
+    GPRReg op1GPR = op1.gpr();
+    
+    switch (node->child1().useKind()) {
+    case StringObjectUse: {
+        GPRTemporary result(this);
+        GPRReg resultGPR = result.gpr();
+        
+        if (!m_state.forNode(node->child1()).m_currentKnownStructure.isSubsetOf(StructureSet(m_jit.globalObjectFor(node->codeOrigin)->stringObjectStructure()))) {
+            speculateStringObject(op1GPR);
+            m_state.forNode(node->child1()).filter(SpecStringObject);
+        }
+        m_jit.loadPtr(JITCompiler::Address(op1GPR, JSWrapperObject::internalValueCellOffset()), resultGPR);
+        cellResult(resultGPR, node);
+        break;
+    }
+        
+    case StringOrStringObjectUse: {
+        GPRTemporary result(this);
+        GPRReg resultGPR = result.gpr();
+        
+        m_jit.loadPtr(JITCompiler::Address(op1GPR, JSCell::structureOffset()), resultGPR);
+        JITCompiler::Jump isString = m_jit.branchPtr(
+            JITCompiler::Equal, resultGPR, TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
+        
+        speculateStringObjectForStructure(resultGPR);
+        
+        m_jit.loadPtr(JITCompiler::Address(op1GPR, JSWrapperObject::internalValueCellOffset()), resultGPR);
+        
+        JITCompiler::Jump done = m_jit.jump();
+        isString.link(&m_jit);
+        m_jit.move(op1GPR, resultGPR);
+        done.link(&m_jit);
+        
+        m_state.forNode(node->child1()).filter(SpecString | SpecStringObject);
+        
+        cellResult(resultGPR, node);
+        break;
+    }
+        
+    case CellUse: {
+        GPRResult result(this);
+        GPRReg resultGPR = result.gpr();
+        
+        // We flush registers instead of silent spill/fill because in this mode we
+        // believe that most likely the input is not a string, and we need to take
+        // slow path.
+        flushRegisters();
+        JITCompiler::Jump done;
+        if (node->child1()->prediction() & SpecString) {
+            done = m_jit.branchPtr(
+                JITCompiler::Equal,
+                JITCompiler::Address(op1GPR, JSCell::structureOffset()),
+                TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
+        }
+        callOperation(operationToStringOnCell, resultGPR, op1GPR);
+        if (done.isSet())
+            done.link(&m_jit);
+        cellResult(resultGPR, node);
+        break;
+    }
+        
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+}
+
+void SpeculativeJIT::compileNewStringObject(Node* node)
+{
+    SpeculateCellOperand operand(this, node->child1());
+    
+    GPRTemporary result(this);
+    GPRTemporary scratch1(this);
+    GPRTemporary scratch2(this);
+
+    GPRReg operandGPR = operand.gpr();
+    GPRReg resultGPR = result.gpr();
+    GPRReg scratch1GPR = scratch1.gpr();
+    GPRReg scratch2GPR = scratch2.gpr();
+    
+    JITCompiler::JumpList slowPath;
+    
+    emitAllocateJSObject<StringObject>(
+        resultGPR, TrustedImmPtr(node->structure()), TrustedImmPtr(0), scratch1GPR, scratch2GPR,
+        slowPath);
+    
+    m_jit.storePtr(
+        TrustedImmPtr(&StringObject::s_info),
+        JITCompiler::Address(resultGPR, JSDestructibleObject::classInfoOffset()));
+#if USE(JSVALUE64)
+    m_jit.store64(
+        operandGPR, JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset()));
+#else
+    m_jit.store32(
+        TrustedImm32(JSValue::CellTag),
+        JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+    m_jit.store32(
+        operandGPR,
+        JITCompiler::Address(resultGPR, JSWrapperObject::internalValueOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+#endif
+    
+    addSlowPathGenerator(slowPathCall(
+        slowPath, this, operationNewStringObject, resultGPR, operandGPR, node->structure()));
+    
+    cellResult(resultGPR, node);
+}
+
 void SpeculativeJIT::speculateInt32(Edge edge)
 {
     if (!needsTypeCheck(edge, SpecInt32))
@@ -3973,10 +4082,11 @@ void SpeculativeJIT::speculateObject(Edge edge)
         return;
     
     SpeculateCellOperand operand(this, edge);
+    GPRReg gpr = operand.gpr();
     DFG_TYPE_CHECK(
-        JSValueSource::unboxedCell(operand.gpr()), edge, SpecObject, m_jit.branchPtr(
+        JSValueSource::unboxedCell(gpr), edge, SpecObject, m_jit.branchPtr(
             MacroAssembler::Equal, 
-            MacroAssembler::Address(operand.gpr(), JSCell::structureOffset()), 
+            MacroAssembler::Address(gpr, JSCell::structureOffset()), 
             MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
 }
 
@@ -3993,7 +4103,7 @@ void SpeculativeJIT::speculateObjectOrOther(Edge edge)
     MacroAssembler::Jump notCell = m_jit.branchTest64(
         MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister);
     DFG_TYPE_CHECK(
-        JSValueRegs(operand.gpr()), edge, (~SpecCell) | SpecObject, m_jit.branchPtr(
+        JSValueRegs(gpr), edge, (~SpecCell) | SpecObject, m_jit.branchPtr(
             MacroAssembler::Equal, 
             MacroAssembler::Address(gpr, JSCell::structureOffset()), 
             MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
@@ -4042,13 +4152,58 @@ void SpeculativeJIT::speculateString(Edge edge)
         return;
     
     SpeculateCellOperand operand(this, edge);
+    GPRReg gpr = operand.gpr();
     DFG_TYPE_CHECK(
-        JSValueSource::unboxedCell(operand.gpr()), edge, SpecString, m_jit.branchPtr(
+        JSValueSource::unboxedCell(gpr), edge, SpecString, m_jit.branchPtr(
             MacroAssembler::NotEqual, 
-            MacroAssembler::Address(operand.gpr(), JSCell::structureOffset()), 
+            MacroAssembler::Address(gpr, JSCell::structureOffset()), 
             MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get())));
 }
 
+void SpeculativeJIT::speculateStringObject(GPRReg gpr)
+{
+    speculateStringObjectForStructure(JITCompiler::Address(gpr, JSCell::structureOffset()));
+}
+
+void SpeculativeJIT::speculateStringObject(Edge edge)
+{
+    if (!needsTypeCheck(edge, SpecStringObject))
+        return;
+    
+    SpeculateCellOperand operand(this, edge);
+    GPRReg gpr = operand.gpr();
+    if (!needsTypeCheck(edge, SpecStringObject))
+        return;
+    
+    speculateStringObject(gpr);
+    m_state.forNode(edge).filter(SpecStringObject);
+}
+
+void SpeculativeJIT::speculateStringOrStringObject(Edge edge)
+{
+    if (!needsTypeCheck(edge, SpecString | SpecStringObject))
+        return;
+    
+    SpeculateCellOperand operand(this, edge);
+    GPRReg gpr = operand.gpr();
+    if (!needsTypeCheck(edge, SpecString | SpecStringObject))
+        return;
+    
+    GPRTemporary structure(this);
+    GPRReg structureGPR = structure.gpr();
+    
+    m_jit.loadPtr(JITCompiler::Address(gpr, JSCell::structureOffset()), structureGPR);
+    
+    JITCompiler::Jump isString = m_jit.branchPtr(
+        JITCompiler::Equal, structureGPR, TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
+    
+    speculateStringObjectForStructure(structureGPR);
+    
+    isString.link(&m_jit);
+    
+    m_state.forNode(edge).filter(SpecString | SpecStringObject);
+}
+
 void SpeculativeJIT::speculateNotCell(Edge edge)
 {
     if (!needsTypeCheck(edge, ~SpecCell))
@@ -4107,6 +4262,9 @@ void SpeculativeJIT::speculate(Node*, Edge edge)
     case KnownCellUse:
         ASSERT(!needsTypeCheck(edge, SpecCell));
         break;
+    case KnownStringUse:
+        ASSERT(!needsTypeCheck(edge, SpecString));
+        break;
     case Int32Use:
         speculateInt32(edge);
         break;
@@ -4131,6 +4289,12 @@ void SpeculativeJIT::speculate(Node*, Edge edge)
     case StringUse:
         speculateString(edge);
         break;
+    case StringObjectUse:
+        speculateStringObject(edge);
+        break;
+    case StringOrStringObjectUse:
+        speculateStringOrStringObject(edge);
+        break;
     case NotCellUse:
         speculateNotCell(edge);
         break;
index 8ea520c..e352d2e 100644 (file)
@@ -1085,6 +1085,16 @@ public:
         m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure));
         return appendCallWithExceptionCheckSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(C_DFGOperation_EJssSt operation, GPRReg result, GPRReg arg1, Structure* structure)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(structure));
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
+    JITCompiler::Call callOperation(C_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
+    {
+        m_jit.setupArgumentsWithExecState(arg1);
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(S_DFGOperation_J operation, GPRReg result, GPRReg arg1)
     {
         m_jit.setupArguments(arg1);
@@ -1473,6 +1483,16 @@ public:
         m_jit.setupArgumentsWithExecState(TrustedImmPtr(structure));
         return appendCallWithExceptionCheckSetResult(operation, result);
     }
+    JITCompiler::Call callOperation(C_DFGOperation_EJssSt operation, GPRReg result, GPRReg arg1, Structure* structure)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(structure));
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
+    JITCompiler::Call callOperation(C_DFGOperation_EJ operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload)
+    {
+        m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag);
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
     JITCompiler::Call callOperation(S_DFGOperation_J operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload)
     {
         m_jit.setupArguments(arg1Payload, arg1Tag);
@@ -2031,6 +2051,9 @@ public:
     void emitObjectOrOtherBranch(Edge value, BlockIndex taken, BlockIndex notTaken);
     void emitBranch(Node*);
     
+    void compileToStringOnCell(Node*);
+    void compileNewStringObject(Node*);
+    
     void compileIntegerCompare(Node*, MacroAssembler::RelationalCondition);
     void compileDoubleCompare(Node*, MacroAssembler::DoubleCondition);
     
@@ -2204,6 +2227,11 @@ public:
     void speculateObject(Edge);
     void speculateObjectOrOther(Edge);
     void speculateString(Edge);
+    template<typename StructureLocationType>
+    void speculateStringObjectForStructure(StructureLocationType);
+    void speculateStringObject(GPRReg);
+    void speculateStringObject(Edge);
+    void speculateStringOrStringObject(Edge);
     void speculateNotCell(Edge);
     void speculateOther(Edge);
     void speculate(Node*, Edge);
@@ -2838,7 +2866,7 @@ public:
         , m_gprOrInvalid(InvalidGPRReg)
     {
         ASSERT(m_jit);
-        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == CellUse || edge.useKind() == KnownCellUse || edge.useKind() == ObjectUse || edge.useKind() == StringUse));
+        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == CellUse || edge.useKind() == KnownCellUse || edge.useKind() == ObjectUse || edge.useKind() == StringUse || edge.useKind() == KnownStringUse || edge.useKind() == StringObjectUse || edge.useKind() == StringOrStringObjectUse));
         if (jit->isFilled(node()))
             gpr();
     }
@@ -2924,6 +2952,21 @@ private:
     GPRReg m_gprOrInvalid;
 };
 
+template<typename StructureLocationType>
+void SpeculativeJIT::speculateStringObjectForStructure(StructureLocationType structureLocation)
+{
+    Structure* stringObjectStructure =
+        m_jit.globalObjectFor(m_currentNode->codeOrigin)->stringObjectStructure();
+    Structure* stringPrototypeStructure = stringObjectStructure->storedPrototype().asCell()->structure();
+    ASSERT(stringPrototypeStructure->transitionWatchpointSetIsStillValid());
+    
+    speculationCheck(
+        NotStringObject, JSValueRegs(), 0,
+        m_jit.branchPtr(
+            JITCompiler::NotEqual, structureLocation, TrustedImmPtr(stringObjectStructure)));
+    stringPrototypeStructure->addTransitionWatchpoint(speculationWatchpoint(NotStringObject));
+}
+
 #define DFG_TYPE_CHECK(source, edge, typesPassedThrough, jumpToFail) do { \
         if (!needsTypeCheck((edge), (typesPassedThrough)))              \
             break;                                                      \
index c13cf87..e56784c 100644 (file)
@@ -1099,7 +1099,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge)
 #endif
     AbstractValue& value = m_state.forNode(edge);
     SpeculatedType type = value.m_type;
-    ASSERT(edge.useKind() != KnownCellUse || !(value.m_type & ~SpecCell));
+    ASSERT((edge.useKind() != KnownCellUse && edge.useKind() != KnownStringUse) || !(value.m_type & ~SpecCell));
     value.filter(SpecCell);
     VirtualRegister virtualRegister = edge->virtualRegister();
     GenerationInfo& info = m_generationInfo[virtualRegister];
@@ -3258,58 +3258,73 @@ void SpeculativeJIT::compile(Node* node)
     }
         
     case ToPrimitive: {
-        switch (node->child1().useKind()) {
-        case Int32Use: {
-            // It's really profitable to speculate integer, since it's really cheap,
-            // it means we don't have to do any real work, and we emit a lot less code.
-            
-            SpeculateIntegerOperand op1(this, node->child1());
-            GPRTemporary result(this, op1);
+        RELEASE_ASSERT(node->child1().useKind() == UntypedUse);
+        JSValueOperand op1(this, node->child1());
+        GPRTemporary resultTag(this, op1);
+        GPRTemporary resultPayload(this, op1, false);
+        
+        GPRReg op1TagGPR = op1.tagGPR();
+        GPRReg op1PayloadGPR = op1.payloadGPR();
+        GPRReg resultTagGPR = resultTag.gpr();
+        GPRReg resultPayloadGPR = resultPayload.gpr();
+        
+        op1.use();
+        
+        if (!(m_state.forNode(node->child1()).m_type & ~(SpecNumber | SpecBoolean))) {
+            m_jit.move(op1TagGPR, resultTagGPR);
+            m_jit.move(op1PayloadGPR, resultPayloadGPR);
+        } else {
+            MacroAssembler::Jump alreadyPrimitive = m_jit.branch32(MacroAssembler::NotEqual, op1TagGPR, TrustedImm32(JSValue::CellTag));
+            MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1PayloadGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
             
-            ASSERT(op1.format() == DataFormatInteger);
-            m_jit.move(op1.gpr(), result.gpr());
+            alreadyPrimitive.link(&m_jit);
+            m_jit.move(op1TagGPR, resultTagGPR);
+            m_jit.move(op1PayloadGPR, resultPayloadGPR);
             
-            integerResult(result.gpr(), node);
-            break;
+            addSlowPathGenerator(
+                slowPathCall(
+                    notPrimitive, this, operationToPrimitive,
+                    JSValueRegs(resultTagGPR, resultPayloadGPR), op1TagGPR, op1PayloadGPR));
         }
-
-        case UntypedUse: {
-            JSValueOperand op1(this, node->child1());
-            GPRTemporary resultTag(this, op1);
-            GPRTemporary resultPayload(this, op1, false);
         
-            GPRReg op1TagGPR = op1.tagGPR();
-            GPRReg op1PayloadGPR = op1.payloadGPR();
-            GPRReg resultTagGPR = resultTag.gpr();
-            GPRReg resultPayloadGPR = resultPayload.gpr();
-        
-            op1.use();
+        jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
+        break;
+    }
         
-            if (!(m_state.forNode(node->child1()).m_type & ~(SpecNumber | SpecBoolean))) {
-                m_jit.move(op1TagGPR, resultTagGPR);
-                m_jit.move(op1PayloadGPR, resultPayloadGPR);
-            } else {
-                MacroAssembler::Jump alreadyPrimitive = m_jit.branch32(MacroAssembler::NotEqual, op1TagGPR, TrustedImm32(JSValue::CellTag));
-                MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1PayloadGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
+    case ToString: {
+        if (node->child1().useKind() == UntypedUse) {
+            JSValueOperand op1(this, node->child1());
+            GPRReg op1PayloadGPR = op1.payloadGPR();
+            GPRReg op1TagGPR = op1.tagGPR();
             
-                alreadyPrimitive.link(&m_jit);
-                m_jit.move(op1TagGPR, resultTagGPR);
-                m_jit.move(op1PayloadGPR, resultPayloadGPR);
+            GPRResult result(this);
+            GPRReg resultGPR = result.gpr();
             
-                addSlowPathGenerator(
-                    slowPathCall(
-                        notPrimitive, this, operationToPrimitive,
-                        JSValueRegs(resultTagGPR, resultPayloadGPR), op1TagGPR, op1PayloadGPR));
-            }
-        
-            jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
-            break;
-        }
+            flushRegisters();
             
-        default:
-            RELEASE_ASSERT_NOT_REACHED();
+            JITCompiler::Jump done;
+            if (node->child1()->prediction() & SpecString) {
+                JITCompiler::Jump slowPath = m_jit.branch32(
+                    JITCompiler::NotEqual, op1TagGPR, TrustedImm32(JSValue::CellTag));
+                done = m_jit.branchPtr(
+                    JITCompiler::Equal,
+                    JITCompiler::Address(op1PayloadGPR, JSCell::structureOffset()),
+                    TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
+                slowPath.link(&m_jit);
+            }
+            callOperation(operationToString, resultGPR, op1TagGPR, op1PayloadGPR);
+            if (done.isSet())
+                done.link(&m_jit);
+            cellResult(resultGPR, node);
             break;
         }
+        
+        compileToStringOnCell(node);
+        break;
+    }
+        
+    case NewStringObject: {
+        compileNewStringObject(node);
         break;
     }
         
index 087aaa2..157549e 100644 (file)
@@ -1125,7 +1125,7 @@ GPRReg SpeculativeJIT::fillSpeculateCell(Edge edge)
 #endif
     AbstractValue& value = m_state.forNode(edge);
     SpeculatedType type = value.m_type;
-    ASSERT(edge.useKind() != KnownCellUse || !(value.m_type & ~SpecCell));
+    ASSERT((edge.useKind() != KnownCellUse && edge.useKind() != KnownStringUse) || !(value.m_type & ~SpecCell));
     value.filter(SpecCell);
     VirtualRegister virtualRegister = edge->virtualRegister();
     GenerationInfo& info = m_generationInfo[virtualRegister];
@@ -3188,52 +3188,65 @@ void SpeculativeJIT::compile(Node* node)
     }
         
     case ToPrimitive: {
-        switch (node->child1().useKind()) {
-        case Int32Use: {
-            // It's really profitable to speculate integer, since it's really cheap,
-            // it means we don't have to do any real work, and we emit a lot less code.
-            
-            SpeculateIntegerOperand op1(this, node->child1());
-            GPRTemporary result(this, op1);
+        RELEASE_ASSERT(node->child1().useKind() == UntypedUse);
+        JSValueOperand op1(this, node->child1());
+        GPRTemporary result(this, op1);
+        
+        GPRReg op1GPR = op1.gpr();
+        GPRReg resultGPR = result.gpr();
+        
+        op1.use();
+        
+        if (!(m_state.forNode(node->child1()).m_type & ~(SpecNumber | SpecBoolean)))
+            m_jit.move(op1GPR, resultGPR);
+        else {
+            MacroAssembler::Jump alreadyPrimitive = m_jit.branchTest64(MacroAssembler::NonZero, op1GPR, GPRInfo::tagMaskRegister);
+            MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
             
-            m_jit.move(op1.gpr(), result.gpr());
-            if (op1.format() == DataFormatInteger)
-                m_jit.or64(GPRInfo::tagTypeNumberRegister, result.gpr());
+            alreadyPrimitive.link(&m_jit);
+            m_jit.move(op1GPR, resultGPR);
             
-            jsValueResult(result.gpr(), node);
-            break;
+            addSlowPathGenerator(
+                slowPathCall(notPrimitive, this, operationToPrimitive, resultGPR, op1GPR));
         }
         
-        case UntypedUse: {
-            JSValueOperand op1(this, node->child1());
-            GPRTemporary result(this, op1);
+        jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
+        break;
+    }
         
+    case ToString: {
+        if (node->child1().useKind() == UntypedUse) {
+            JSValueOperand op1(this, node->child1());
             GPRReg op1GPR = op1.gpr();
+            
+            GPRResult result(this);
             GPRReg resultGPR = result.gpr();
-        
-            op1.use();
-        
-            if (!(m_state.forNode(node->child1()).m_type & ~(SpecNumber | SpecBoolean)))
-                m_jit.move(op1GPR, resultGPR);
-            else {
-                MacroAssembler::Jump alreadyPrimitive = m_jit.branchTest64(MacroAssembler::NonZero, op1GPR, GPRInfo::tagMaskRegister);
-                MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
             
-                alreadyPrimitive.link(&m_jit);
-                m_jit.move(op1GPR, resultGPR);
+            flushRegisters();
             
-                addSlowPathGenerator(
-                    slowPathCall(notPrimitive, this, operationToPrimitive, resultGPR, op1GPR));
+            JITCompiler::Jump done;
+            if (node->child1()->prediction() & SpecString) {
+                JITCompiler::Jump slowPath = m_jit.branchTest64(
+                    JITCompiler::NonZero, op1GPR, GPRInfo::tagMaskRegister);
+                done = m_jit.branchPtr(
+                    JITCompiler::Equal,
+                    JITCompiler::Address(op1GPR, JSCell::structureOffset()),
+                    TrustedImmPtr(m_jit.globalData()->stringStructure.get()));
+                slowPath.link(&m_jit);
             }
-        
-            jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
-            break;
-        }
-            
-        default:
-            RELEASE_ASSERT_NOT_REACHED();
+            callOperation(operationToString, resultGPR, op1GPR);
+            if (done.isSet())
+                done.link(&m_jit);
+            cellResult(resultGPR, node);
             break;
         }
+        
+        compileToStringOnCell(node);
+        break;
+    }
+        
+    case NewStringObject: {
+        compileNewStringObject(node);
         break;
     }
         
index bb81920..bfba754 100644 (file)
@@ -71,6 +71,15 @@ void printInternal(PrintStream& out, UseKind useKind)
     case StringUse:
         out.print("String");
         break;
+    case KnownStringUse:
+        out.print("KnownString");
+        break;
+    case StringObjectUse:
+        out.print("StringObject");
+        break;
+    case StringOrStringObjectUse:
+        out.print("StringOrStringObject");
+        break;
     case NotCellUse:
         out.print("NotCell");
         break;
index 74b0ca2..afe3d35 100644 (file)
@@ -48,6 +48,9 @@ enum UseKind {
     ObjectUse,
     ObjectOrOtherUse,
     StringUse,
+    KnownStringUse,
+    StringObjectUse,
+    StringOrStringObjectUse,
     NotCellUse,
     OtherUse,
     LastUseKind // Must always be the last entry in the enum, as it is used to denote the number of enum elements.
@@ -76,7 +79,12 @@ ALWAYS_INLINE SpeculatedType typeFilterFor(UseKind useKind)
     case ObjectOrOtherUse:
         return SpecObject | SpecOther;
     case StringUse:
+    case KnownStringUse:
         return SpecString;
+    case StringObjectUse:
+        return SpecStringObject;
+    case StringOrStringObjectUse:
+        return SpecString | SpecStringObject;
     case NotCellUse:
         return ~SpecCell;
     case OtherUse:
index 9852b31..716115b 100644 (file)
@@ -94,7 +94,6 @@ namespace JSC  {
         static const HashTable* regExpTable(CallFrame* callFrame) { return callFrame->globalData().regExpTable; }
         static const HashTable* regExpConstructorTable(CallFrame* callFrame) { return callFrame->globalData().regExpConstructorTable; }
         static const HashTable* regExpPrototypeTable(CallFrame* callFrame) { return callFrame->globalData().regExpPrototypeTable; }
-        static const HashTable* stringTable(CallFrame* callFrame) { return callFrame->globalData().stringTable; }
         static const HashTable* stringConstructorTable(CallFrame* callFrame) { return callFrame->globalData().stringConstructorTable; }
 
         static CallFrame* create(Register* callFrameBase) { return static_cast<CallFrame*>(callFrameBase); }
index 73244e7..76fb92a 100644 (file)
@@ -47,6 +47,7 @@ enum Intrinsic {
     LogIntrinsic,
     RegExpExecIntrinsic,
     RegExpTestIntrinsic,
+    StringPrototypeValueOfIntrinsic
 };
 
 } // namespace JSC
index b8479be..7eb4548 100644 (file)
@@ -14,6 +14,8 @@ public:
     static const bool needsDestruction = true;
 
     const ClassInfo* classInfo() const { return m_classInfo; }
+    
+    static ptrdiff_t classInfoOffset() { return OBJECT_OFFSETOF(JSDestructibleObject, m_classInfo); }
 
 protected:
     JSDestructibleObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly = 0)
index 36f2ffd..7ff2de1 100644 (file)
@@ -97,7 +97,6 @@ extern const HashTable privateNamePrototypeTable;
 extern const HashTable regExpTable;
 extern const HashTable regExpConstructorTable;
 extern const HashTable regExpPrototypeTable;
-extern const HashTable stringTable;
 extern const HashTable stringConstructorTable;
 
 // Note: Platform.h will enforce that ENABLE(ASSEMBLER) is true if either
@@ -158,7 +157,6 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, HeapType heapType)
     , regExpTable(fastNew<HashTable>(JSC::regExpTable))
     , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable))
     , regExpPrototypeTable(fastNew<HashTable>(JSC::regExpPrototypeTable))
-    , stringTable(fastNew<HashTable>(JSC::stringTable))
     , stringConstructorTable(fastNew<HashTable>(JSC::stringConstructorTable))
     , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
     , propertyNames(new CommonIdentifiers(this))
@@ -288,7 +286,6 @@ JSGlobalData::~JSGlobalData()
     regExpTable->deleteTable();
     regExpConstructorTable->deleteTable();
     regExpPrototypeTable->deleteTable();
-    stringTable->deleteTable();
     stringConstructorTable->deleteTable();
 
     fastDelete(const_cast<HashTable*>(arrayConstructorTable));
@@ -307,7 +304,6 @@ JSGlobalData::~JSGlobalData()
     fastDelete(const_cast<HashTable*>(regExpTable));
     fastDelete(const_cast<HashTable*>(regExpConstructorTable));
     fastDelete(const_cast<HashTable*>(regExpPrototypeTable));
-    fastDelete(const_cast<HashTable*>(stringTable));
     fastDelete(const_cast<HashTable*>(stringConstructorTable));
 
     opaqueJSClassData.clear();
index 570d85d..9a59d14 100644 (file)
@@ -230,7 +230,6 @@ namespace JSC {
         const HashTable* regExpTable;
         const HashTable* regExpConstructorTable;
         const HashTable* regExpPrototypeTable;
-        const HashTable* stringTable;
         const HashTable* stringConstructorTable;
         
         Strong<Structure> structureStructure;
index bd88b4d..bb87763 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
- *  Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2012 Apple Inc. All rights reserved.
+ *  Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
  *  Copyright (C) 2007 Eric Seidel (eric@webkit.org)
  *
  *  This library is free software; you can redistribute it and/or
@@ -30,6 +30,7 @@
 #include "CopyVisitorInlines.h"
 #include "DatePrototype.h"
 #include "ErrorConstructor.h"
+#include "Executable.h"
 #include "GetterSetter.h"
 #include "IndexingHeaderInlines.h"
 #include "JSFunction.h"
index d8532b1..17566f8 100644 (file)
@@ -1454,10 +1454,16 @@ COMPILE_ASSERT(!(sizeof(JSObject) % sizeof(WriteBarrierBase<Unknown>)), JSObject
 // Helper for defining native functions, if you're not using a static hash table.
 // Use this macro from within finishCreation() methods in prototypes. This assumes
 // you've defined variables called exec, globalObject, and globalData, and they
-// have the expected meanings. This also assumes that the function you're defining
-// doesn't have an intrinsic.
+// have the expected meanings.
+#define JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, attributes, length, intrinsic) \
+    putDirectNativeFunction(\
+        exec, globalObject, Identifier(exec, #jsName), (length), cppName, \
+        (intrinsic), (attributes))
+
+// As above, but this assumes that the function you're defining doesn't have an
+// intrinsic.
 #define JSC_NATIVE_FUNCTION(jsName, cppName, attributes, length) \
-    putDirectNativeFunction(exec, globalObject, globalData.propertyNames->jsName, (length), cppName, NoIntrinsic, (attributes))
+    JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, (attributes), (length), NoIntrinsic)
 
 } // namespace JSC
 
index 72bc187..f108c9e 100644 (file)
@@ -32,6 +32,12 @@ namespace JSC {
     public:
         typedef JSDestructibleObject Base;
 
+        static size_t allocationSize(size_t inlineCapacity)
+        {
+            ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
+            return sizeof(JSWrapperObject);
+        }
+
         JSValue internalValue() const;
         void setInternalValue(JSGlobalData&, JSValue);
 
@@ -39,6 +45,16 @@ namespace JSC {
         { 
             return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
         }
+        
+        static ptrdiff_t internalValueOffset() { return OBJECT_OFFSETOF(JSWrapperObject, m_internalValue); }
+        static ptrdiff_t internalValueCellOffset()
+        {
+#if USE(JSVALUE64)
+            return internalValueOffset();
+#else
+            return internalValueOffset() + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload);
+#endif
+        }
 
     protected:
         explicit JSWrapperObject(JSGlobalData&, Structure*);
index 25f9897..d810812 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
- *  Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *  Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved.
  *  Copyright (C) 2009 Torch Mobile, Inc.
  *
  *  This library is free software; you can redistribute it and/or
@@ -82,56 +82,7 @@ static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*);
 static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*);
 static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*);
 
-}
-
-#include "StringPrototype.lut.h"
-
-namespace JSC {
-
-const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, ExecState::stringTable, CREATE_METHOD_TABLE(StringPrototype) };
-
-/* Source for StringPrototype.lut.h
-@begin stringTable 26
-    toString              stringProtoFuncToString          DontEnum|Function       0
-    valueOf               stringProtoFuncToString          DontEnum|Function       0
-    charAt                stringProtoFuncCharAt            DontEnum|Function       1
-    charCodeAt            stringProtoFuncCharCodeAt        DontEnum|Function       1
-    concat                stringProtoFuncConcat            DontEnum|Function       1
-    indexOf               stringProtoFuncIndexOf           DontEnum|Function       1
-    lastIndexOf           stringProtoFuncLastIndexOf       DontEnum|Function       1
-    match                 stringProtoFuncMatch             DontEnum|Function       1
-    replace               stringProtoFuncReplace           DontEnum|Function       2
-    search                stringProtoFuncSearch            DontEnum|Function       1
-    slice                 stringProtoFuncSlice             DontEnum|Function       2
-    split                 stringProtoFuncSplit             DontEnum|Function       2
-    substr                stringProtoFuncSubstr            DontEnum|Function       2
-    substring             stringProtoFuncSubstring         DontEnum|Function       2
-    toLowerCase           stringProtoFuncToLowerCase       DontEnum|Function       0
-    toUpperCase           stringProtoFuncToUpperCase       DontEnum|Function       0
-    localeCompare         stringProtoFuncLocaleCompare     DontEnum|Function       1
-
-    # toLocaleLowerCase and toLocaleUpperCase are currently identical to toLowerCase and toUpperCase
-    toLocaleLowerCase     stringProtoFuncToLowerCase       DontEnum|Function       0
-    toLocaleUpperCase     stringProtoFuncToUpperCase       DontEnum|Function       0
-
-    big                   stringProtoFuncBig               DontEnum|Function       0
-    small                 stringProtoFuncSmall             DontEnum|Function       0
-    blink                 stringProtoFuncBlink             DontEnum|Function       0
-    bold                  stringProtoFuncBold              DontEnum|Function       0
-    fixed                 stringProtoFuncFixed             DontEnum|Function       0
-    italics               stringProtoFuncItalics           DontEnum|Function       0
-    strike                stringProtoFuncStrike            DontEnum|Function       0
-    sub                   stringProtoFuncSub               DontEnum|Function       0
-    sup                   stringProtoFuncSup               DontEnum|Function       0
-    fontcolor             stringProtoFuncFontcolor         DontEnum|Function       1
-    fontsize              stringProtoFuncFontsize          DontEnum|Function       1
-    anchor                stringProtoFuncAnchor            DontEnum|Function       1
-    link                  stringProtoFuncLink              DontEnum|Function       1
-    trim                  stringProtoFuncTrim              DontEnum|Function       0
-    trimLeft              stringProtoFuncTrimLeft          DontEnum|Function       0
-    trimRight             stringProtoFuncTrimRight         DontEnum|Function       0
-@end
-*/
+const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, 0, CREATE_METHOD_TABLE(StringPrototype) };
 
 // ECMA 15.5.4
 StringPrototype::StringPrototype(ExecState* exec, Structure* structure)
@@ -139,23 +90,59 @@ StringPrototype::StringPrototype(ExecState* exec, Structure* structure)
 {
 }
 
-void StringPrototype::finishCreation(ExecState* exec, JSGlobalObject*, JSString* nameAndMessage)
+void StringPrototype::finishCreation(ExecState* exec, JSGlobalObject* globalObject, JSString* nameAndMessage)
 {
-    Base::finishCreation(exec->globalData(), nameAndMessage);
+    JSGlobalData& globalData = exec->globalData();
+    
+    Base::finishCreation(globalData, nameAndMessage);
     ASSERT(inherits(&s_info));
 
+    JSC_NATIVE_INTRINSIC_FUNCTION(toString, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic);
+    JSC_NATIVE_INTRINSIC_FUNCTION(valueOf, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic);
+    JSC_NATIVE_INTRINSIC_FUNCTION(charAt, stringProtoFuncCharAt, DontEnum, 1, CharAtIntrinsic);
+    JSC_NATIVE_INTRINSIC_FUNCTION(charCodeAt, stringProtoFuncCharCodeAt, DontEnum, 1, CharCodeAtIntrinsic);
+    JSC_NATIVE_FUNCTION(concat, stringProtoFuncConcat, DontEnum, 1);
+    JSC_NATIVE_FUNCTION(indexOf, stringProtoFuncIndexOf, DontEnum, 1);
+    JSC_NATIVE_FUNCTION(lastIndexOf, stringProtoFuncLastIndexOf, DontEnum, 1);
+    JSC_NATIVE_FUNCTION(match, stringProtoFuncMatch, DontEnum, 1);
+    JSC_NATIVE_FUNCTION(replace, stringProtoFuncReplace, DontEnum, 2);
+    JSC_NATIVE_FUNCTION(search, stringProtoFuncSearch, DontEnum, 1);
+    JSC_NATIVE_FUNCTION(slice, stringProtoFuncSlice, DontEnum, 2);
+    JSC_NATIVE_FUNCTION(split, stringProtoFuncSplit, DontEnum, 2);
+    JSC_NATIVE_FUNCTION(substr, stringProtoFuncSubstr, DontEnum, 2);
+    JSC_NATIVE_FUNCTION(substring, stringProtoFuncSubstring, DontEnum, 2);
+    JSC_NATIVE_FUNCTION(toLowerCase, stringProtoFuncToLowerCase, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(toUpperCase, stringProtoFuncToUpperCase, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(localeCompare, stringProtoFuncLocaleCompare, DontEnum, 1);
+    JSC_NATIVE_FUNCTION(toLocaleLowerCase, stringProtoFuncToLowerCase, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(toLocaleUpperCase, stringProtoFuncToUpperCase, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(big, stringProtoFuncBig, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(small, stringProtoFuncSmall, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(blink, stringProtoFuncBlink, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(bold, stringProtoFuncBold, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(fixed, stringProtoFuncFixed, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(italics, stringProtoFuncItalics, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(strike, stringProtoFuncStrike, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(sub, stringProtoFuncSub, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(sup, stringProtoFuncSup, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(fontcolor, stringProtoFuncFontcolor, DontEnum, 1);
+    JSC_NATIVE_FUNCTION(fontsize, stringProtoFuncFontsize, DontEnum, 1);
+    JSC_NATIVE_FUNCTION(anchor, stringProtoFuncAnchor, DontEnum, 1);
+    JSC_NATIVE_FUNCTION(link, stringProtoFuncLink, DontEnum, 1);
+    JSC_NATIVE_FUNCTION(trim, stringProtoFuncTrim, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(trimLeft, stringProtoFuncTrimLeft, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(trimRight, stringProtoFuncTrimRight, DontEnum, 0);
+
     // The constructor will be added later, after StringConstructor has been built
     putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
 }
 
-bool StringPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot &slot)
-{
-    return getStaticFunctionSlot<StringObject>(exec, ExecState::stringTable(exec), jsCast<StringPrototype*>(cell), propertyName, slot);
-}
-
-bool StringPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
+StringPrototype* StringPrototype::create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
 {
-    return getStaticFunctionDescriptor<StringObject>(exec, ExecState::stringTable(exec), jsCast<StringPrototype*>(object), propertyName, descriptor);
+    JSString* empty = jsEmptyString(exec);
+    StringPrototype* prototype = new (NotNull, allocateCell<StringPrototype>(*exec->heap())) StringPrototype(exec, structure);
+    prototype->finishCreation(exec, globalObject, empty);
+    return prototype;
 }
 
 // ------------------------------ Functions --------------------------
index b846c7b..6d36804 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *  Copyright (C) 2007, 2008, 2013 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -34,16 +34,7 @@ namespace JSC {
     public:
         typedef StringObject Base;
 
-        static StringPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
-        {
-            JSString* empty = jsEmptyString(exec);
-            StringPrototype* prototype = new (NotNull, allocateCell<StringPrototype>(*exec->heap())) StringPrototype(exec, structure);
-            prototype->finishCreation(exec, globalObject, empty);
-            return prototype;
-        }
-
-        static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
-        static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
+        static StringPrototype* create(ExecState*, JSGlobalObject*, Structure*);
 
         static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
         {
@@ -54,7 +45,7 @@ namespace JSC {
         
     protected:
         void finishCreation(ExecState*, JSGlobalObject*, JSString*);
-        static const unsigned StructureFlags = OverridesGetOwnPropertySlot | StringObject::StructureFlags;
+        static const unsigned StructureFlags = StringObject::StructureFlags;
 
     };