[ES6] Implement ES6 arrow function syntax. Arrow function specific features. Lexical bind of this
https://bugs.webkit.org/show_bug.cgi?id=144956
Source/JavaScriptCore:
Patch by Aleksandr Skachkov <gskachkov@gmail.com> on 2015-08-17
Reviewed by Saam Barati.
Added support of ES6 arrow function specific feature, lexical bind of this and no constructor. http://wiki.ecmascript.org/doku.php?id=harmony:arrow_function_syntax
In patch were implemented the following cases:
this - variable |this| is point to the |this| of the function where arrow function is declared. Lexical bind of |this|
constructor - the using of the command |new| for arrow function leads to runtime error
call(), apply(), bind() - methods can only pass in arguments, but has no effect on |this|
* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
* bytecode/ExecutableInfo.h:
(JSC::ExecutableInfo::ExecutableInfo):
(JSC::ExecutableInfo::isArrowFunction):
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::isArrowFunction):
* bytecode/UnlinkedFunctionExecutable.cpp:
(JSC::generateFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
(JSC::UnlinkedFunctionExecutable::codeBlockFor):
* bytecode/UnlinkedFunctionExecutable.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitNewFunctionCommon):
(JSC::BytecodeGenerator::emitNewFunctionExpression):
(JSC::BytecodeGenerator::emitNewArrowFunctionExpression):
(JSC::BytecodeGenerator::emitLoadArrowFunctionThis):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::ArrowFuncExprNode::emitBytecode):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToPhantomNewFunction):
(JSC::DFG::Node::hasCellOperand):
(JSC::DFG::Node::isFunctionAllocation):
* dfg/DFGNodeType.h:
* dfg/DFGObjectAllocationSinkingPhase.cpp:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGPromotedHeapLocation.cpp:
(WTF::printInternal):
* dfg/DFGPromotedHeapLocation.h:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileLoadArrowFunctionThis):
(JSC::DFG::SpeculativeJIT::compileNewFunctionCommon):
(JSC::DFG::SpeculativeJIT::compileNewFunction):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStoreBarrierInsertionPhase.cpp:
* dfg/DFGStructureRegistrationPhase.cpp:
(JSC::DFG::StructureRegistrationPhase::run):
* ftl/FTLAbstractHeapRepository.cpp:
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLIntrinsicRepository.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::DFG::LowerDFGToLLVM::compileNode):
(JSC::FTL::DFG::LowerDFGToLLVM::compileNewFunction):
(JSC::FTL::DFG::LowerDFGToLLVM::compileLoadArrowFunctionThis):
* ftl/FTLOperations.cpp:
(JSC::FTL::operationMaterializeObjectInOSR):
* interpreter/Interpreter.cpp:
* interpreter/Interpreter.h:
* jit/CCallHelpers.h:
(JSC::CCallHelpers::setupArgumentsWithExecState): Added 3 arguments version for windows build.
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITInlines.h:
(JSC::JIT::callOperation):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_load_arrowfunction_this):
(JSC::JIT::emit_op_new_func_exp):
(JSC::JIT::emitNewFuncExprCommon):
(JSC::JIT::emit_op_new_arrow_func_exp):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_load_arrowfunction_this):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* llint/LLIntOffsetsExtractor.cpp:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
(JSC::LLInt::setUpCall):
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createFunctionMetadata):
(JSC::ASTBuilder::createArrowFunctionExpr):
* parser/NodeConstructors.h:
(JSC::BaseFuncExprNode::BaseFuncExprNode):
(JSC::FuncExprNode::FuncExprNode):
(JSC::ArrowFuncExprNode::ArrowFuncExprNode):
* parser/Nodes.cpp:
(JSC::FunctionMetadataNode::FunctionMetadataNode):
* parser/Nodes.h:
(JSC::ExpressionNode::isArrowFuncExprNode):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseFunctionBody):
(JSC::Parser<LexerType>::parseFunctionInfo):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createFunctionMetadata):
* runtime/Executable.cpp:
(JSC::ScriptExecutable::newCodeBlockFor):
* runtime/Executable.h:
* runtime/JSArrowFunction.cpp: Added.
(JSC::JSArrowFunction::destroy):
(JSC::JSArrowFunction::create):
(JSC::JSArrowFunction::JSArrowFunction):
(JSC::JSArrowFunction::createWithInvalidatedReallocationWatchpoint):
(JSC::JSArrowFunction::visitChildren):
(JSC::JSArrowFunction::getConstructData):
* runtime/JSArrowFunction.h: Added.
(JSC::JSArrowFunction::allocationSize):
(JSC::JSArrowFunction::createImpl):
(JSC::JSArrowFunction::boundThis):
(JSC::JSArrowFunction::createStructure):
(JSC::JSArrowFunction::offsetOfThisValue):
* runtime/JSFunction.h:
* runtime/JSFunctionInlines.h:
(JSC::JSFunction::JSFunction):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::arrowFunctionStructure):
* tests/stress/arrowfunction-activation-sink-osrexit-default-value-tdz-error.js: Added.
* tests/stress/arrowfunction-activation-sink-osrexit-default-value.js: Added.
* tests/stress/arrowfunction-activation-sink-osrexit.js: Added.
* tests/stress/arrowfunction-activation-sink.js: Added.
* tests/stress/arrowfunction-bound.js: Added.
* tests/stress/arrowfunction-call.js: Added.
* tests/stress/arrowfunction-constructor.js: Added.
* tests/stress/arrowfunction-lexical-bind-this-1.js: Added.
* tests/stress/arrowfunction-lexical-bind-this-2.js: Added.
* tests/stress/arrowfunction-lexical-bind-this-3.js: Added.
* tests/stress/arrowfunction-lexical-bind-this-4.js: Added.
* tests/stress/arrowfunction-lexical-bind-this-5.js: Added.
* tests/stress/arrowfunction-lexical-bind-this-6.js: Added.
* tests/stress/arrowfunction-lexical-this-activation-sink-osrexit.js: Added.
* tests/stress/arrowfunction-lexical-this-activation-sink.js: Added.
* tests/stress/arrowfunction-lexical-this-sinking-no-double-allocate.js: Added.
* tests/stress/arrowfunction-lexical-this-sinking-osrexit.js: Added.
* tests/stress/arrowfunction-lexical-this-sinking-put.js: Added.
* tests/stress/arrowfunction-others.js: Added.
* tests/stress/arrowfunction-run-10-1.js: Added.
* tests/stress/arrowfunction-run-10-2.js: Added.
* tests/stress/arrowfunction-run-10000-1.js: Added.
* tests/stress/arrowfunction-run-10000-2.js: Added.
* tests/stress/arrowfunction-sinking-no-double-allocate.js: Added.
* tests/stress/arrowfunction-sinking-osrexit.js: Added.
* tests/stress/arrowfunction-sinking-put.js: Added.
* tests/stress/arrowfunction-tdz.js: Added.
* tests/stress/arrowfunction-typeof.js: Added.
LayoutTests:
Patch by Skachkov Oleksandr <gskachkov@gmail.com> on 2015-08-17
Reviewed by Saam Barati.
* js/arrowfunction-bind-expected.txt: Added.
* js/arrowfunction-bind.html: Added.
* js/arrowfunction-call-expected.txt: Added.
* js/arrowfunction-call.html: Added.
* js/arrowfunction-constructor-expected.txt: Added.
* js/arrowfunction-constructor.html: Added.
* js/arrowfunction-lexical-bind-this-expected.txt: Added.
* js/arrowfunction-lexical-bind-this.html: Added.
* js/arrowfunction-others-expected.txt: Added.
* js/arrowfunction-others.html: Added.
* js/arrowfunction-tdz-expected.txt: Added.
* js/arrowfunction-tdz.html: Added.
* js/arrowfunction-typeof-expected.txt: Added.
* js/arrowfunction-typeof.html: Added.
* js/regress/arrowfunction-call-expected.txt: Added.
* js/regress/arrowfunction-call.html: Added.
* js/regress/script-tests/arrowfunction-call.js: Added.
* js/regress/script-tests/function-call.js: Added.
* js/script-tests/arrowfunction-bind.js: Added.
* js/script-tests/arrowfunction-call.js: Added.
* js/script-tests/arrowfunction-constructor.js: Added.
* js/script-tests/arrowfunction-lexical-bind-this.js: Added.
* js/script-tests/arrowfunction-others.js: Added.
* js/script-tests/arrowfunction-tdz.js: Added.
* js/script-tests/arrowfunction-typeof.js: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@188545 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink-osrexit-default-value-tdz-error.js b/Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink-osrexit-default-value-tdz-error.js
new file mode 100644
index 0000000..c1e3a66
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink-osrexit-default-value-tdz-error.js
@@ -0,0 +1,46 @@
+"use strict";
+
+var n = 1000000;
+
+function shouldThrowTDZ(func) {
+ var hasThrown = false;
+ try {
+ func();
+ } catch(e) {
+ if (e.name.indexOf("ReferenceError") !== -1)
+ hasThrown = true;
+ }
+ if (!hasThrown)
+ throw new Error("Did not throw TDZ error");
+}
+
+function bar(f) { }
+
+function foo(b) {
+ let result = 0;
+ var set = (x) => { result = x; return tdzPerpetrator; }
+ if (b) {
+ OSRExit();
+ if (b) {
+ bar(set);
+ return tdzPerpetrator;
+ }
+ }
+ let tdzPerpetrator;
+ return result;
+}
+
+noInline(bar);
+noInline(foo);
+noInline(shouldThrowTDZ);
+
+for (var i = 0; i < n; i++) {
+ var bool = !(i % 100);
+ if (bool)
+ shouldThrowTDZ(()=> { foo(bool); });
+ else {
+ var result = foo(bool);
+ if (result != 0)
+ throw "Error: bad result: " + result;
+ }
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink-osrexit-default-value.js b/Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink-osrexit-default-value.js
new file mode 100644
index 0000000..e41bbe1
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink-osrexit-default-value.js
@@ -0,0 +1,37 @@
+var n = 1000000;
+
+function bar(set) {
+ var result = set(0);
+ if (result !== void 0)
+ throw "Error: bad value: " + result;
+}
+
+function foo(b) {
+ var result = 0;
+ var imUndefined;
+ var baz;
+ var set = (x) => {
+ result = x;
+ if (baz !== 50)
+ throw "Error: bad value: " + baz;
+ return imUndefined;
+ };
+ baz = 50;
+ if (b) {
+ OSRExit();
+ if (b) {
+ bar(set);
+ }
+ return 0;
+ }
+ return result;
+}
+
+noInline(bar);
+noInline(foo);
+
+for (var i = 0; i < n; i++) {
+ var result = foo(!(i % 100));
+ if (result != 0)
+ throw "Error: bad result: " + result;
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink-osrexit.js b/Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink-osrexit.js
new file mode 100644
index 0000000..2e437af
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink-osrexit.js
@@ -0,0 +1,25 @@
+var n = 1000000;
+
+function bar() { }
+
+function foo(b) {
+ var result = 0;
+ var set = (x) => { result = x; }
+ if (b) {
+ OSRExit();
+ if (b) {
+ bar(set);
+ }
+ return 0;
+ }
+ return result;
+}
+
+noInline(bar);
+noInline(foo);
+
+for (var i = 0; i < n; i++) {
+ var result = foo(!(i % 100));
+ if (result != 0)
+ throw "Error: bad result: " + result;
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink.js b/Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink.js
new file mode 100644
index 0000000..76a79ec
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink.js
@@ -0,0 +1,24 @@
+var n = 10000000;
+
+function bar(f) { f(10); }
+
+function foo(b) {
+ var result = 0;
+ var set = x => { result = x; }
+ if (b) {
+ bar(set);
+ if (result != 10)
+ throw "Error: bad: " + result;
+ return 0;
+ }
+ return result;
+}
+
+noInline(bar);
+noInline(foo);
+
+for (var i = 0; i < n; i++) {
+ var result = foo(!(i % 100));
+ if (result != 0)
+ throw "Error: bad result: " + result;
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-bound.js b/Source/JavaScriptCore/tests/stress/arrowfunction-bound.js
new file mode 100644
index 0000000..9203208
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-bound.js
@@ -0,0 +1,18 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+var d = {
+ x : "bar",
+ y : function() { return z => this.x + z; }
+};
+
+noInline(d.y);
+
+var e = { x : "baz" };
+
+for (var i=0; i<10000; i++) {
+ testCase(d.y().bind(e, "ley")(), "barley", "Error: function bind shouldn't change lexical binding of the arrow function");
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-call.js b/Source/JavaScriptCore/tests/stress/arrowfunction-call.js
new file mode 100644
index 0000000..6877e0a
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-call.js
@@ -0,0 +1,18 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+var d = {
+ x : "foo",
+ y : function() { return () => this.x; }
+};
+noInline(d.y);
+
+var e = { x : "bar" };
+
+for (var i=0; i<10000;i++){
+ testCase(d.y().call(e), "foo", "Error: function call shouln't change the lexical binding of the arrow function");
+ testCase(d.y().apply(e), "foo", "Error: function apply shouln't change the lexical binding of the arrow function");
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-constructor.js b/Source/JavaScriptCore/tests/stress/arrowfunction-constructor.js
new file mode 100644
index 0000000..15beb55
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-constructor.js
@@ -0,0 +1,22 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+var simpleArrowFunction = () => {};
+
+noInline(simpleArrowFunction);
+
+var errorOnCreate = false;
+
+for (i=0;i<10000;i++) {
+ try {
+ var fc = new simpleArrowFunction();
+ }
+ catch (e) {
+ errorOnCreate = true;
+ }
+
+ testCase(errorOnCreate, true, "Error: No exception during run new ArrowFunction");
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-1.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-1.js
new file mode 100644
index 0000000..4cfab24
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-1.js
@@ -0,0 +1,19 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+function Dog(name) {
+ this.name = name;
+ this.getName = () => eval("this.name");
+ this.getNameHard = () => eval("(() => this.name)()");
+}
+
+noInline(Dog)
+
+for (var i=0;i<10000; i++) {
+ var d = new Dog("Max");
+ testCase(d.getName(), d.name, "Error: this is not lexically binded inside of the arrow function #1");
+ testCase(d.getNameHard(), d.name, "Error: this is not lexically binded inside of the arrow function #2");
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-2.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-2.js
new file mode 100644
index 0000000..117db30
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-2.js
@@ -0,0 +1,39 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+var functionConstructor = function () {
+ this.func = () => this;
+};
+
+var instance = new functionConstructor();
+
+testCase(instance.func() === instance, true, "Error: this is not lexically binded inside of the arrow function #2");
+
+var obj = {
+ method: function () {
+ return () => this;
+ }
+};
+
+noInline(obj.method);
+
+for (var i=0; i < 10000; i++) {
+ testCase(obj.method()() === obj, true, "Error: this is not lexically binded inside of the arrow function #3");
+}
+
+var fake = {steal: obj.method()};
+noInline(fake.steal);
+
+for (var i=0; i < 10000; i++) {
+ testCase(fake.steal() === obj, true, "Error: this is not lexically binded inside of the arrow function #4");
+}
+
+var real = {borrow: obj.method};
+noInline(real.borrow);
+
+for (var i=0; i < 10000; i++) {
+ testCase(real.borrow()() === real, true, "Error: this is not lexically binded inside of the arrow function #5");
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-3.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-3.js
new file mode 100644
index 0000000..1019086
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-3.js
@@ -0,0 +1,28 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+
+var obj = { name:'obj', method: function () { return (value) => this.name + "-name-" + value; }};
+
+for (var i=0; i<10000; i++) {
+ testCase(obj.method()('test' + i.toString()), 'obj-name-test' + i.toString(), "Error: this is not lexically binded inside of the arrow function #1");
+}
+
+for (var i=0; i<10000; i++) {
+ var result1 = obj.method()('test' + i.toString());
+ testCase(result1, 'obj-name-test' + i.toString(), "Error: this is not lexically binded inside of the arrow function #1");
+}
+
+obj.name='newObj';
+
+for (var i=0; i<10000; i++) {
+ testCase(obj.method()('test' + i.toString()), 'newObj-name-test' + i.toString(), "Error: this is not lexically binded inside of the arrow function #5");
+}
+
+for (var i=0; i<10000; i++) {
+ var result2 = obj.method()('test' + i.toString());
+ testCase(result2, 'newObj-name-test' + i.toString(), "Error: this is not lexically binded inside of the arrow function #5");
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-4.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-4.js
new file mode 100644
index 0000000..85bd363
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-4.js
@@ -0,0 +1,26 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+
+var obj = {
+ name:'obj',
+ internalObject: {
+ name :'internalObject',
+ method: function () { return (value) => this.name + "-name-" + value; }
+ }
+};
+
+noInline(obj.internalObject.method);
+
+for (var i=0; i<10000; i++) {
+ testCase(obj.internalObject.method()('test' + i.toString()), 'internalObject-name-test' + i.toString(), "Error: this is not lexically binded inside of the arrow function #1");
+}
+
+obj.internalObject.name='newInternalObject';
+
+for (var i=0; i<10000; i++) {
+ testCase(obj.internalObject.method()('test' + i.toString()), 'newInternalObject-name-test' + i.toString(), "Error: this is not lexically binded inside of the arrow function #5");
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-5.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-5.js
new file mode 100644
index 0000000..875494c
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-5.js
@@ -0,0 +1,48 @@
+var sortedValues;
+
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+
+var obj = {
+ arr: [1, 4, 6, 3, 7, 0],
+ bubbleSort: function () {
+ return () => {
+ var tmp;
+ var ar = this.arr.slice();
+ var _length = ar.length
+ for (var i = 0; i < _length; i++) {
+ for (var j = i; j > 0; j--) {
+ if ((ar[j] - ar[j - 1]) < 0) {
+ tmp = ar[j];
+ ar[j] = ar[j - 1];
+ ar[j - 1] = tmp;
+ }
+ }
+ }
+ return ar;
+ }
+ }
+};
+
+noInline(obj.bubbleSort);
+
+for (var i=0; i<10000; i++) {
+ obj.arr = [1, 2, 4, 6, 3, 7, 0];
+ testCase(obj.bubbleSort()().length, 7, "Error: this is not lexically binded inside of the arrow function #1");
+
+ var sortedValues = obj.bubbleSort()();
+ testCase(sortedValues[0], 0, "Error: this is not lexically binded inside of the arrow function #6");
+ testCase(sortedValues[6], 7, "Error: this is not lexically binded inside of the arrow function #7");
+
+ obj.arr = [1, 2, 4, 6, 5, 8, 21, 19, 0];
+
+ testCase(obj.bubbleSort()().length, 9, "Error: this is not lexically binded inside of the arrow function #8");
+
+ sortedValues = obj.bubbleSort()();
+ testCase(sortedValues[1], 1, "Error: this is not lexically binded inside of the arrow function #12");
+ testCase(sortedValues[8], 21, "Error: this is not lexically binded inside of the arrow function #13");
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-6.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-6.js
new file mode 100644
index 0000000..c417bc7
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-6.js
@@ -0,0 +1,24 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+function Dog(name) {
+ this.name = name;
+ this.getName = () => this.name;
+ this.getNameNestingLevel1 = () => () => this.name;
+ this.getNameNestingLevel2 = () => () => () => this.name;
+}
+
+var d = new Dog("Max");
+
+noInline(d.getName());
+noInline(d.getNameNestingLevel1()());
+noInline(d.getNameNestingLevel2()()());
+
+for (var i=0;i<10000; i++) {
+ testCase(d.getName(), d.name, "Error: this is not lexically binded inside of the arrow function #1");
+ testCase(d.getNameNestingLevel1()(), d.name, "Error: this is not lexically binded inside of the arrow function #2");
+ testCase(d.getNameNestingLevel2()()(), d.name, "Error: this is not lexically binded inside of the arrow function #3");
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-activation-sink-osrexit.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-activation-sink-osrexit.js
new file mode 100644
index 0000000..ad10a31
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-activation-sink-osrexit.js
@@ -0,0 +1,34 @@
+var n = 10000000;
+
+var newContext = {
+ id : 'new-context'
+};
+
+function bar() { }
+
+function foo(b) {
+ var result = 0;
+ var set = (x) => {
+ // Check if arrow function store context
+ if (this != newContext || this.id != newContext.id)
+ throw 'Wrong context of arrow function';
+ result = x;
+ }
+ if (b) {
+ OSRExit();
+ if (b) {
+ bar(set);
+ }
+ return result;
+ }
+ return result;
+}
+
+noInline(bar);
+noInline(foo);
+
+for (var i = 0; i < n; i++) {
+ var result = foo.call(newContext, !(i % 100));
+ if (result != 0)
+ throw "Error: bad result: " + result;
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-activation-sink.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-activation-sink.js
new file mode 100644
index 0000000..ca43063
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-activation-sink.js
@@ -0,0 +1,38 @@
+var n = 10000000;
+
+var newContext = {
+ id : 'new-context'
+};
+
+function bar(f) {
+ if (this == newContext)
+ throw 'Wrong context of nesting function';
+ f(10);
+}
+
+function foo(b) {
+ var result = 0;
+ var set = (x) => {
+ result = x;
+ // Check if arrow function store context
+ if (this != newContext || this.id != newContext.id)
+ throw 'Wrong context of arrow function';
+ };
+
+ if (b) {
+ bar(set);
+ if (result != 10)
+ throw "Error: bad: " + result;
+ return 0;
+ }
+ return result;
+}
+
+noInline(bar);
+noInline(foo);
+
+for (var i = 0; i < n; i++) {
+ var result = foo.call(newContext, !(i % 100));
+ if (result != 0)
+ throw "Error: bad result: " + result;
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-sinking-no-double-allocate.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-sinking-no-double-allocate.js
new file mode 100644
index 0000000..869e027
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-sinking-no-double-allocate.js
@@ -0,0 +1,37 @@
+var newContext = {
+ id : 'new-context'
+};
+
+function call(o) { o.x = 3; }
+noInline(call);
+
+// Should be invoced by call with substitute this by newContext
+function sink (p, q) {
+ var f = () => {
+ // Check if arrow function store context
+ if (this != newContext || this.id != newContext.id)
+ throw 'Wrong context of arrow function #1';
+ };
+ if (p) {
+ call(f); // Force allocation of f
+ if (q) {
+ OSRExit();
+ }
+ return f;
+ }
+ return { 'x': 2 };
+}
+noInline(sink);
+
+for (var i = 0; i < 100000; ++i) {
+ var o = sink.call(newContext, true, false);
+ if (o.x != 3)
+ throw "Error: expected o.x to be 2 but is " + result;
+}
+
+// At this point, the arrow function should be compiled down to the FTL
+
+// Check that the function is properly allocated on OSR exit
+var f = sink(true, true);
+if (f.x != 3)
+ throw "Error: expected o.x to be 3 but is " + result;
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-sinking-osrexit.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-sinking-osrexit.js
new file mode 100644
index 0000000..7ffcb3f
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-sinking-osrexit.js
@@ -0,0 +1,36 @@
+var newContext = {
+ id : 'new-context'
+};
+
+// Should be invoced by call with substitute this by newContext
+function sink (p, q) {
+ var g = x => {
+ // Check if arrow function store context
+ if (this != newContext || this.id != newContext.id)
+ throw 'Wrong context of arrow function #1';
+ return x;
+ };
+ if (p) { if (q) OSRExit(); return g; }
+ return x => {
+ // Check if arrow function store context
+ if (this != newContext || this.id != newContext.id)
+ throw 'Wrong context of arrow function #2';
+ return x;
+ };
+}
+noInline(sink);
+
+for (var i = 0; i < 10000; ++i) {
+ var f = sink.call(newContext, true, false);// Substitute this
+ var result = f(42);
+ if (result != 42)
+ throw "Error: expected 42 but got " + result;
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Check that the function is properly allocated on OSR exit
+var f = sink.call(newContext,true, true);// Substitute this
+var result = f(42);
+if (result != 42)
+ throw "Error: expected 42 but got " + result;
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-sinking-put.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-sinking-put.js
new file mode 100644
index 0000000..057ea07
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-sinking-put.js
@@ -0,0 +1,45 @@
+var newContext = {
+ id : 'new-context'
+};
+
+// Should be invoced by call with substitute this by newContext
+function sink (p, q) {
+ var g = x => {
+ // Check if arrow function store context
+ if (this != newContext || this.id != newContext.id)
+ throw 'Wrong context of arrow function #1';
+
+ return x;
+ };
+ if (p) { if (q) g.inner = 42; return g; }
+ return x => {
+ // Check if arrow function store context
+ if (this != newContext || this.id != newContext.id)
+ throw 'Wrong context of arrow function #2';
+
+ return x;
+ };
+}
+noInline(sink);
+
+for (var i = 0; i < 10000; ++i) {
+ var f = sink.call(newContext, true, true);// use call to substitute context
+ var result = f(42);
+ if (result != 42)
+ throw "Error: expected 42 but got " + result;
+}
+
+// At this point, the arrow function should be compiled down to the FTL
+
+// Test the allocation on the implicit inner else branch
+var f = sink.call(newContext, true, false);
+var result = f(12);
+if (result != 12)
+ // This shouldn't matter as it should be either correct or completely crash
+ throw "Error: expected 12 but got " + result;
+
+// Check that the allocation did not sink beyond the property assignment
+var f = sink.call(newContext, true, true);
+var result = f.inner;
+if (result != 42)
+ throw "Error: inner should be 42 but is " + result;
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-others.js b/Source/JavaScriptCore/tests/stress/arrowfunction-others.js
new file mode 100644
index 0000000..14ce0c6
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-others.js
@@ -0,0 +1,17 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+var simpleArrowFunction = () => {};
+
+noInline(simpleArrowFunction);
+
+for (var i=0;i<10000;i++) {
+ testCase(Object.getPrototypeOf(simpleArrowFunction), Function.prototype, "Error: Not correct getPrototypeOf value for arrow function");
+
+ testCase(simpleArrowFunction instanceof Function, true, "Error: Not correct result for instanceof method for arrow function");
+
+ testCase(simpleArrowFunction.constructor == Function, true, "Error: Not correct result for constructor method of arrow functio n");
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-run-10-1.js b/Source/JavaScriptCore/tests/stress/arrowfunction-run-10-1.js
new file mode 100644
index 0000000..07a1f0a
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-run-10-1.js
@@ -0,0 +1,24 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+function run(count) {
+ var result = true;
+ for(var i=0; i<count; i++) {
+ var Obj = function (name) {
+ this.name = name;
+ this.getName = () => this.name;
+ };
+
+ var obj = new Obj("Item" + i);
+ if (obj.name !== obj.getName()) {
+ result = false;
+ }
+ }
+ return result;
+}
+
+testCase(run(1), true, "Error: Error: during execution of arrow function one time");
+testCase(run(10), true, "Error: Error: during execution of arrow function 10 times");
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-run-10-2.js b/Source/JavaScriptCore/tests/stress/arrowfunction-run-10-2.js
new file mode 100644
index 0000000..5ddcdb3
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-run-10-2.js
@@ -0,0 +1,25 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+function run(count) {
+ var result = true;
+ for(var i=0; i<count; i++) {
+ var Obj = function (name) {
+ this.name = name;
+ this.getName = () => eval("this.name");;
+ };
+
+
+ var obj = new Obj("Item" + i);
+ if (obj.name !== obj.getName()) {
+ result = false;
+ }
+ }
+ return result;
+}
+
+testCase(run(1), true, "Error: during execution of arrow function one time");
+testCase(run(10), true, "Error: during execution of arrow function 10 times");
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-run-10000-1.js b/Source/JavaScriptCore/tests/stress/arrowfunction-run-10000-1.js
new file mode 100644
index 0000000..0e5f6bc
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-run-10000-1.js
@@ -0,0 +1,23 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+function run(count) {
+ var result = true;
+ for(var i=0; i<count; i++) {
+ var Obj = function (name) {
+ this.name = name;
+ this.getName = () => this.name;
+ };
+
+ var obj = new Obj("Item" + i);
+ if (obj.name !== obj.getName()) {
+ result = false;
+ }
+ }
+ return result;
+}
+
+testCase(run(10000), true, "Error: Error: during execution of arrow function 10000 times");
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-run-10000-2.js b/Source/JavaScriptCore/tests/stress/arrowfunction-run-10000-2.js
new file mode 100644
index 0000000..dc4271f
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-run-10000-2.js
@@ -0,0 +1,23 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+function run(count) {
+ var result = true;
+ for (var i=0; i<count; i++) {
+ var Obj = function (name) {
+ this.name = name;
+ this.getName = () => eval("this.name");;
+ };
+
+ var obj = new Obj("Item" + i);
+ if (obj.name !== obj.getName()) {
+ result = false;
+ }
+ }
+ return result;
+}
+
+testCase(run(10000), true, "Error: Error: during execution of arrow function 10000 times");
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-sinking-no-double-allocate.js b/Source/JavaScriptCore/tests/stress/arrowfunction-sinking-no-double-allocate.js
new file mode 100644
index 0000000..d2862c62
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-sinking-no-double-allocate.js
@@ -0,0 +1,28 @@
+function call(o) { o.x = 3; }
+noInline(call);
+
+function sink (p, q) {
+ var f = () => { };
+ if (p) {
+ call(f); // Force allocation of f
+ if (q) {
+ OSRExit();
+ }
+ return f;
+ }
+ return { 'x': 2 };
+}
+noInline(sink);
+
+for (var i = 0; i < 100000; ++i) {
+ var o = sink(true, false);
+ if (o.x != 3)
+ throw "Error: expected o.x to be 2 but is " + result;
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Check that the function is properly allocated on OSR exit
+var f = sink(true, true);
+if (f.x != 3)
+ throw "Error: expected o.x to be 3 but is " + result;
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-sinking-osrexit.js b/Source/JavaScriptCore/tests/stress/arrowfunction-sinking-osrexit.js
new file mode 100644
index 0000000..727f3ca
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-sinking-osrexit.js
@@ -0,0 +1,21 @@
+function sink (p, q) {
+ var g = x => x;
+ if (p) { if (q) OSRExit(); return g; }
+ return x => x;
+}
+noInline(sink);
+
+for (var i = 0; i < 10000; ++i) {
+ var f = sink(true, false);
+ var result = f(42);
+ if (result != 42)
+ throw "Error: expected 42 but got " + result;
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Check that the function is properly allocated on OSR exit
+var f = sink(true, true);
+var result = f(42);
+if (result != 42)
+ throw "Error: expected 42 but got " + result;
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-sinking-put.js b/Source/JavaScriptCore/tests/stress/arrowfunction-sinking-put.js
new file mode 100644
index 0000000..8db70bb
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-sinking-put.js
@@ -0,0 +1,28 @@
+function sink (p, q) {
+ var g = x => x;
+ if (p) { if (q) g.inner = 42; return g; }
+ return x => x;
+}
+noInline(sink);
+
+for (var i = 0; i < 10000; ++i) {
+ var f = sink(true, true);
+ var result = f(42);
+ if (result != 42)
+ throw "Error: expected 42 but got " + result;
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Test the allocation on the implicit inner else branch
+var f = sink(true, false);
+var result = f(12);
+if (result != 12)
+ // This shouldn't matter as it should be either correct or completely crash
+ throw "Error: expected 12 but got " + result;
+
+// Check that the allocation did not sink beyond the property assignment
+var f = sink(true, true);
+var result = f.inner;
+if (result != 42)
+ throw "Error: inner should be 42 but is " + result;
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-tdz.js b/Source/JavaScriptCore/tests/stress/arrowfunction-tdz.js
new file mode 100644
index 0000000..6874923
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-tdz.js
@@ -0,0 +1,27 @@
+var A = class A { };
+var B = class B extends A {
+ constructor(accessThisBeforeSuper) {
+ if (accessThisBeforeSuper) {
+ var f = () => this;
+ super();
+ } else {
+ super();
+ }
+ }
+};
+
+var exception = null;
+for (var i=0; i<10000; i++) {
+ try {
+ new B(true);
+ } catch (e) {
+ exception = e;
+ if (!(e instanceof ReferenceError))
+ throw "Exception thrown was not a reference error";
+ }
+
+ if (!exception)
+ throw "Exception not thrown for an unitialized this at iteration";
+
+ var e = new B(false);
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-typeof.js b/Source/JavaScriptCore/tests/stress/arrowfunction-typeof.js
new file mode 100644
index 0000000..753ec0d
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/arrowfunction-typeof.js
@@ -0,0 +1,27 @@
+var testCase = function (actual, expected, message) {
+ if (actual !== expected) {
+ throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+ }
+};
+
+var af1 = () => {};
+var af2 = (a) => {a + 1};
+
+noInline(af1);
+noInline(af2);
+
+for (var i = 0; i < 10000; ++i) {
+ testCase(typeof af1, "function", "Error: Not correct type of the arrow function #1");
+ testCase(typeof af2, "function", "Error: Not correct type of the arrow function #2");
+
+//Fixme: Some bug in inlining typeof with following run parameters ftl-no-cjit-no-inline-validate
+// --useFTLJIT\=true --enableFunctionDotArguments\=true --enableConcurrentJIT=false --thresholdForJITAfterWarmUp=100 --validateGraph=true --maximumInliningDepth=1
+//
+// for (var i = 0; i < 10000; ++i) {
+// if (typeof (function () {}) !== 'function')
+// throw 'Wrong type';
+// }
+// testCase(typeof ()=>{}, "function", "Error: Not correct type of the arrow function #3-" + i);
+
+// testCase(typeof ((b) => {b + 1}), "function", "Error: Not correct type of the arrow function #4");
+}