[ES6] Implement ES6 arrow function syntax. Arrow function specific features. Lexical...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Aug 2015 22:24:20 +0000 (22:24 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Aug 2015 22:24:20 +0000 (22:24 +0000)
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: https://svn.webkit.org/repository/webkit/trunk@188545 268f45cc-cd09-0410-ab3c-d52691b4dbfc

125 files changed:
LayoutTests/ChangeLog
LayoutTests/js/arrowfunction-bind-expected.txt [new file with mode: 0644]
LayoutTests/js/arrowfunction-bind.html [new file with mode: 0644]
LayoutTests/js/arrowfunction-call-expected.txt [new file with mode: 0644]
LayoutTests/js/arrowfunction-call.html [new file with mode: 0644]
LayoutTests/js/arrowfunction-constructor-expected.txt [new file with mode: 0644]
LayoutTests/js/arrowfunction-constructor.html [new file with mode: 0644]
LayoutTests/js/arrowfunction-lexical-bind-this-expected.txt [new file with mode: 0644]
LayoutTests/js/arrowfunction-lexical-bind-this.html [new file with mode: 0644]
LayoutTests/js/arrowfunction-others-expected.txt [new file with mode: 0644]
LayoutTests/js/arrowfunction-others.html [new file with mode: 0644]
LayoutTests/js/arrowfunction-tdz-expected.txt [new file with mode: 0644]
LayoutTests/js/arrowfunction-tdz.html [new file with mode: 0644]
LayoutTests/js/arrowfunction-typeof-expected.txt [new file with mode: 0644]
LayoutTests/js/arrowfunction-typeof.html [new file with mode: 0644]
LayoutTests/js/regress/arrowfunction-call-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/arrowfunction-call.html [new file with mode: 0644]
LayoutTests/js/regress/script-tests/arrowfunction-call.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/function-call.js [new file with mode: 0644]
LayoutTests/js/script-tests/arrowfunction-bind.js [new file with mode: 0644]
LayoutTests/js/script-tests/arrowfunction-call.js [new file with mode: 0644]
LayoutTests/js/script-tests/arrowfunction-constructor.js [new file with mode: 0644]
LayoutTests/js/script-tests/arrowfunction-lexical-bind-this.js [new file with mode: 0644]
LayoutTests/js/script-tests/arrowfunction-others.js [new file with mode: 0644]
LayoutTests/js/script-tests/arrowfunction-tdz.js [new file with mode: 0644]
LayoutTests/js/script-tests/arrowfunction-typeof.js [new file with mode: 0644]
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/ExecutableInfo.h
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp
Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.cpp
Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.h
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp
Source/JavaScriptCore/dfg/DFGStructureRegistrationPhase.cpp
Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp
Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
Source/JavaScriptCore/ftl/FTLOperations.cpp
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/interpreter/Interpreter.h
Source/JavaScriptCore/jit/CCallHelpers.h
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITInlines.h
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.h
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/parser/ASTBuilder.h
Source/JavaScriptCore/parser/NodeConstructors.h
Source/JavaScriptCore/parser/Nodes.cpp
Source/JavaScriptCore/parser/Nodes.h
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/SyntaxChecker.h
Source/JavaScriptCore/runtime/Executable.cpp
Source/JavaScriptCore/runtime/Executable.h
Source/JavaScriptCore/runtime/JSArrowFunction.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSArrowFunction.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSFunction.h
Source/JavaScriptCore/runtime/JSFunctionInlines.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink-osrexit-default-value-tdz-error.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink-osrexit-default-value.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink-osrexit.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-bound.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-call.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-constructor.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-1.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-2.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-3.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-4.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-5.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-6.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-activation-sink-osrexit.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-activation-sink.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-sinking-no-double-allocate.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-sinking-osrexit.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-this-sinking-put.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-others.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-run-10-1.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-run-10-2.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-run-10000-1.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-run-10000-2.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-sinking-no-double-allocate.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-sinking-osrexit.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-sinking-put.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-tdz.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-typeof.js [new file with mode: 0644]

index 59e955c..c063601 100644 (file)
@@ -1,3 +1,36 @@
+2015-08-17  Skachkov Oleksandr  <gskachkov@gmail.com>
+
+        [ES6] Implement ES6 arrow function syntax. Arrow function specific features. Lexical bind of this
+        https://bugs.webkit.org/show_bug.cgi?id=144956
+
+        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.
+
 2015-08-17  Brian Burg  <bburg@apple.com>
 
         Web Inspector: split TestStub.js into multiple files and modernize it
diff --git a/LayoutTests/js/arrowfunction-bind-expected.txt b/LayoutTests/js/arrowfunction-bind-expected.txt
new file mode 100644 (file)
index 0000000..22b326c
--- /dev/null
@@ -0,0 +1,10 @@
+Tests for ES6 arrow function, this should be overwritten during invoke bind
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS d.y().bind(e, 'ley')() is 'barley'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/arrowfunction-bind.html b/LayoutTests/js/arrowfunction-bind.html
new file mode 100644 (file)
index 0000000..0b9acb2
--- /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/arrowfunction-bind.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/arrowfunction-call-expected.txt b/LayoutTests/js/arrowfunction-call-expected.txt
new file mode 100644 (file)
index 0000000..9c077f9
--- /dev/null
@@ -0,0 +1,11 @@
+Tests for ES6 arrow function, this should be overwritten during invoke call&apply
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS d.y().call(e) is 'foo'
+PASS d.y().apply(e) is 'foo'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/arrowfunction-call.html b/LayoutTests/js/arrowfunction-call.html
new file mode 100644 (file)
index 0000000..c1d8a47
--- /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/arrowfunction-call.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/arrowfunction-constructor-expected.txt b/LayoutTests/js/arrowfunction-constructor-expected.txt
new file mode 100644 (file)
index 0000000..56706ff
--- /dev/null
@@ -0,0 +1,10 @@
+Tests for ES6 arrow function no constructor
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS new simpleArrowFunction() threw exception TypeError: function is not a constructor (evaluating 'new simpleArrowFunction()').
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/arrowfunction-constructor.html b/LayoutTests/js/arrowfunction-constructor.html
new file mode 100644 (file)
index 0000000..20c0b9a
--- /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/arrowfunction-constructor.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/arrowfunction-lexical-bind-this-expected.txt b/LayoutTests/js/arrowfunction-lexical-bind-this-expected.txt
new file mode 100644 (file)
index 0000000..3b66fc2
--- /dev/null
@@ -0,0 +1,22 @@
+Tests for ES6 arrow function lexical bind of this
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS d.getName() is d.name
+PASS d.getNameHard() is d.name
+PASS d.getNameNesting()()() is d.name
+PASS obj.method()('correct') is 'objCode-name-correct'
+PASS obj.method()('correct') is 'newObjCode-name-correct'
+PASS deepObj.internalObject.method()('correct') is 'internalObject-name-correct'
+PASS deepObj.internalObject.method()('correct') is 'newInternalObject-name-correct'
+PASS instance.func() === instance is true
+PASS ownerObj.method()() === ownerObj is true
+PASS fake.steal() === ownerObj is true
+PASS real.borrow()() === real is true
+PASS arrowFunction('-this') is "right-this"
+PASS hostObj.func('-this') is "right-this"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/arrowfunction-lexical-bind-this.html b/LayoutTests/js/arrowfunction-lexical-bind-this.html
new file mode 100644 (file)
index 0000000..81ea22a
--- /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/arrowfunction-lexical-bind-this.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/arrowfunction-others-expected.txt b/LayoutTests/js/arrowfunction-others-expected.txt
new file mode 100644 (file)
index 0000000..19152e5
--- /dev/null
@@ -0,0 +1,12 @@
+Tests for ES6 arrow function instanceof and typeof operators
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Object.getPrototypeOf(simpleArrowFunction) is Function.prototype
+PASS simpleArrowFunction instanceof Function is true
+PASS simpleArrowFunction.constructor == Function is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/arrowfunction-others.html b/LayoutTests/js/arrowfunction-others.html
new file mode 100644 (file)
index 0000000..9f67f8b
--- /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/arrowfunction-others.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/arrowfunction-tdz-expected.txt b/LayoutTests/js/arrowfunction-tdz-expected.txt
new file mode 100644 (file)
index 0000000..17af6cd
--- /dev/null
@@ -0,0 +1,10 @@
+Tests for ES6 arrow function test tdz
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS isReferenceError is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/arrowfunction-tdz.html b/LayoutTests/js/arrowfunction-tdz.html
new file mode 100644 (file)
index 0000000..f8ef171
--- /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/arrowfunction-tdz.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/arrowfunction-typeof-expected.txt b/LayoutTests/js/arrowfunction-typeof-expected.txt
new file mode 100644 (file)
index 0000000..62fb2ce
--- /dev/null
@@ -0,0 +1,8 @@
+PASS typeof af1 === 'function' is true
+PASS typeof af2 === 'function' is true
+PASS typeof (()=>{}) === 'function' is true
+PASS typeof ((b) => {b + 1})==='function' is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/arrowfunction-typeof.html b/LayoutTests/js/arrowfunction-typeof.html
new file mode 100644 (file)
index 0000000..f0acaaa
--- /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/arrowfunction-typeof.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/arrowfunction-call-expected.txt b/LayoutTests/js/regress/arrowfunction-call-expected.txt
new file mode 100644 (file)
index 0000000..6eb552f
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/arrowfunction-call
+
+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/js/regress/arrowfunction-call.html b/LayoutTests/js/regress/arrowfunction-call.html
new file mode 100644 (file)
index 0000000..63d8454
--- /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/arrowfunction-call.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/script-tests/arrowfunction-call.js b/LayoutTests/js/regress/script-tests/arrowfunction-call.js
new file mode 100644 (file)
index 0000000..8924c84
--- /dev/null
@@ -0,0 +1,15 @@
+var af = (a, b) => a + b;
+
+noInline(af);
+
+function bar(a, b) {
+    return af(a, b);
+}
+
+noInline(bar);
+
+for (var i = 0; i < 1000000; ++i) {
+    var result = bar(1, 2);
+    if (result != 3)
+        throw "Error: bad result: " + result;
+}
diff --git a/LayoutTests/js/regress/script-tests/function-call.js b/LayoutTests/js/regress/script-tests/function-call.js
new file mode 100644 (file)
index 0000000..1573c3b
--- /dev/null
@@ -0,0 +1,15 @@
+var fe = function (a, b) { return a + b;}
+
+noInline(fe);
+
+function bar(a, b) {
+    return fe(a, b);
+}
+
+noInline(bar);
+
+for (var i = 0; i < 1000000; ++i) {
+    var result = bar(1, 2);
+    if (result != 3)
+        throw "Error: bad result: " + result;
+}
diff --git a/LayoutTests/js/script-tests/arrowfunction-bind.js b/LayoutTests/js/script-tests/arrowfunction-bind.js
new file mode 100644 (file)
index 0000000..153f08e
--- /dev/null
@@ -0,0 +1,12 @@
+description('Tests for ES6 arrow function, this should be overwritten during invoke bind');
+
+var d = {
+  x : "bar",
+  y : function() { return z => this.x + z; }
+};
+
+var e = { x : "baz" };
+
+shouldBe("d.y().bind(e, 'ley')()", "'barley'");
+
+var successfullyParsed = true;
diff --git a/LayoutTests/js/script-tests/arrowfunction-call.js b/LayoutTests/js/script-tests/arrowfunction-call.js
new file mode 100644 (file)
index 0000000..5c888f9
--- /dev/null
@@ -0,0 +1,13 @@
+description('Tests for ES6 arrow function, this should be overwritten during invoke call&apply');
+
+var d = {
+  x : "foo",
+  y : function() { return () => this.x; }
+};
+
+var e = { x : "bar" };
+
+shouldBe('d.y().call(e)', "'foo'");
+shouldBe('d.y().apply(e)', "'foo'");
+
+var successfullyParsed = true;
diff --git a/LayoutTests/js/script-tests/arrowfunction-constructor.js b/LayoutTests/js/script-tests/arrowfunction-constructor.js
new file mode 100644 (file)
index 0000000..aefad07
--- /dev/null
@@ -0,0 +1,7 @@
+description('Tests for ES6 arrow function no constructor');
+
+var simpleArrowFunction = () => {};
+
+shouldThrow('new simpleArrowFunction()');
+
+var successfullyParsed = true;
diff --git a/LayoutTests/js/script-tests/arrowfunction-lexical-bind-this.js b/LayoutTests/js/script-tests/arrowfunction-lexical-bind-this.js
new file mode 100644 (file)
index 0000000..2e56a15
--- /dev/null
@@ -0,0 +1,67 @@
+description('Tests for ES6 arrow function lexical bind of this');
+
+function Dog(name) {
+  this.name = name;
+  this.getName = () => eval("this.name");
+  this.getNameHard = () => eval("(() => this.name)()");
+  this.getNameNesting = () => () => () => this.name;
+}
+
+var d = new Dog("Max");
+shouldBe('d.getName()', 'd.name');
+shouldBe('d.getNameHard()', 'd.name');
+shouldBe('d.getNameNesting()()()', 'd.name');
+
+var obj = {
+  name   : 'objCode',
+  method : function () {
+    return (value) => this.name + "-name-" + value;
+  }
+};
+
+shouldBe("obj.method()('correct')", "'objCode-name-correct'");
+obj.name='newObjCode';
+shouldBe("obj.method()('correct')", "'newObjCode-name-correct'");
+
+var deepObj = {
+  name : 'wrongObjCode',
+  internalObject: {
+    name  :'internalObject',
+    method: function () { return (value) => this.name + "-name-" + value; }
+  }
+};
+shouldBe("deepObj.internalObject.method()('correct')", "'internalObject-name-correct'");
+
+deepObj.internalObject.name = 'newInternalObject';
+
+shouldBe("deepObj.internalObject.method()('correct')", "'newInternalObject-name-correct'");
+
+var functionConstructor = function () {
+  this.func = () => this;
+};
+
+var instance = new functionConstructor();
+
+shouldBe("instance.func() === instance", "true");
+
+var ownerObj = {
+  method : function () {
+    return () => this;
+  }
+};
+
+shouldBe("ownerObj.method()() === ownerObj", "true");
+
+var fake = { steal : ownerObj.method() };
+shouldBe("fake.steal() === ownerObj", "true");
+
+var real = { borrow : ownerObj.method };
+shouldBe("real.borrow()() === real", "true");
+
+var arrowFunction = { x : "right", getArrowFunction : function() { return z => this.x + z; }}.getArrowFunction();
+var hostObj = { x : "wrong", func : arrowFunction };
+
+shouldBe("arrowFunction('-this')", '"right-this"');
+shouldBe("hostObj.func('-this')", '"right-this"');
+
+var successfullyParsed = true;
diff --git a/LayoutTests/js/script-tests/arrowfunction-others.js b/LayoutTests/js/script-tests/arrowfunction-others.js
new file mode 100644 (file)
index 0000000..a79931c
--- /dev/null
@@ -0,0 +1,10 @@
+// Inspired by mozilla tests
+description('Tests for ES6 arrow function instanceof and typeof operators');
+
+var simpleArrowFunction = () => {};
+
+shouldBe("Object.getPrototypeOf(simpleArrowFunction)", "Function.prototype");
+shouldBe("simpleArrowFunction instanceof Function", "true");
+shouldBe("simpleArrowFunction.constructor == Function", "true");
+
+var successfullyParsed = true;
diff --git a/LayoutTests/js/script-tests/arrowfunction-tdz.js b/LayoutTests/js/script-tests/arrowfunction-tdz.js
new file mode 100644 (file)
index 0000000..aaf58fc
--- /dev/null
@@ -0,0 +1,26 @@
+description('Tests for ES6 arrow function test tdz');
+
+var A = class A { };
+var B = class B extends A {
+  constructor(accessThisBeforeSuper) {
+    if (accessThisBeforeSuper) {
+      var f = () => this;
+      super();
+    } else {
+      super();
+    }
+  }
+};
+
+var isReferenceError = false;
+try {
+     new B(true);
+} catch (e) {
+    isReferenceError = e instanceof ReferenceError;
+}
+
+shouldBe('isReferenceError', 'true');
+
+var e = new B(false);
+
+var successfullyParsed = true;
diff --git a/LayoutTests/js/script-tests/arrowfunction-typeof.js b/LayoutTests/js/script-tests/arrowfunction-typeof.js
new file mode 100644 (file)
index 0000000..62aa269
--- /dev/null
@@ -0,0 +1,12 @@
+var af1 = () => {};
+var af2 = (a) => {a + 1};
+
+shouldBe("typeof af1 === 'function'", "true");
+
+shouldBe("typeof af2 === 'function'", "true");
+
+shouldBe("typeof (()=>{}) === 'function'", "true");
+
+shouldBe("typeof ((b) => {b + 1})==='function'", "true");
+
+var successfullyParsed = true;
index 16b6697..a0e0878 100644 (file)
@@ -510,6 +510,7 @@ set(JavaScriptCore_RUNTIME_SOURCES
     runtime/JSArrayBufferPrototype.cpp
     runtime/JSArrayBufferView.cpp
     runtime/JSArrayIterator.cpp
+    runtime/JSArrowFunction.cpp
     runtime/JSBoundFunction.cpp
     runtime/JSCJSValue.cpp
     runtime/JSCallee.cpp
index 1f5dd63..959223b 100644 (file)
@@ -1,3 +1,192 @@
+2015-08-17 Aleksandr Skachkov   <gskachkov@gmail.com>
+
+        [ES6] Implement ES6 arrow function syntax. Arrow function specific features. Lexical bind of this
+        https://bugs.webkit.org/show_bug.cgi?id=144956
+
+        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.
+
 2015-07-28  Sam Weinig  <sam@webkit.org>
 
         Cleanup the builtin JavaScript files
index 01d837f..ac39ea1 100644 (file)
     <ClCompile Include="..\runtime\JSArrayBufferPrototype.cpp" />
     <ClCompile Include="..\runtime\JSArrayBufferView.cpp" />
     <ClCompile Include="..\runtime\JSBoundFunction.cpp" />
+    <ClCompile Include="..\runtime\JSArrowFunction.cpp" />
     <ClCompile Include="..\runtime\JSCJSValue.cpp" />
     <ClCompile Include="..\runtime\JSCallee.cpp" />
     <ClCompile Include="..\runtime\JSCell.cpp" />
     <ClInclude Include="..\runtime\JSArrayBufferViewInlines.h" />
     <ClInclude Include="..\runtime\JSArrayIterator.h" />
     <ClInclude Include="..\runtime\JSBoundFunction.h" />
+    <ClInclude Include="..\runtime\JSArrowFunction.h" />
     <ClInclude Include="..\runtime\JSCInlines.h" />
     <ClInclude Include="..\runtime\JSCJSValue.h" />
     <ClInclude Include="..\runtime\JSCJSValueInlines.h" />
index ce1ab24..6d0fef8 100644 (file)
     <ClInclude Include="..\runtime\JSArray.h">
       <Filter>runtime</Filter>
     </ClInclude>
+    <ClInclude Include="..\runtime\JSArrowFunction.h">
+      <Filter>runtime</Filter>
+    </ClInclude>
     <ClInclude Include="..\runtime\JSBoundFunction.h">
       <Filter>runtime</Filter>
     </ClInclude>
index fdc6837..33ca329 100644 (file)
                86F3EEBF168CDE930077B92A /* ObjcRuntimeExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = 86F3EEB616855A5B0077B92A /* ObjcRuntimeExtras.h */; };
                86FA9E91142BBB2E001773B7 /* JSBoundFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86FA9E8F142BBB2D001773B7 /* JSBoundFunction.cpp */; };
                86FA9E92142BBB2E001773B7 /* JSBoundFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 86FA9E90142BBB2E001773B7 /* JSBoundFunction.h */; };
+               8B0F424C1ABD6DE2003917EA /* JSArrowFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8B0F424B1ABD6DE2003917EA /* JSArrowFunction.cpp */; };
+               8B14186D1B62527F00FB2068 /* JSArrowFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B0F424A1ABD6D2F003917EA /* JSArrowFunction.h */; settings = {ATTRIBUTES = (Private, ); }; };
                90213E3D123A40C200D422F3 /* MemoryStatistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90213E3B123A40C200D422F3 /* MemoryStatistics.cpp */; };
                90213E3E123A40C200D422F3 /* MemoryStatistics.h in Headers */ = {isa = PBXBuildFile; fileRef = 90213E3C123A40C200D422F3 /* MemoryStatistics.h */; settings = {ATTRIBUTES = (Private, ); }; };
                93052C340FB792190048FDC3 /* ParserArena.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93052C320FB792190048FDC3 /* ParserArena.cpp */; };
                86F75EFD151C062F007C9BA3 /* RegExpMatchesArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegExpMatchesArray.cpp; sourceTree = "<group>"; };
                86FA9E8F142BBB2D001773B7 /* JSBoundFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSBoundFunction.cpp; sourceTree = "<group>"; };
                86FA9E90142BBB2E001773B7 /* JSBoundFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBoundFunction.h; sourceTree = "<group>"; };
+               8B0F424A1ABD6D2F003917EA /* JSArrowFunction.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSArrowFunction.h; sourceTree = "<group>"; };
+               8B0F424B1ABD6DE2003917EA /* JSArrowFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSArrowFunction.cpp; sourceTree = "<group>"; };
                90213E3B123A40C200D422F3 /* MemoryStatistics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryStatistics.cpp; sourceTree = "<group>"; };
                90213E3C123A40C200D422F3 /* MemoryStatistics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryStatistics.h; sourceTree = "<group>"; };
                93052C320FB792190048FDC3 /* ParserArena.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParserArena.cpp; sourceTree = "<group>"; };
                                A7BDAEC517F4EA1400F6140C /* JSArrayIterator.h */,
                                86FA9E8F142BBB2D001773B7 /* JSBoundFunction.cpp */,
                                86FA9E90142BBB2E001773B7 /* JSBoundFunction.h */,
+                               8B0F424B1ABD6DE2003917EA /* JSArrowFunction.cpp */,
+                               8B0F424A1ABD6D2F003917EA /* JSArrowFunction.h */,
                                657CF45619BF6662004ACBF2 /* JSCallee.cpp */,
                                657CF45719BF6662004ACBF2 /* JSCallee.h */,
                                BC7F8FBA0E19D1EF008632C0 /* JSCell.cpp */,
                                A503FA26188EFFFD00110F14 /* ScriptDebugServer.h in Headers */,
                                A55D93A6185012A800400DED /* ScriptFunctionCall.h in Headers */,
                                A54CF2FA184EAEDA00237F19 /* ScriptObject.h in Headers */,
+                               8B14186D1B62527F00FB2068 /* JSArrowFunction.h in Headers */,
                                A54CF2F6184EAB2400237F19 /* ScriptValue.h in Headers */,
                                A7299DA617D12858005F5FF9 /* SetConstructor.h in Headers */,
                                A790DD6E182F499700588807 /* SetIteratorPrototype.h in Headers */,
                                0FF2CD5B1B61A4F8004955A8 /* DFGMultiGetByOffsetData.cpp in Sources */,
                                0F235BDC17178E1C00690C7F /* FTLOSRExit.cpp in Sources */,
                                0F235BDF17178E1C00690C7F /* FTLOSRExitCompiler.cpp in Sources */,
+                               8B0F424C1ABD6DE2003917EA /* JSArrowFunction.cpp in Sources */,
                                0FEA0A2A1709629600BB722C /* FTLOutput.cpp in Sources */,
                                0F485329187DFDEC0083B687 /* FTLRecoveryOpcode.cpp in Sources */,
                                0F6B1CC31862C47800845D97 /* FTLRegisterAtOffset.cpp in Sources */,
index 704cfda..4e5a96c 100644 (file)
@@ -94,6 +94,7 @@
             { "name" : "op_switch_string", "length" : 4 },
             { "name" : "op_new_func", "length" : 4 },
             { "name" : "op_new_func_exp", "length" : 4 },
+            { "name" : "op_new_arrow_func_exp", "length" : 5 },
             { "name" : "op_call", "length" : 9 },
             { "name" : "op_call_eval", "length" : 9 },
             { "name" : "op_call_varargs", "length" : 9 },
             { "name" : "op_get_property_enumerator", "length" : 3 },
             { "name" : "op_enumerator_structure_pname", "length" : 4 },
             { "name" : "op_enumerator_generic_pname", "length" : 4 },
-            { "name" : "op_to_index_string", "length" : 3 }
+            { "name" : "op_to_index_string", "length" : 3 },
+            { "name" : "op_load_arrowfunction_this", "length" : 2 }
         ]
     },
     {
index f3174e9..f92267c 100644 (file)
@@ -55,6 +55,7 @@ void computeUsesForBytecodeOffset(
     case op_create_out_of_band_arguments:
         return;
     case op_get_scope:
+    case op_load_arrowfunction_this:
     case op_to_this:
     case op_check_tdz:
     case op_profile_will_call:
@@ -119,6 +120,7 @@ void computeUsesForBytecodeOffset(
     case op_get_property_enumerator:
     case op_get_enumerable_length:
     case op_new_func_exp:
+    case op_new_arrow_func_exp:
     case op_to_index_string:
     case op_create_lexical_environment:
     case op_resolve_scope:
@@ -309,6 +311,7 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset,
     case op_new_regexp:
     case op_new_func:
     case op_new_func_exp:
+    case op_new_arrow_func_exp:
     case op_call_varargs:
     case op_construct_varargs:
     case op_get_from_scope:
@@ -362,6 +365,7 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset,
     case op_to_this:
     case op_check_tdz:
     case op_get_scope:
+    case op_load_arrowfunction_this:
     case op_create_direct_arguments:
     case op_create_scoped_arguments:
     case op_create_out_of_band_arguments:
index a7a05da..5de417e 100644 (file)
@@ -757,6 +757,11 @@ void CodeBlock::dumpBytecode(
             printLocationOpAndRegisterOperand(out, exec, location, it, "get_scope", r0);
             break;
         }
+        case op_load_arrowfunction_this: {
+            int r0 = (++it)->u.operand;
+            printLocationOpAndRegisterOperand(out, exec, location, it, "load_arrowfunction_this", r0);
+            break;
+        }
         case op_create_direct_arguments: {
             int r0 = (++it)->u.operand;
             printLocationAndOp(out, exec, location, it, "create_direct_arguments");
@@ -1289,6 +1294,15 @@ void CodeBlock::dumpBytecode(
             out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
             break;
         }
+        case op_new_arrow_func_exp: {
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            int f0 = (++it)->u.operand;
+            int r2 = (++it)->u.operand;
+            printLocationAndOp(out, exec, location, it, "op_new_arrow_func_exp");
+            out.printf("%s, %s, f%d, %s", registerName(r0).data(), registerName(r1).data(), f0, registerName(r2).data());
+            break;
+        }
         case op_new_func_exp: {
             int r0 = (++it)->u.operand;
             int r1 = (++it)->u.operand;
index c56a770..92144f8 100644 (file)
 namespace JSC {
 
 struct ExecutableInfo {
-    ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind)
+    ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind, bool isArrowFunction)
         : m_needsActivation(needsActivation)
         , m_usesEval(usesEval)
         , m_isStrictMode(isStrictMode)
         , m_isConstructor(isConstructor)
         , m_isBuiltinFunction(isBuiltinFunction)
         , m_constructorKind(static_cast<unsigned>(constructorKind))
+        , m_isArrowFunction(isArrowFunction)
     {
         ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind));
     }
@@ -48,6 +49,7 @@ struct ExecutableInfo {
     bool isConstructor() const { return m_isConstructor; }
     bool isBuiltinFunction() const { return m_isBuiltinFunction; }
     ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
+    bool isArrowFunction() const { return m_isArrowFunction; }
 
 private:
     unsigned m_needsActivation : 1;
@@ -56,6 +58,7 @@ private:
     unsigned m_isConstructor : 1;
     unsigned m_isBuiltinFunction : 1;
     unsigned m_constructorKind : 2;
+    unsigned m_isArrowFunction : 1;
 };
 
 } // namespace JSC
index 73959cf..574b1e4 100644 (file)
@@ -64,6 +64,7 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType code
     , m_hasCapturedVariables(false)
     , m_isBuiltinFunction(info.isBuiltinFunction())
     , m_constructorKind(static_cast<unsigned>(info.constructorKind()))
+    , m_isArrowFunction(info.isArrowFunction())
     , m_firstLine(0)
     , m_lineCount(0)
     , m_endColumn(UINT_MAX)
index 552ed84..322d261 100644 (file)
@@ -118,6 +118,7 @@ public:
     bool isConstructor() const { return m_isConstructor; }
     bool isStrictMode() const { return m_isStrictMode; }
     bool usesEval() const { return m_usesEval; }
+    bool isArrowFunction() const { return m_isArrowFunction; }
 
     bool needsFullScopeChain() const { return m_needsFullScopeChain; }
 
@@ -391,6 +392,7 @@ private:
     unsigned m_hasCapturedVariables : 1;
     unsigned m_isBuiltinFunction : 1;
     unsigned m_constructorKind : 2;
+    unsigned m_isArrowFunction : 1;
 
     unsigned m_firstLine;
     unsigned m_lineCount;
index 1891cb8..e935ed8 100644 (file)
@@ -50,7 +50,7 @@ const ClassInfo UnlinkedFunctionExecutable::s_info = { "UnlinkedFunctionExecutab
 static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(
     VM& vm, UnlinkedFunctionExecutable* executable, const SourceCode& source,
     CodeSpecializationKind kind, DebuggerMode debuggerMode, ProfilerMode profilerMode,
-    UnlinkedFunctionKind functionKind, ParserError& error)
+    UnlinkedFunctionKind functionKind, ParserError& error, bool isArrowFunction)
 {
     JSParserBuiltinMode builtinMode = executable->isBuiltinFunction() ? JSParserBuiltinMode::Builtin : JSParserBuiltinMode::NotBuiltin;
     JSParserStrictMode strictMode = executable->isInStrictContext() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict;
@@ -67,7 +67,7 @@ static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(
     executable->recordParse(function->features(), function->hasCapturedVariables());
     
     UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(&vm, FunctionCode,
-        ExecutableInfo(function->needsActivation(), function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind()));
+        ExecutableInfo(function->needsActivation(), function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind(), isArrowFunction));
     auto generator(std::make_unique<BytecodeGenerator>(vm, function.get(), result, debuggerMode, profilerMode, executable->parentScopeTDZVariables()));
     error = generator->generate();
     if (error.isValid())
@@ -99,6 +99,7 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct
     , m_constructAbility(static_cast<unsigned>(constructAbility))
     , m_constructorKind(static_cast<unsigned>(node->constructorKind()))
     , m_functionMode(node->functionMode())
+    , m_isArrowFunction(node->isArrowFunction())
 {
     ASSERT(m_constructorKind == static_cast<unsigned>(node->constructorKind()));
     m_parentScopeTDZVariables.swap(parentScopeTDZVariables);
@@ -179,7 +180,7 @@ UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode(
 
 UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(
     VM& vm, const SourceCode& source, CodeSpecializationKind specializationKind, 
-    DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
+    DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error, bool isArrowFunction)
 {
     switch (specializationKind) {
     case CodeForCall:
@@ -195,7 +196,7 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::codeBlockFor(
     UnlinkedFunctionCodeBlock* result = generateFunctionCodeBlock(
         vm, this, source, specializationKind, debuggerMode, profilerMode, 
         isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, 
-        error);
+        error, isArrowFunction);
     
     if (error.isValid())
         return nullptr;
index 6eae9f0..4e054b2 100644 (file)
@@ -94,7 +94,7 @@ public:
 
     UnlinkedFunctionCodeBlock* codeBlockFor(
         VM&, const SourceCode&, CodeSpecializationKind, DebuggerMode, ProfilerMode, 
-        ParserError&);
+        ParserError&, bool);
 
     static UnlinkedFunctionExecutable* fromGlobalCode(
         const Identifier&, ExecState&, const SourceCode&, JSObject*& exception, 
@@ -124,6 +124,7 @@ public:
     ConstructAbility constructAbility() const { return static_cast<ConstructAbility>(m_constructAbility); }
     bool isClassConstructorFunction() const { return constructorKind() != ConstructorKind::None; }
     const VariableEnvironment* parentScopeTDZVariables() const { return &m_parentScopeTDZVariables; }
+    bool isArrowFunction() const { return m_isArrowFunction; }
 
 private:
     UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, VariableEnvironment&);
@@ -156,6 +157,7 @@ private:
     unsigned m_constructAbility: 1;
     unsigned m_constructorKind : 2;
     unsigned m_functionMode : 1; // FunctionMode
+    unsigned m_isArrowFunction : 1;
 
 protected:
     void finishCreation(VM& vm)
index 364e921..12b9798 100644 (file)
@@ -470,20 +470,25 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     }
 
     m_newTargetRegister = addVar();
-    if (isConstructor()) {
-        emitMove(m_newTargetRegister, &m_thisRegister);
-        if (constructorKind() == ConstructorKind::Derived) {
-            emitMoveEmptyValue(&m_thisRegister);
-        } else
-            emitCreateThis(&m_thisRegister);
-    } else if (constructorKind() != ConstructorKind::None) {
-        emitThrowTypeError("Cannot call a class constructor");
-    } else if (functionNode->usesThis() || codeBlock->usesEval()) {
-        m_codeBlock->addPropertyAccessInstruction(instructions().size());
-        emitOpcode(op_to_this);
-        instructions().append(kill(&m_thisRegister));
-        instructions().append(0);
-        instructions().append(0);
+    if (!codeBlock->isArrowFunction()) {
+        if (isConstructor()) {
+            emitMove(m_newTargetRegister, &m_thisRegister);
+            if (constructorKind() == ConstructorKind::Derived)
+                emitMoveEmptyValue(&m_thisRegister);
+            else
+                emitCreateThis(&m_thisRegister);
+        } else if (constructorKind() != ConstructorKind::None) {
+            emitThrowTypeError("Cannot call a class constructor");
+        } else if (functionNode->usesThis() || codeBlock->usesEval()) {
+            m_codeBlock->addPropertyAccessInstruction(instructions().size());
+            emitOpcode(op_to_this);
+            instructions().append(kill(&m_thisRegister));
+            instructions().append(0);
+            instructions().append(0);
+        }
+    } else {
+        if (functionNode->usesThis() || codeBlock->usesEval())
+            emitLoadArrowFunctionThis(&m_thisRegister);
     }
 
     // All "addVar()"s needs to happen before "initializeDefaultParameterValuesAndSetupFunctionScopeStack()" is called
@@ -2257,16 +2262,37 @@ RegisterID* BytecodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp)
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n)
+void BytecodeGenerator::emitNewFunctionCommon(RegisterID* dst, BaseFuncExprNode* func, OpcodeID opcodeID)
 {
-    FunctionMetadataNode* metadata = n->metadata();
-    unsigned index = m_codeBlock->addFunctionExpr(makeFunction(metadata));
 
-    emitOpcode(op_new_func_exp);
-    instructions().append(r0->index());
+    ASSERT(opcodeID == op_new_func_exp || opcodeID == op_new_arrow_func_exp);
+    
+    FunctionMetadataNode* function = func->metadata();
+    unsigned index = m_codeBlock->addFunctionExpr(makeFunction(function));
+    
+    emitOpcode(opcodeID);
+    instructions().append(dst->index());
     instructions().append(scopeRegister()->index());
     instructions().append(index);
-    return r0;
+    
+    if (opcodeID == op_new_arrow_func_exp)
+        instructions().append(thisRegister()->index());
+}
+
+RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func)
+{
+    emitNewFunctionCommon(dst, func, op_new_func_exp);
+    return dst;
+}
+
+RegisterID* BytecodeGenerator::emitNewArrowFunctionExpression(RegisterID* dst, ArrowFuncExprNode* func)
+{
+    bool isClassConstructor = m_codeBlock->isConstructor() && constructorKind() != ConstructorKind::None;
+    if (isClassConstructor)
+        emitTDZCheck(thisRegister());
+    
+    emitNewFunctionCommon(dst, func, op_new_arrow_func_exp);
+    return dst;
 }
 
 RegisterID* BytecodeGenerator::emitNewDefaultConstructor(RegisterID* dst, ConstructorKind constructorKind, const Identifier& name)
@@ -2842,6 +2868,13 @@ void BytecodeGenerator::allocateAndEmitScope()
     emitMove(m_topMostScope, scopeRegister());
 }
 
+RegisterID* BytecodeGenerator::emitLoadArrowFunctionThis(RegisterID* arrowFunctionThis)
+{
+    emitOpcode(op_load_arrowfunction_this);
+    instructions().append(arrowFunctionThis->index());
+    return arrowFunctionThis;
+}
+    
 void BytecodeGenerator::emitComplexPopScopes(RegisterID* scope, ControlFlowContext* topScope, ControlFlowContext* bottomScope)
 {
     while (topScope > bottomScope) {
index 1d6ce13..d7f1b1f 100644 (file)
@@ -481,6 +481,8 @@ namespace JSC {
         RegisterID* emitNewFunctionInternal(RegisterID* dst, unsigned index);
         RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func);
         RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name);
+        void emitNewFunctionCommon(RegisterID*, BaseFuncExprNode*, OpcodeID);
+        RegisterID* emitNewArrowFunctionExpression(RegisterID*, ArrowFuncExprNode*);
         RegisterID* emitNewRegExp(RegisterID* dst, RegExp*);
 
         RegisterID* emitMoveLinkTimeConstant(RegisterID* dst, LinkTimeConstant);
@@ -663,6 +665,7 @@ namespace JSC {
         ALWAYS_INLINE void rewindUnaryOp();
 
         void allocateAndEmitScope();
+        RegisterID* emitLoadArrowFunctionThis(RegisterID*);
         void emitComplexPopScopes(RegisterID*, ControlFlowContext* topScope, ControlFlowContext* bottomScope);
 
         typedef HashMap<double, JSValue> NumberMap;
index 23427f1..41ae7fe 100644 (file)
@@ -2955,6 +2955,13 @@ RegisterID* FuncExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID*
     return generator.emitNewFunctionExpression(generator.finalDestination(dst), this);
 }
 
+// ------------------------------ ArrowFuncExprNode ---------------------------------
+
+RegisterID* ArrowFuncExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+{
+    return generator.emitNewArrowFunctionExpression(generator.finalDestination(dst), this);
+}
+    
 #if ENABLE(ES6_CLASS_SYNTAX)
 // ------------------------------ ClassDeclNode ---------------------------------
 
index 9325348..1bd8f69 100644 (file)
@@ -1682,7 +1682,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
     case CreateClonedArguments:
         forNode(node).setType(m_graph, SpecObjectOther);
         break;
-        
+            
+    case NewArrowFunction:
+        forNode(node).set(
+            m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->arrowFunctionStructure());
+        break;
+            
     case NewFunction:
         forNode(node).set(
             m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->functionStructure());
@@ -1743,6 +1748,15 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         forNode(node).setType(m_graph, SpecObjectOther);
         break;
 
+    case LoadArrowFunctionThis:
+        if (JSValue base = forNode(node->child1()).m_value) {
+            JSArrowFunction* function = jsDynamicCast<JSArrowFunction*>(base);
+            setConstant(node, *m_graph.freeze(function->boundThis()));
+            break;
+        }
+        forNode(node).setType(m_graph, SpecFinalObject);
+        break;
+            
     case SkipScope: {
         JSValue child = forNode(node->child1()).value();
         if (child) {
index a56337c..53e1bef 100644 (file)
@@ -4079,6 +4079,17 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             set(VirtualRegister(currentInstruction[1].u.operand), result);
             NEXT_OPCODE(op_get_scope);
         }
+
+        case op_load_arrowfunction_this: {
+            Node* callee = get(VirtualRegister(JSStack::Callee));
+            Node* result;
+            if (JSArrowFunction* function = callee->dynamicCastConstant<JSArrowFunction*>())
+                result = jsConstant(function->boundThis());
+            else
+                result = addToGraph(LoadArrowFunctionThis, callee);
+            set(VirtualRegister(currentInstruction[1].u.operand), result);
+            NEXT_OPCODE(op_load_arrowfunction_this);
+        }
             
         case op_create_direct_arguments: {
             noticeArgumentsUse();
@@ -4136,6 +4147,18 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             NEXT_OPCODE(op_new_func_exp);
         }
 
+        case op_new_arrow_func_exp: {
+            FunctionExecutable* expr = m_inlineStackTop->m_profiledBlock->functionExpr(currentInstruction[3].u.operand);
+            FrozenValue* frozen = m_graph.freezeStrong(expr);
+
+            set(VirtualRegister(currentInstruction[1].u.operand),
+                addToGraph(NewArrowFunction, OpInfo(frozen),
+                    get(VirtualRegister(currentInstruction[2].u.operand)),
+                    get(VirtualRegister(currentInstruction[4].u.operand))));
+            
+            NEXT_OPCODE(op_new_arrow_func_exp);
+        }
+
         case op_typeof: {
             set(VirtualRegister(currentInstruction[1].u.operand),
                 addToGraph(TypeOf, get(VirtualRegister(currentInstruction[2].u.operand))));
index f9b5e77..7f54308 100644 (file)
@@ -193,6 +193,7 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
     case op_switch_char:
     case op_in:
     case op_get_scope:
+    case op_load_arrowfunction_this:
     case op_get_from_scope:
     case op_get_enumerable_length:
     case op_has_generic_property:
@@ -205,6 +206,7 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
     case op_to_index_string:
     case op_new_func:
     case op_new_func_exp:
+    case op_new_arrow_func_exp:
     case op_create_lexical_environment:
     case op_get_parent_scope:
         return CanCompileAndInline;
index 85c57e5..7727a9e 100644 (file)
@@ -139,6 +139,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case ArithCos:
     case ArithLog:
     case GetScope:
+    case LoadArrowFunctionThis:
     case SkipScope:
     case StringCharCodeAt:
     case StringFromCharCode:
@@ -958,7 +959,8 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         read(HeapObjectCount);
         write(HeapObjectCount);
         return;
-        
+    
+    case NewArrowFunction:
     case NewFunction:
         if (node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid())
             write(Watchpoint_fire);
index e470b8d..3547332 100644 (file)
@@ -99,6 +99,7 @@ bool doesGC(Graph& graph, Node* node)
     case GetButterfly:
     case CheckArray:
     case GetScope:
+    case LoadArrowFunctionThis:
     case SkipScope:
     case GetClosureVar:
     case PutClosureVar:
@@ -229,6 +230,7 @@ bool doesGC(Graph& graph, Node* node)
     case NewRegexp:
     case NewStringObject:
     case MakeRope:
+    case NewArrowFunction:
     case NewFunction:
     case NewTypedArray:
     case ThrowReferenceError:
index da76e7a..0ab3938 100644 (file)
@@ -948,7 +948,12 @@ private:
             speculateForBarrier(node->child2());
             break;
         }
-            
+
+        case LoadArrowFunctionThis: {
+            fixEdge<KnownCellUse>(node->child1());
+            break;
+        }
+
         case SkipScope:
         case GetScope:
         case GetGetter:
@@ -1271,7 +1276,13 @@ private:
             fixEdge<CellUse>(node->child1());
             break;
         }
-            
+
+        case NewArrowFunction: {
+            fixEdge<CellUse>(node->child1());
+            fixEdge<CellUse>(node->child2());
+            break;
+        }
+
 #if !ASSERT_DISABLED
         // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
         case SetArgument:
index 83fcf5c..306327a 100644 (file)
@@ -580,7 +580,7 @@ struct Node {
 
     void convertToPhantomNewFunction()
     {
-        ASSERT(m_op == NewFunction);
+        ASSERT(m_op == NewFunction || m_op == NewArrowFunction);
         m_op = PhantomNewFunction;
         m_flags |= NodeMustGenerate;
         m_opInfo = 0;
@@ -1280,6 +1280,7 @@ struct Node {
         switch (op()) {
         case CheckCell:
         case NewFunction:
+        case NewArrowFunction:
         case CreateActivation:
         case MaterializeCreateActivation:
             return true;
@@ -1496,6 +1497,7 @@ struct Node {
     bool isFunctionAllocation()
     {
         switch (op()) {
+        case NewArrowFunction:
         case NewFunction:
             return true;
         default:
index e9bf727..74aa984 100644 (file)
@@ -197,6 +197,7 @@ namespace JSC { namespace DFG {
     macro(MultiPutByOffset, NodeMustGenerate) \
     macro(GetArrayLength, NodeResultInt32) \
     macro(GetTypedArrayByteOffset, NodeResultInt32) \
+    macro(LoadArrowFunctionThis, NodeResultJS) \
     macro(GetScope, NodeResultJS) \
     macro(SkipScope, NodeResultJS) \
     macro(GetClosureVar, NodeResultJS) \
@@ -294,6 +295,8 @@ namespace JSC { namespace DFG {
     \
     macro(NewFunction, NodeResultJS) \
     \
+    macro(NewArrowFunction, NodeResultJS) \
+    \
     /* These aren't terminals but always exit */ \
     macro(Throw, NodeMustGenerate) \
     macro(ThrowReferenceError, NodeMustGenerate) \
index 3e21c4a..f6f4919 100644 (file)
@@ -138,7 +138,7 @@ public:
     // once it is escaped if it still has pointers to it in order to
     // replace any use of those pointers by the corresponding
     // materialization
-    enum class Kind { Escaped, Object, Activation, Function };
+    enum class Kind { Escaped, Object, Activation, Function, NewArrowFunction };
 
     explicit Allocation(Node* identifier = nullptr, Kind kind = Kind::Escaped)
         : m_identifier(identifier)
@@ -232,7 +232,12 @@ public:
 
     bool isFunctionAllocation() const
     {
-        return m_kind == Kind::Function;
+        return m_kind == Kind::Function || m_kind == Kind::NewArrowFunction;
+    }
+    
+    bool isArrowFunctionAllocation() const
+    {
+        return m_kind == Kind::NewArrowFunction;
     }
 
     bool operator==(const Allocation& other) const
@@ -267,6 +272,10 @@ public:
         case Kind::Function:
             out.print("Function");
             break;
+                
+        case Kind::NewArrowFunction:
+            out.print("NewArrowFunction");
+            break;
 
         case Kind::Activation:
             out.print("Activation");
@@ -840,14 +849,19 @@ private:
             break;
         }
 
-        case NewFunction: {
+        case NewFunction:
+        case NewArrowFunction: {
+            bool isArrowFunction = node->op() == NewArrowFunction;
             if (node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid()) {
                 m_heap.escape(node->child1().node());
                 break;
             }
-            target = &m_heap.newAllocation(node, Allocation::Kind::Function);
+            
+            target = &m_heap.newAllocation(node, isArrowFunction ? Allocation::Kind::NewArrowFunction : Allocation::Kind::Function);
             writes.add(FunctionExecutablePLoc, LazyNode(node->cellOperand()));
             writes.add(FunctionActivationPLoc, LazyNode(node->child1().node()));
+            if (isArrowFunction)
+                writes.add(ArrowFunctionBoundThisPLoc, LazyNode(node->child2().node()));
             break;
         }
 
@@ -1034,6 +1048,14 @@ private:
                 m_heap.escape(node->child1().node());
             break;
 
+        case LoadArrowFunctionThis:
+            target = m_heap.onlyLocalAllocation(node->child1().node());
+            if (target && target->isArrowFunctionAllocation())
+                exactRead = ArrowFunctionBoundThisPLoc;
+            else
+                m_heap.escape(node->child1().node());
+            break;
+        
         case GetScope:
             target = m_heap.onlyLocalAllocation(node->child1().node());
             if (target && target->isFunctionAllocation())
@@ -1467,11 +1489,14 @@ private:
                 OpInfo(set), OpInfo(data), 0, 0);
         }
 
+        case Allocation::Kind::NewArrowFunction:
         case Allocation::Kind::Function: {
             FrozenValue* executable = allocation.identifier()->cellOperand();
-
+            
+            NodeType nodeType = allocation.kind() == Allocation::Kind::NewArrowFunction ? NewArrowFunction : NewFunction;
+            
             return m_graph.addNode(
-                allocation.identifier()->prediction(), NewFunction,
+                allocation.identifier()->prediction(), nodeType,
                 NodeOrigin(
                     allocation.identifier()->origin.semantic,
                     where->origin.forExit),
@@ -1775,6 +1800,7 @@ private:
                         node->convertToPhantomNewObject();
                         break;
 
+                    case NewArrowFunction:
                     case NewFunction:
                         node->convertToPhantomNewFunction();
                         break;
@@ -2025,18 +2051,27 @@ private:
                 firstChild, m_graph.m_varArgChildren.size() - firstChild);
             break;
         }
-
-        case NewFunction: {
+        
+        case NewFunction:
+        case NewArrowFunction: {
+            bool isArrowFunction = node->op() == NewArrowFunction;
             Vector<PromotedHeapLocation> locations = m_locationsForAllocation.get(escapee);
-            ASSERT(locations.size() == 2);
-
+            ASSERT(locations.size() == (isArrowFunction ? 3 : 2));
+                
             PromotedHeapLocation executable(FunctionExecutablePLoc, allocation.identifier());
             ASSERT_UNUSED(executable, locations.contains(executable));
-
+                
             PromotedHeapLocation activation(FunctionActivationPLoc, allocation.identifier());
             ASSERT(locations.contains(activation));
 
             node->child1() = Edge(resolve(block, activation), KnownCellUse);
+            
+            if (isArrowFunction) {
+                PromotedHeapLocation boundThis(ArrowFunctionBoundThisPLoc, allocation.identifier());
+                ASSERT(locations.contains(boundThis));
+                node->child2() = Edge(resolve(block, boundThis), CellUse);
+            }
+            
             break;
         }
 
index 36f2df7..355735f 100644 (file)
@@ -215,6 +215,7 @@ private:
         case GetGetter:
         case GetSetter:
         case GetCallee:
+        case NewArrowFunction:
         case NewFunction: {
             changed |= setPrediction(SpecFunction);
             break;
@@ -585,11 +586,15 @@ private:
             // These don't get inserted until we go into SSA.
             RELEASE_ASSERT_NOT_REACHED();
             break;
-
+    
         case GetScope:
             changed |= setPrediction(SpecObjectOther);
             break;
-            
+
+        case LoadArrowFunctionThis:
+            changed |= setPrediction(SpecFinalObject);
+            break;
+
         case In:
             changed |= setPrediction(SpecBoolean);
             break;
index 24f6977..8fe1591 100644 (file)
@@ -102,6 +102,10 @@ void printInternal(PrintStream& out, PromotedLocationKind kind)
     case ClosureVarPLoc:
         out.print("ClosureVarPLoc");
         return;
+
+    case ArrowFunctionBoundThisPLoc:
+        out.print("ArrowFunctionBoundThisPLoc");
+        return;
     }
     
     RELEASE_ASSERT_NOT_REACHED();
index a21e4da..97293f3 100644 (file)
@@ -47,6 +47,7 @@ enum PromotedLocationKind {
     FunctionActivationPLoc,
     ActivationScopePLoc,
     ClosureVarPLoc,
+    ArrowFunctionBoundThisPLoc
 };
 
 class PromotedLocationDescriptor {
index b2d07d5..f7787f4 100644 (file)
@@ -180,6 +180,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case Arrayify:
     case ArrayifyToStructure:
     case GetScope:
+    case LoadArrowFunctionThis:
     case SkipScope:
     case GetClosureVar:
     case PutClosureVar:
@@ -239,6 +240,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case CreateClonedArguments:
     case GetFromArguments:
     case PutToArguments:
+    case NewArrowFunction:
     case NewFunction:
     case Jump:
     case Branch:
index f5791db..aca4820 100644 (file)
@@ -38,6 +38,7 @@
 #include "DFGSaneStringGetByValSlowPathGenerator.h"
 #include "DFGSlowPathGenerator.h"
 #include "DirectArguments.h"
+#include "JSArrowFunction.h"
 #include "JSCInlines.h"
 #include "JSEnvironmentRecord.h"
 #include "JSLexicalEnvironment.h"
@@ -4477,6 +4478,15 @@ void SpeculativeJIT::compileGetScope(Node* node)
     cellResult(result.gpr(), node);
 }
 
+    
+void SpeculativeJIT::compileLoadArrowFunctionThis(Node* node)
+{
+    SpeculateCellOperand function(this, node->child1());
+    GPRTemporary result(this, Reuse, function);
+    m_jit.loadPtr(JITCompiler::Address(function.gpr(), JSArrowFunction::offsetOfThisValue()), result.gpr());
+    cellResult(result.gpr(), node);
+}
+    
 void SpeculativeJIT::compileSkipScope(Node* node)
 {
     SpeculateCellOperand scope(this, node->child1());
@@ -4607,55 +4617,73 @@ void SpeculativeJIT::compileCheckIdent(Node* node)
     noResult(node);
 }
 
+template <typename ClassType> void SpeculativeJIT::compileNewFunctionCommon(GPRReg resultGPR, Structure* structure, GPRReg scratch1GPR, GPRReg scratch2GPR, GPRReg scopeGPR, MacroAssembler::JumpList& slowPath, size_t size, FunctionExecutable* executable, ptrdiff_t offsetOfScopeChain, ptrdiff_t offsetOfExecutable, ptrdiff_t offsetOfRareData)
+{
+    emitAllocateJSObjectWithKnownSize<ClassType>(resultGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratch1GPR, scratch2GPR, slowPath, size);
+    
+    m_jit.storePtr(scopeGPR, JITCompiler::Address(resultGPR, offsetOfScopeChain));
+    m_jit.storePtr(TrustedImmPtr(executable), JITCompiler::Address(resultGPR, offsetOfExecutable));
+    m_jit.storePtr(TrustedImmPtr(0), JITCompiler::Address(resultGPR, offsetOfRareData));
+}
+
 void SpeculativeJIT::compileNewFunction(Node* node)
 {
+    NodeType nodeType = node->op();
+    ASSERT(nodeType == NewFunction || nodeType == NewArrowFunction);
+    
     SpeculateCellOperand scope(this, node->child1());
+    GPRReg thisValueGPR;
     GPRReg scopeGPR = scope.gpr();
 
     FunctionExecutable* executable = node->castOperand<FunctionExecutable*>();
 
+    if (nodeType == NewArrowFunction) {
+        SpeculateCellOperand thisValue(this, node->child2());
+        thisValueGPR = thisValue.gpr();
+    }
+
     if (executable->singletonFunction()->isStillValid()) {
         GPRFlushedCallResult result(this);
         GPRReg resultGPR = result.gpr();
-
+        
         flushRegisters();
-
-        callOperation(operationNewFunction, resultGPR, scopeGPR, executable);
+        
+        if (nodeType == NewArrowFunction)
+            callOperation(operationNewArrowFunction, resultGPR, scopeGPR, executable, thisValueGPR);
+        else
+            callOperation(operationNewFunction, resultGPR, scopeGPR, executable);
+        
         cellResult(resultGPR, node);
         return;
     }
 
-    Structure* structure = m_jit.graph().globalObjectFor(
-        node->origin.semantic)->functionStructure();
-
+    Structure* structure = nodeType == NewArrowFunction
+        ? m_jit.graph().globalObjectFor(node->origin.semantic)->arrowFunctionStructure()
+        : m_jit.graph().globalObjectFor(node->origin.semantic)->functionStructure();
+    
     GPRTemporary result(this);
     GPRTemporary scratch1(this);
     GPRTemporary scratch2(this);
+    
     GPRReg resultGPR = result.gpr();
     GPRReg scratch1GPR = scratch1.gpr();
     GPRReg scratch2GPR = scratch2.gpr();
-
+    
     JITCompiler::JumpList slowPath;
-    emitAllocateJSObjectWithKnownSize<JSFunction>(
-        resultGPR, TrustedImmPtr(structure), TrustedImmPtr(0),
-        scratch1GPR, scratch2GPR, slowPath, JSFunction::allocationSize(0));
-
-    // Don't need a memory barriers since we just fast-created the function, so it
-    // must be young.
-    m_jit.storePtr(
-        scopeGPR,
-        JITCompiler::Address(resultGPR, JSFunction::offsetOfScopeChain()));
-    m_jit.storePtr(
-        TrustedImmPtr(executable),
-        JITCompiler::Address(resultGPR, JSFunction::offsetOfExecutable()));
-    m_jit.storePtr(
-        TrustedImmPtr(0),
-        JITCompiler::Address(resultGPR, JSFunction::offsetOfRareData()));
-
-
-    addSlowPathGenerator(
-        slowPathCall(
-            slowPath, this, operationNewFunctionWithInvalidatedReallocationWatchpoint, resultGPR, scopeGPR, executable));
+    
+    if (nodeType == NewFunction) {
+        compileNewFunctionCommon<JSFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSFunction::allocationSize(0), executable, JSFunction::offsetOfScopeChain(), JSFunction::offsetOfExecutable(), JSFunction::offsetOfRareData());
+            
+        addSlowPathGenerator(slowPathCall(slowPath, this, operationNewFunctionWithInvalidatedReallocationWatchpoint, resultGPR, scopeGPR, executable));
+    }
+    
+    if (nodeType == NewArrowFunction) {
+        compileNewFunctionCommon<JSArrowFunction>(resultGPR, structure, scratch1GPR, scratch2GPR, scopeGPR, slowPath, JSArrowFunction::allocationSize(0), executable, JSArrowFunction::offsetOfScopeChain(), JSArrowFunction::offsetOfExecutable(), JSArrowFunction::offsetOfRareData());
+        
+        m_jit.storePtr(thisValueGPR, JITCompiler::Address(resultGPR, JSArrowFunction::offsetOfThisValue()));
+        
+        addSlowPathGenerator(slowPathCall(slowPath, this, operationNewArrowFunctionWithInvalidatedReallocationWatchpoint, resultGPR, scopeGPR, executable, thisValueGPR));
+    }
 
     cellResult(resultGPR, node);
 }
index ca07992..b2bbe62 100644 (file)
@@ -1215,6 +1215,12 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell));
         return appendCallWithExceptionCheckSetResult(operation, result);
     }
+    
+    JITCompiler::Call callOperation(J_JITOperation_EJscCJ operation, GPRReg result, GPRReg arg1, JSCell* cell, GPRReg arg2)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell), arg2);
+        return appendCallWithExceptionCheckSetResult(operation, result);
+    }
 
     JITCompiler::Call callOperation(V_JITOperation_EWs operation, WatchpointSet* watchpointSet)
     {
@@ -1621,6 +1627,11 @@ public:
         m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell));
         return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
     }
+    JITCompiler::Call callOperation(J_JITOperation_EJscCJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, JSCell* cell, GPRReg arg2)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell), arg2);
+        return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
+    }
     JITCompiler::Call callOperation(J_JITOperation_ESsiCI operation, GPRReg resultTag, GPRReg resultPayload, StructureStubInfo* stubInfo, GPRReg arg1, const UniquedStringImpl* uid)
     {
         m_jit.setupArgumentsWithExecState(TrustedImmPtr(stubInfo), arg1, TrustedImmPtr(uid));
@@ -2192,6 +2203,7 @@ public:
     void compileGetByValOnScopedArguments(Node*);
     
     void compileGetScope(Node*);
+    void compileLoadArrowFunctionThis(Node*);
     void compileSkipScope(Node*);
 
     void compileGetArrayLength(Node*);
@@ -2225,6 +2237,7 @@ public:
     void compilePutByValForIntTypedArray(GPRReg base, GPRReg property, Node*, TypedArrayType);
     void compileGetByValOnFloatTypedArray(Node*, TypedArrayType);
     void compilePutByValForFloatTypedArray(GPRReg base, GPRReg property, Node*, TypedArrayType);
+    template <typename ClassType> void compileNewFunctionCommon(GPRReg, Structure*, GPRReg, GPRReg, GPRReg, MacroAssembler::JumpList&, size_t, FunctionExecutable*, ptrdiff_t, ptrdiff_t, ptrdiff_t);
     void compileNewFunction(Node*);
     void compileForwardVarargs(Node*);
     void compileCreateActivation(Node*);
index 800b872..7512096 100644 (file)
@@ -3686,7 +3686,11 @@ void SpeculativeJIT::compile(Node* node)
     case GetScope:
         compileGetScope(node);
         break;
-        
+
+    case LoadArrowFunctionThis:
+        compileLoadArrowFunctionThis(node);
+        break;
+            
     case SkipScope:
         compileSkipScope(node);
         break;
@@ -4331,11 +4335,12 @@ void SpeculativeJIT::compile(Node* node)
         compileCreateClonedArguments(node);
         break;
     }
-        
+
     case NewFunction:
+    case NewArrowFunction:
         compileNewFunction(node);
         break;
-        
+
     case In:
         compileIn(node);
         break;
index 53daf34..aff7314 100644 (file)
@@ -3729,7 +3729,11 @@ void SpeculativeJIT::compile(Node* node)
     case GetScope:
         compileGetScope(node);
         break;
-        
+            
+    case LoadArrowFunctionThis:
+        compileLoadArrowFunctionThis(node);
+        break;
+            
     case SkipScope:
         compileSkipScope(node);
         break;
@@ -4336,11 +4340,12 @@ void SpeculativeJIT::compile(Node* node)
         compileCreateClonedArguments(node);
         break;
     }
-        
+
     case NewFunction:
+    case NewArrowFunction:
         compileNewFunction(node);
         break;
-        
+
     case In:
         compileIn(node);
         break;
index 66acda2..d20c5dd 100644 (file)
@@ -300,6 +300,7 @@ private:
             case CreateDirectArguments:
             case CreateScopedArguments:
             case CreateClonedArguments:
+            case NewArrowFunction:
             case NewFunction:
                 // Nodes that allocate get to set their epoch because for those nodes we know
                 // that they will be the newest object in the heap.
index ac9273c..7919025 100644 (file)
@@ -135,7 +135,9 @@ public:
                 case NewRegexp:
                     registerStructure(m_graph.globalObjectFor(node->origin.semantic)->regExpStructure());
                     break;
-                    
+                case NewArrowFunction:
+                    registerStructure(m_graph.globalObjectFor(node->origin.semantic)->arrowFunctionStructure());
+                    break;
                 case NewFunction:
                     registerStructure(m_graph.globalObjectFor(node->origin.semantic)->functionStructure());
                     break;
index e416fda..3c3864c 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "DirectArguments.h"
 #include "GetterSetter.h"
+#include "JSArrowFunction.h"
 #include "JSEnvironmentRecord.h"
 #include "JSPropertyNameEnumerator.h"
 #include "JSScope.h"
index 581f4cb..712fd8d 100644 (file)
@@ -88,7 +88,11 @@ namespace JSC { namespace FTL {
     macro(Structure_globalObject, Structure::globalObjectOffset()) \
     macro(Structure_prototype, Structure::prototypeOffset()) \
     macro(Structure_structureID, Structure::structureIDOffset()) \
-    macro(Symbol_privateName, Symbol::offsetOfPrivateName())
+    macro(Symbol_privateName, Symbol::offsetOfPrivateName()) \
+    macro(JSArrowFunction_executable, JSArrowFunction::offsetOfExecutable()) \
+    macro(JSArrowFunction_scope, JSArrowFunction::offsetOfScopeChain()) \
+    macro(JSArrowFunction_rareData, JSArrowFunction::offsetOfRareData()) \
+    macro(JSArrowFunction_this, JSArrowFunction::offsetOfThisValue())
 
 #define FOR_EACH_INDEXED_ABSTRACT_HEAP(macro) \
     macro(DirectArguments_storage, DirectArguments::storageOffset(), sizeof(EncodedJSValue)) \
index e2b1f41..7737421 100644 (file)
@@ -105,6 +105,7 @@ inline CapabilityLevel canCompile(Node* node)
     case LoopHint:
     case SkipScope:
     case CreateActivation:
+    case NewArrowFunction:
     case NewFunction:
     case GetClosureVar:
     case PutClosureVar:
@@ -141,6 +142,7 @@ inline CapabilityLevel canCompile(Node* node)
     case CountExecution:
     case GetExecutable:
     case GetScope:
+    case LoadArrowFunctionThis:
     case GetCallee:
     case GetArgumentCount:
     case ToString:
index 9b34414..125e4fe 100644 (file)
@@ -86,6 +86,7 @@ namespace JSC { namespace FTL {
     macro(J_JITOperation_EJI, functionType(int64, intPtr, int64, intPtr)) \
     macro(J_JITOperation_EJJ, functionType(int64, intPtr, int64, int64)) \
     macro(J_JITOperation_EJscC, functionType(intPtr, intPtr, intPtr, intPtr)) \
+    macro(J_JITOperation_EJscCJ, functionType(int64, intPtr, int64, int64, int64))\
     macro(J_JITOperation_EJssZ, functionType(int64, intPtr, intPtr, int32)) \
     macro(J_JITOperation_ESsiJI, functionType(int64, intPtr, intPtr, int64, intPtr)) \
     macro(Jss_JITOperation_EZ, functionType(intPtr, intPtr, int32)) \
index 04f234b..8a7d00d 100644 (file)
@@ -44,6 +44,7 @@
 #include "FTLOutput.h"
 #include "FTLThunks.h"
 #include "FTLWeightedTarget.h"
+#include "JSArrowFunction.h"
 #include "JSCInlines.h"
 #include "JSLexicalEnvironment.h"
 #include "OperandsInlines.h"
@@ -593,6 +594,7 @@ private:
             compileCreateActivation();
             break;
         case NewFunction:
+        case NewArrowFunction:
             compileNewFunction();
             break;
         case CreateDirectArguments:
@@ -678,6 +680,9 @@ private:
         case GetScope:
             compileGetScope();
             break;
+        case LoadArrowFunctionThis:
+            compileLoadArrowFunctionThis();
+            break;
         case SkipScope:
             compileSkipScope();
             break;
@@ -3093,38 +3098,55 @@ private:
     
     void compileNewFunction()
     {
+        ASSERT(m_node->op() == NewFunction || m_node->op() == NewArrowFunction);
+        
+        bool isArrowFunction = m_node->op() == NewArrowFunction;
+        
         LValue scope = lowCell(m_node->child1());
+        LValue thisValue = isArrowFunction ? lowCell(m_node->child2()) : nullptr;
+        
         FunctionExecutable* executable = m_node->castOperand<FunctionExecutable*>();
         if (executable->singletonFunction()->isStillValid()) {
-            LValue callResult = vmCall(
-                m_out.operation(operationNewFunction), m_callFrame, scope, weakPointer(executable));
+            LValue callResult = isArrowFunction
+                ? vmCall(m_out.operation(operationNewArrowFunction), m_callFrame, scope, weakPointer(executable), thisValue)
+                : vmCall(m_out.operation(operationNewFunction), m_callFrame, scope, weakPointer(executable));
             setJSValue(callResult);
             return;
         }
         
-        Structure* structure = m_graph.globalObjectFor(m_node->origin.semantic)->functionStructure();
+        Structure* structure = isArrowFunction
+            ? m_graph.globalObjectFor(m_node->origin.semantic)->arrowFunctionStructure()
+            : m_graph.globalObjectFor(m_node->origin.semantic)->functionStructure();
         
         LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("NewFunction slow path"));
         LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NewFunction continuation"));
         
         LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath);
         
-        LValue fastObject = allocateObject<JSFunction>(
-            structure, m_out.intPtrZero, slowPath);
+        LValue fastObject = isArrowFunction
+            ? allocateObject<JSArrowFunction>(structure, m_out.intPtrZero, slowPath)
+            : allocateObject<JSFunction>(structure, m_out.intPtrZero, slowPath);
+        
         
         // We don't need memory barriers since we just fast-created the function, so it
         // must be young.
-        m_out.storePtr(scope, fastObject, m_heaps.JSFunction_scope);
-        m_out.storePtr(weakPointer(executable), fastObject, m_heaps.JSFunction_executable);
-        m_out.storePtr(m_out.intPtrZero, fastObject, m_heaps.JSFunction_rareData);
+        m_out.storePtr(scope, fastObject, isArrowFunction ? m_heaps.JSArrowFunction_scope : m_heaps.JSFunction_scope);
+        m_out.storePtr(weakPointer(executable), fastObject, isArrowFunction ?  m_heaps.JSArrowFunction_executable : m_heaps.JSFunction_executable);
+        
+        if (isArrowFunction)
+            m_out.storePtr(thisValue, fastObject, m_heaps.JSArrowFunction_this);
+        
+        m_out.storePtr(m_out.intPtrZero, fastObject, isArrowFunction ?  m_heaps.JSArrowFunction_rareData : m_heaps.JSFunction_rareData);
         
         ValueFromBlock fastResult = m_out.anchor(fastObject);
         m_out.jump(continuation);
         
         m_out.appendTo(slowPath, continuation);
-        LValue callResult = vmCall(
-            m_out.operation(operationNewFunctionWithInvalidatedReallocationWatchpoint),
-            m_callFrame, scope, weakPointer(executable));
+        
+        LValue callResult = isArrowFunction
+            ? vmCall(m_out.operation(operationNewArrowFunctionWithInvalidatedReallocationWatchpoint), m_callFrame, scope, weakPointer(executable), thisValue)
+            : vmCall(m_out.operation(operationNewFunctionWithInvalidatedReallocationWatchpoint), m_callFrame, scope, weakPointer(executable));
+        
         ValueFromBlock slowResult = m_out.anchor(callResult);
         m_out.jump(continuation);
         
@@ -4056,6 +4078,11 @@ private:
         setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSFunction_scope));
     }
     
+    void compileLoadArrowFunctionThis()
+    {
+        setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSArrowFunction_this));
+    }
+    
     void compileSkipScope()
     {
         setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.JSScope_next));
index 8cdbc5d..a8bd57f 100644 (file)
@@ -159,16 +159,25 @@ extern "C" JSCell* JIT_OPERATION operationMaterializeObjectInOSR(
         // Figure out what the executable and activation are
         FunctionExecutable* executable = nullptr;
         JSScope* activation = nullptr;
+        JSValue boundThis;
+        bool isArrowFunction = false;
         for (unsigned i = materialization->properties().size(); i--;) {
             const ExitPropertyValue& property = materialization->properties()[i];
             if (property.location() == PromotedLocationDescriptor(FunctionExecutablePLoc))
                 executable = jsCast<FunctionExecutable*>(JSValue::decode(values[i]));
             if (property.location() == PromotedLocationDescriptor(FunctionActivationPLoc))
                 activation = jsCast<JSScope*>(JSValue::decode(values[i]));
+            if (property.location() == PromotedLocationDescriptor(ArrowFunctionBoundThisPLoc)) {
+                isArrowFunction = true;
+                boundThis = JSValue::decode(values[i]);
+            }
         }
         RELEASE_ASSERT(executable && activation);
 
-        JSFunction* result = JSFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation);
+        
+        JSFunction* result = isArrowFunction
+            ? JSArrowFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation, boundThis)
+            : JSFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation);
 
         return result;
     }
index 0d50803..0a802bd 100644 (file)
@@ -45,6 +45,7 @@
 #include "ExceptionHelpers.h"
 #include "GetterSetter.h"
 #include "JSArray.h"
+#include "JSArrowFunction.h"
 #include "JSBoundFunction.h"
 #include "JSCInlines.h"
 #include "JSLexicalEnvironment.h"
index ad9df6f..187dabe 100644 (file)
@@ -31,6 +31,7 @@
 #define Interpreter_h
 
 #include "ArgList.h"
+#include "JSArrowFunction.h"
 #include "JSCJSValue.h"
 #include "JSCell.h"
 #include "JSObject.h"
@@ -50,6 +51,7 @@ namespace JSC {
     class ExecutableBase;
     class FunctionExecutable;
     class VM;
+    class JSArrowFunction;
     class JSFunction;
     class JSGlobalObject;
     class LLIntOffsetsExtractor;
index 4506c68..9bdefaf 100644 (file)
@@ -209,6 +209,15 @@ public:
         addCallArgument(arg2);
     }
 
+    ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, GPRReg arg3)
+    {
+        resetCallArguments();
+        addCallArgument(GPRInfo::callFrameRegister);
+        addCallArgument(arg1);
+        addCallArgument(arg2);
+        addCallArgument(arg3);
+    }
+    
     ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImm32 arg2)
     {
         resetCallArguments();
index 038f5d7..bbc8523 100644 (file)
@@ -219,6 +219,7 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_end)
         DEFINE_OP(op_enter)
         DEFINE_OP(op_get_scope)
+        DEFINE_OP(op_load_arrowfunction_this)
         DEFINE_OP(op_eq)
         DEFINE_OP(op_eq_null)
         case op_get_by_id_out_of_line:
@@ -259,6 +260,7 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_new_array_buffer)
         DEFINE_OP(op_new_func)
         DEFINE_OP(op_new_func_exp)
+        DEFINE_OP(op_new_arrow_func_exp) 
         DEFINE_OP(op_new_object)
         DEFINE_OP(op_new_regexp)
         DEFINE_OP(op_not)
index dd89563..ad17f3e 100644 (file)
@@ -498,6 +498,7 @@ namespace JSC {
         void emit_op_end(Instruction*);
         void emit_op_enter(Instruction*);
         void emit_op_get_scope(Instruction*);
+        void emit_op_load_arrowfunction_this(Instruction*);
         void emit_op_eq(Instruction*);
         void emit_op_eq_null(Instruction*);
         void emit_op_get_by_id(Instruction*);
@@ -539,6 +540,7 @@ namespace JSC {
         void emit_op_new_array_buffer(Instruction*);
         void emit_op_new_func(Instruction*);
         void emit_op_new_func_exp(Instruction*);
+        void emit_op_new_arrow_func_exp(Instruction*);
         void emit_op_new_object(Instruction*);
         void emit_op_new_regexp(Instruction*);
         void emit_op_not(Instruction*);
@@ -653,6 +655,7 @@ namespace JSC {
         void emitRightShift(Instruction*, bool isUnsigned);
         void emitRightShiftSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator&, bool isUnsigned);
 
+        void emitNewFuncExprCommon(Instruction*);
         void emitVarInjectionCheck(bool needsVarInjectionChecks);
         void emitResolveClosure(int dst, int scope, bool needsVarInjectionChecks, unsigned depth);
         void emitLoadWithStructureCheck(int scope, Structure** structureSlot);
@@ -723,6 +726,7 @@ namespace JSC {
         MacroAssembler::Call callOperation(J_JITOperation_EJJBy, int, GPRReg, GPRReg, ByValInfo*);
         MacroAssembler::Call callOperation(C_JITOperation_EJsc, GPRReg);
         MacroAssembler::Call callOperation(J_JITOperation_EJscC, int, GPRReg, JSCell*);
+        MacroAssembler::Call callOperation(J_JITOperation_EJscCJ, int, GPRReg, JSCell*, GPRReg);
         MacroAssembler::Call callOperation(C_JITOperation_EJscZ, GPRReg, int32_t);
         MacroAssembler::Call callOperation(C_JITOperation_EJscZ, int, GPRReg, int32_t);
 #if USE(JSVALUE64)
index d936438..1bf9ff1 100644 (file)
@@ -271,6 +271,12 @@ ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(J_JITOperation_EJscC opera
     return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
 }
 
+ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(J_JITOperation_EJscCJ operation, int dst, GPRReg arg1, JSCell* cell, GPRReg arg2)
+{
+    setupArgumentsWithExecState(arg1, TrustedImmPtr(cell), arg2);
+    return appendCallWithExceptionCheckSetJSValueResult(operation, dst);
+}
+    
 ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(J_JITOperation_EP operation, int dst, void* pointer)
 {
     setupArgumentsWithExecState(TrustedImmPtr(pointer));
index 598d4ec..c83bcc8 100644 (file)
@@ -35,6 +35,7 @@
 #include "Heap.h"
 #include "JITInlines.h"
 #include "JSArray.h"
+#include "JSArrowFunction.h"
 #include "JSCell.h"
 #include "JSFunction.h"
 #include "JSPropertyNameEnumerator.h"
@@ -673,6 +674,14 @@ void JIT::emit_op_get_scope(Instruction* currentInstruction)
     loadPtr(Address(regT0, JSFunction::offsetOfScopeChain()), regT0);
     emitStoreCell(dst, regT0);
 }
+    
+void JIT::emit_op_load_arrowfunction_this(Instruction* currentInstruction)
+{
+    int dst = currentInstruction[1].u.operand;
+    emitGetFromCallFrameHeaderPtr(JSStack::Callee, regT0);
+    loadPtr(Address(regT0, JSArrowFunction::offsetOfThisValue()), regT0);
+    emitStoreCell(dst, regT0);
+}
 
 void JIT::emit_op_to_this(Instruction* currentInstruction)
 {
@@ -962,26 +971,45 @@ void JIT::emit_op_new_func(Instruction* currentInstruction)
 
 void JIT::emit_op_new_func_exp(Instruction* currentInstruction)
 {
+    emitNewFuncExprCommon(currentInstruction);
+}
+    
+void JIT::emitNewFuncExprCommon(Instruction* currentInstruction)
+{
+    OpcodeID opcodeID = m_vm->interpreter->getOpcodeID(currentInstruction->u.opcode);
+    bool isArrowFunction = opcodeID == op_new_arrow_func_exp;
+    
     Jump notUndefinedScope;
     int dst = currentInstruction[1].u.operand;
 #if USE(JSVALUE64)
     emitGetVirtualRegister(currentInstruction[2].u.operand, regT0);
+    if (isArrowFunction)
+        emitGetVirtualRegister(currentInstruction[4].u.operand, regT1);
     notUndefinedScope = branch64(NotEqual, regT0, TrustedImm64(JSValue::encode(jsUndefined())));
     store64(TrustedImm64(JSValue::encode(jsUndefined())), Address(callFrameRegister, sizeof(Register) * dst));
 #else
     emitLoadPayload(currentInstruction[2].u.operand, regT0);
+    if (isArrowFunction)
+        emitLoadPayload(currentInstruction[4].u.operand, regT1);
     notUndefinedScope = branch32(NotEqual, tagFor(currentInstruction[2].u.operand), TrustedImm32(JSValue::UndefinedTag));
     emitStore(dst, jsUndefined());
 #endif
-
     Jump done = jump();
     notUndefinedScope.link(this);
-
-    FunctionExecutable* funcExpr = m_codeBlock->functionExpr(currentInstruction[3].u.operand);
-    callOperation(operationNewFunction, dst, regT0, funcExpr);
+        
+    FunctionExecutable* function = m_codeBlock->functionExpr(currentInstruction[3].u.operand);
+    if (isArrowFunction)
+        callOperation(operationNewArrowFunction, dst, regT0, function, regT1);
+    else
+        callOperation(operationNewFunction, dst, regT0, function);
     done.link(this);
 }
-
+    
+void JIT::emit_op_new_arrow_func_exp(Instruction* currentInstruction)
+{
+    emitNewFuncExprCommon(currentInstruction);
+}
+    
 void JIT::emit_op_new_array(Instruction* currentInstruction)
 {
     int dst = currentInstruction[1].u.operand;
index 91c00e3..b39ae1d 100644 (file)
@@ -35,6 +35,7 @@
 #include "Exception.h"
 #include "JITInlines.h"
 #include "JSArray.h"
+#include "JSArrowFunction.h"
 #include "JSCell.h"
 #include "JSEnvironmentRecord.h"
 #include "JSFunction.h"
@@ -922,6 +923,14 @@ void JIT::emit_op_get_scope(Instruction* currentInstruction)
     emitStoreCell(dst, regT0);
 }
 
+void JIT::emit_op_load_arrowfunction_this(Instruction* currentInstruction)
+{
+    int dst = currentInstruction[1].u.operand;
+    emitGetFromCallFrameHeaderPtr(JSStack::Callee, regT0);
+    loadPtr(Address(regT0, JSArrowFunction::offsetOfThisValue()), regT0);
+    emitStoreCell(dst, regT0);
+}
+
 void JIT::emit_op_create_this(Instruction* currentInstruction)
 {
     int callee = currentInstruction[2].u.operand;
index 97929b7..b95d56e 100644 (file)
@@ -43,6 +43,7 @@
 #include "HostCallReturnValue.h"
 #include "JIT.h"
 #include "JITToDFGDeferredCompilationCallback.h"
+#include "JSArrowFunction.h"
 #include "JSCInlines.h"
 #include "JSGlobalObjectFunctions.h"
 #include "JSLexicalEnvironment.h"
@@ -942,6 +943,30 @@ EncodedJSValue JIT_OPERATION operationNewFunctionWithInvalidatedReallocationWatc
     return JSValue::encode(JSFunction::createWithInvalidatedReallocationWatchpoint(vm, static_cast<FunctionExecutable*>(functionExecutable), scope));
 }
 
+EncodedJSValue static operationNewFunctionCommon(ExecState* exec, JSScope* scope, JSCell* functionExecutable, EncodedJSValue thisValue, bool isInvalidated)
+{
+    ASSERT(functionExecutable->inherits(FunctionExecutable::info()));
+    FunctionExecutable* executable = static_cast<FunctionExecutable*>(functionExecutable);
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+        
+    JSArrowFunction* arrowFunction  = isInvalidated
+        ? JSArrowFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, scope, JSValue::decode(thisValue))
+        : JSArrowFunction::create(vm, executable, scope, JSValue::decode(thisValue));
+    
+    return JSValue::encode(arrowFunction);
+}
+    
+EncodedJSValue JIT_OPERATION operationNewArrowFunctionWithInvalidatedReallocationWatchpoint(ExecState* exec, JSScope* scope, JSCell* functionExecutable, EncodedJSValue thisValue)
+{
+    return operationNewFunctionCommon(exec, scope, functionExecutable, thisValue, true);
+}
+    
+EncodedJSValue JIT_OPERATION operationNewArrowFunction(ExecState* exec, JSScope* scope, JSCell* functionExecutable, EncodedJSValue thisValue)
+{
+    return operationNewFunctionCommon(exec, scope, functionExecutable, thisValue, false);
+}
+
 JSCell* JIT_OPERATION operationNewObject(ExecState* exec, Structure* structure)
 {
     VM* vm = &exec->vm();
index 0440b85..bd6875c 100644 (file)
@@ -122,6 +122,7 @@ typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EPP)(ExecState*, void*, vo
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EPS)(ExecState*, void*, size_t);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EPc)(ExecState*, Instruction*);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJscC)(ExecState*, JSScope*, JSCell*);
+typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJscCJ)(ExecState*, JSScope*, JSCell*, EncodedJSValue);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_ESS)(ExecState*, size_t, size_t);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_ESsiCI)(ExecState*, StructureStubInfo*, JSCell*, UniquedStringImpl*);
 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_ESsiJI)(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*);
@@ -288,6 +289,8 @@ EncodedJSValue JIT_OPERATION operationNewArrayBufferWithProfile(ExecState*, Arra
 EncodedJSValue JIT_OPERATION operationNewArrayWithSizeAndProfile(ExecState*, ArrayAllocationProfile*, EncodedJSValue size) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewFunction(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewFunctionWithInvalidatedReallocationWatchpoint(ExecState*, JSScope*, JSCell*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationNewArrowFunction(ExecState*, JSScope*, JSCell*, EncodedJSValue) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationNewArrowFunctionWithInvalidatedReallocationWatchpoint(ExecState*, JSScope*, JSCell*, EncodedJSValue) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationNewObject(ExecState*, Structure*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewRegexp(ExecState*, void*) WTF_INTERNAL;
 void JIT_OPERATION operationHandleWatchdogTimer(ExecState*) WTF_INTERNAL;
index 2d4677c..a2a6b2b 100644 (file)
@@ -36,6 +36,7 @@
 #include "Interpreter.h"
 #include "JITStubs.h"
 #include "JSArray.h"
+#include "JSArrowFunction.h"
 #include "JSCell.h"
 #include "JSFunction.h"
 #include "VM.h"
index 4bad506..663489b 100644 (file)
@@ -39,6 +39,7 @@
 #include "Interpreter.h"
 #include "JIT.h"
 #include "JITExceptions.h"
+#include "JSArrowFunction.h"
 #include "JSLexicalEnvironment.h"
 #include "JSCInlines.h"
 #include "JSCJSValue.h"
@@ -171,7 +172,7 @@ namespace JSC { namespace LLInt {
         ExecState* __rcf_exec = (execCallee);                           \
         LLINT_RETURN_TWO(pc, __rcf_exec);                               \
     } while (false)
-
+    
 extern "C" SlowPathReturnType llint_trace_operand(ExecState* exec, Instruction* pc, int fromWhere, int operand)
 {
     LLINT_BEGIN();
@@ -1017,12 +1018,24 @@ LLINT_SLOW_PATH_DECL(slow_path_new_func)
 LLINT_SLOW_PATH_DECL(slow_path_new_func_exp)
 {
     LLINT_BEGIN();
+    
     CodeBlock* codeBlock = exec->codeBlock();
     JSScope* scope = exec->uncheckedR(pc[2].u.operand).Register::scope();
-    FunctionExecutable* function = codeBlock->functionExpr(pc[3].u.operand);
-    JSFunction* func = JSFunction::create(vm, function, scope);
+    FunctionExecutable* executable = codeBlock->functionExpr(pc[3].u.operand);
     
-    LLINT_RETURN(func);
+    LLINT_RETURN(JSFunction::create(vm, executable, scope));
+}
+
+LLINT_SLOW_PATH_DECL(slow_path_new_arrow_func_exp)
+{
+    LLINT_BEGIN();
+
+    JSValue thisValue = LLINT_OP_C(4).jsValue();
+    CodeBlock* codeBlock = exec->codeBlock();
+    JSScope* scope = exec->uncheckedR(pc[2].u.operand).Register::scope();
+    FunctionExecutable* executable = codeBlock->functionExpr(pc[3].u.operand);
+    
+    LLINT_RETURN(JSArrowFunction::create(vm, executable, scope, thisValue));
 }
 
 static SlowPathReturnType handleHostCall(ExecState* execCallee, Instruction* pc, JSValue callee, CodeSpecializationKind kind)
@@ -1100,7 +1113,7 @@ inline SlowPathReturnType setUpCall(ExecState* execCallee, Instruction* pc, Code
     JSScope* scope = callee->scopeUnchecked();
     VM& vm = *scope->vm();
     ExecutableBase* executable = callee->executable();
-    
+
     MacroAssemblerCodePtr codePtr;
     CodeBlock* codeBlock = 0;
     if (executable->isHostFunction())
index 8cc69a9..3f1daa8 100644 (file)
@@ -97,6 +97,7 @@ LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_switch_char);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_switch_string);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_func);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_func_exp);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_new_arrow_func_exp);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_call);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_construct);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_size_frame_for_varargs);
index cb42b74..5ad8346 100644 (file)
@@ -1183,6 +1183,10 @@ _llint_op_new_func_exp:
     callSlowPath(_llint_slow_path_new_func_exp)
     dispatch(4)
 
+_llint_op_new_arrow_func_exp:
+    traceExecution()
+    callSlowPath(_llint_slow_path_new_arrow_func_exp)
+    dispatch(5)
 
 _llint_op_call:
     traceExecution()
index e90eced..7ef6b87 100644 (file)
@@ -2373,3 +2373,12 @@ _llint_op_profile_type:
 
 .opProfileTypeDone:
     dispatch(6)
+
+_llint_op_load_arrowfunction_this:
+    traceExecution()
+    loadi Callee + PayloadOffset[cfr], t0
+    loadi JSArrowFunction::m_boundThis[t0], t0
+    loadisFromInstruction(1, t1)
+    storei CellTag, TagOffset[cfr, t1, 8]
+    storei t0, PayloadOffset[cfr, t1, 8]
+    dispatch(2)
\ No newline at end of file
index d9455f7..d2152a2 100644 (file)
@@ -2226,3 +2226,11 @@ _llint_op_profile_type:
 
 .opProfileTypeDone:
     dispatch(6)
+
+_llint_op_load_arrowfunction_this:
+    traceExecution()
+    loadp Callee[cfr], t0
+    loadp JSArrowFunction::m_boundThis[t0], t0
+    loadisFromInstruction(1, t1)
+    storeq t0, [cfr, t1, 8]
+    dispatch(2)
\ No newline at end of file
index 029f17e..3853839 100644 (file)
@@ -361,19 +361,19 @@ public:
         const JSTokenLocation& startLocation, const JSTokenLocation& endLocation, 
         unsigned startColumn, unsigned endColumn, int functionKeywordStart, 
         int functionNameStart, int parametersStart, bool inStrictContext, 
-        ConstructorKind constructorKind, unsigned parameterCount, SourceParseMode mode)
+        ConstructorKind constructorKind, unsigned parameterCount, SourceParseMode mode, bool isArrowFunction)
     {
         return new (m_parserArena) FunctionMetadataNode(
             m_parserArena, startLocation, endLocation, startColumn, endColumn, 
             functionKeywordStart, functionNameStart, parametersStart, 
-            inStrictContext, constructorKind, parameterCount, mode);
+            inStrictContext, constructorKind, parameterCount, mode, isArrowFunction);
     }
 
     ExpressionNode* createArrowFunctionExpr(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
     {
+        usesThis();
         SourceCode source = m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.bodyStartColumn);
-
-        FuncExprNode* result = new (m_parserArena) FuncExprNode(location, *functionInfo.name, functionInfo.body, source);
+        ArrowFuncExprNode* result = new (m_parserArena) ArrowFuncExprNode(location, *functionInfo.name, functionInfo.body, source);
         functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);
         return result;
     }
index b3748cf..f349137 100644 (file)
@@ -890,13 +890,19 @@ namespace JSC {
     {
     }
 
-    inline FuncExprNode::FuncExprNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* m_metadata, const SourceCode& source)
+    
+    inline BaseFuncExprNode::BaseFuncExprNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* m_metadata, const SourceCode& source)
         : ExpressionNode(location)
         , m_metadata(m_metadata)
     {
         m_metadata->finishParsing(source, ident, FunctionExpression);
     }
 
+    inline FuncExprNode::FuncExprNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* m_metadata, const SourceCode& source)
+        : BaseFuncExprNode(location, ident, m_metadata, source)
+    {
+    }
+
     inline FuncDeclNode::FuncDeclNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* m_metadata, const SourceCode& source)
         : StatementNode(location)
         , m_metadata(m_metadata)
@@ -904,6 +910,11 @@ namespace JSC {
         m_metadata->finishParsing(source, ident, FunctionDeclaration);
     }
 
+    inline ArrowFuncExprNode::ArrowFuncExprNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* m_metadata, const SourceCode& source)
+        : BaseFuncExprNode(location, ident, m_metadata, source)
+    {
+    }
+
 #if ENABLE(ES6_CLASS_SYNTAX)
     inline ClassDeclNode::ClassDeclNode(const JSTokenLocation& location, ExpressionNode* classDeclaration)
         : StatementNode(location)
index cf4fe45..18f8455 100644 (file)
@@ -151,7 +151,7 @@ FunctionMetadataNode::FunctionMetadataNode(
     ParserArena&, const JSTokenLocation& startLocation, 
     const JSTokenLocation& endLocation, unsigned startColumn, unsigned endColumn, 
     int functionKeywordStart, int functionNameStart, int parametersStart, bool isInStrictContext, 
-    ConstructorKind constructorKind, unsigned parameterCount, SourceParseMode mode)
+    ConstructorKind constructorKind, unsigned parameterCount, SourceParseMode mode, bool isArrowFunction)
         : Node(endLocation)
         , m_startColumn(startColumn)
         , m_endColumn(endColumn)
@@ -163,6 +163,7 @@ FunctionMetadataNode::FunctionMetadataNode(
         , m_parseMode(mode)
         , m_isInStrictContext(isInStrictContext)
         , m_constructorKind(static_cast<unsigned>(constructorKind))
+        , m_isArrowFunction(isArrowFunction)
 {
     ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind));
 }
index c02b42c..ed5fc27 100644 (file)
@@ -165,6 +165,7 @@ namespace JSC {
         virtual bool isDotAccessorNode() const { return false; }
         virtual bool isDestructuringNode() const { return false; }
         virtual bool isFuncExprNode() const { return false; }
+        virtual bool isArrowFuncExprNode() const { return false; }
         virtual bool isCommaNode() const { return false; }
         virtual bool isSimpleArray() const { return false; }
         virtual bool isAdd() const { return false; }
@@ -1809,7 +1810,7 @@ namespace JSC {
             ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, 
             unsigned startColumn, unsigned endColumn, int functionKeywordStart, 
             int functionNameStart, int parametersStart, bool isInStrictContext, 
-            ConstructorKind, unsigned, SourceParseMode);
+            ConstructorKind, unsigned, SourceParseMode, bool isArrowFunction);
 
         void finishParsing(const SourceCode&, const Identifier&, FunctionMode);
         
@@ -1835,6 +1836,7 @@ namespace JSC {
         int startStartOffset() const { return m_startStartOffset; }
         bool isInStrictContext() const { return m_isInStrictContext; }
         ConstructorKind constructorKind() { return static_cast<ConstructorKind>(m_constructorKind); }
+        bool isArrowFunction() const { return m_isArrowFunction; }
 
         void setLoc(unsigned firstLine, unsigned lastLine, int startOffset, int lineStartOffset)
         {
@@ -1860,6 +1862,7 @@ namespace JSC {
         SourceParseMode m_parseMode;
         unsigned m_isInStrictContext : 1;
         unsigned m_constructorKind : 2;
+        unsigned m_isArrowFunction : 1;
     };
 
     class FunctionNode final : public ScopeNode {
@@ -1889,18 +1892,35 @@ namespace JSC {
         unsigned m_endColumn;
     };
 
-    class FuncExprNode : public ExpressionNode {
+    class BaseFuncExprNode : public ExpressionNode {
     public:
-        FuncExprNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&);
+        BaseFuncExprNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&);
 
         FunctionMetadataNode* metadata() { return m_metadata; }
 
+    protected:
+        FunctionMetadataNode* m_metadata;
+    };
+
+
+    class FuncExprNode : public BaseFuncExprNode {
+    public:
+        FuncExprNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&);
+
     private:
         virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
 
         virtual bool isFuncExprNode() const override { return true; }
+    };
 
-        FunctionMetadataNode* m_metadata;
+    class ArrowFuncExprNode : public BaseFuncExprNode {
+    public:
+        ArrowFuncExprNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&);
+
+    private:
+        virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+        virtual bool isArrowFuncExprNode() const override { return true; }
     };
 
 #if ENABLE(ES6_CLASS_SYNTAX)
index 71ff677..326bfd2 100644 (file)
@@ -1546,11 +1546,12 @@ template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBo
     TreeBuilder& context, const JSTokenLocation& startLocation, int startColumn, int functionKeywordStart, int functionNameStart, int parametersStart, 
     ConstructorKind constructorKind, FunctionBodyType bodyType, unsigned parameterCount, SourceParseMode parseMode)
 {
+    bool isArrowFunction = FunctionBodyType::StandardFunctionBodyBlock != bodyType;
     if (bodyType == StandardFunctionBodyBlock || bodyType == ArrowFunctionBodyBlock) {
         next();
         if (match(CLOSEBRACE)) {
             unsigned endColumn = tokenColumn();
-            return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, parameterCount, parseMode);
+            return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, parameterCount, parseMode, isArrowFunction);
         }
     }
 
@@ -1562,7 +1563,7 @@ template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBo
     else
         failIfFalse(parseSourceElements(syntaxChecker, CheckForStrictMode), bodyType == StandardFunctionBodyBlock ? "Cannot parse body of this function" : "Cannot parse body of this arrow function");
     unsigned endColumn = tokenColumn();
-    return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, parameterCount, parseMode);
+    return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, parameterCount, parseMode, isArrowFunction);
 }
 
 static const char* stringForFunctionMode(SourceParseMode mode)
@@ -1737,7 +1738,7 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
     }
     
     bool isClassConstructor = constructorKind != ConstructorKind::None;
-
+    
     functionInfo.bodyStartColumn = startColumn;
     
     // If we know about this function already, we can use the cached info and skip the parser to the end of the function.
@@ -1756,11 +1757,13 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
             endLocation.startOffset - m_token.m_data.lineStartOffset :
             endLocation.startOffset - endLocation.lineStartOffset;
         unsigned currentLineStartOffset = m_token.m_location.lineStartOffset;
-
+        
+        bool isArrowFunction = parseType == ArrowFunctionParseType;
+        
         functionInfo.body = context.createFunctionMetadata(
             startLocation, endLocation, functionInfo.bodyStartColumn, bodyEndColumn, 
             functionKeywordStart, functionNameStart, parametersStart, 
-            cachedInfo->strictMode, constructorKind, cachedInfo->parameterCount, mode);
+            cachedInfo->strictMode, constructorKind, cachedInfo->parameterCount, mode, isArrowFunction);
         
         functionScope->restoreFromSourceProviderCache(cachedInfo);
         popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo);
@@ -1774,7 +1777,7 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
         m_lexer->setLineNumber(m_token.m_location.line);
         functionInfo.endOffset = cachedInfo->endFunctionOffset;
 
-        if (parseType == ArrowFunctionParseType)
+        if (isArrowFunction)
             functionBodyType = cachedInfo->isBodyArrowExpression ?  ArrowFunctionBodyExpression : ArrowFunctionBodyBlock;
         else
             functionBodyType = StandardFunctionBodyBlock;
index 9ddc052..7a85dd2 100644 (file)
@@ -186,7 +186,7 @@ public:
     ClassExpression createClassExpr(const JSTokenLocation&, const Identifier&, ExpressionType, ExpressionType, PropertyList, PropertyList) { return ClassExpr; }
 #endif
     ExpressionType createFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
-    int createFunctionMetadata(const JSTokenLocation&, const JSTokenLocation&, int, int, bool, int, int, int, ConstructorKind, unsigned, SourceParseMode) { return FunctionBodyResult; }
+    int createFunctionMetadata(const JSTokenLocation&, const JSTokenLocation&, int, int, bool, int, int, int, ConstructorKind, unsigned, SourceParseMode, bool) { return FunctionBodyResult; }
     ExpressionType createArrowFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
     void setFunctionNameStart(int, int) { }
     int createArguments() { return ArgumentsResult; }
index 0ab1672..9dc694f 100644 (file)
@@ -236,8 +236,7 @@ RefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor(
     DebuggerMode debuggerMode = globalObject->hasDebugger() ? DebuggerOn : DebuggerOff;
     ProfilerMode profilerMode = globalObject->hasProfiler() ? ProfilerOn : ProfilerOff;
     UnlinkedFunctionCodeBlock* unlinkedCodeBlock =
-        executable->m_unlinkedExecutable->codeBlockFor(
-            *vm, executable->m_source, kind, debuggerMode, profilerMode, error);
+    executable->m_unlinkedExecutable->codeBlockFor(*vm, executable->m_source, kind, debuggerMode, profilerMode, error, executable->isArrowFunction());
     recordParse(executable->m_unlinkedExecutable->features(), executable->m_unlinkedExecutable->hasCapturedVariables(), firstLine(), lastLine(), startColumn(), endColumn()); 
     if (!unlinkedCodeBlock) {
         exception = vm->throwException(
index bce2428..cf2bde8 100644 (file)
@@ -474,7 +474,7 @@ public:
 
     void clearCode();
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None); }
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false); }
 
     unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }
     unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }
@@ -530,7 +530,7 @@ public:
 
     void clearCode();
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None); }
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false); }
 
 private:
     friend class ScriptExecutable;
@@ -633,6 +633,7 @@ public:
     FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); }
     bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); }
     ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); }
+    bool isArrowFunction() const { return m_unlinkedExecutable->isArrowFunction(); }
     bool isClassConstructorFunction() const { return m_unlinkedExecutable->isClassConstructorFunction(); }
     const Identifier& name() { return m_unlinkedExecutable->name(); }
     const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); }
diff --git a/Source/JavaScriptCore/runtime/JSArrowFunction.cpp b/Source/JavaScriptCore/runtime/JSArrowFunction.cpp
new file mode 100644 (file)
index 0000000..951c260
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 Aleksandr Skachkov <gskachkov@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSArrowFunction.h"
+
+#include "Error.h"
+#include "ExceptionHelpers.h"
+#include "JSCInlines.h"
+#include "JSCJSValue.h"
+#include "JSFunction.h"
+#include "JSFunctionInlines.h"
+#include "JSObject.h"
+#include "PropertySlot.h"
+#include "VM.h"
+
+namespace JSC {
+
+const ClassInfo JSArrowFunction::s_info = { "ArrowFunction", &Base::s_info, 0, CREATE_METHOD_TABLE(JSArrowFunction) };
+
+void JSArrowFunction::destroy(JSCell* cell)
+{
+    static_cast<JSArrowFunction*>(cell)->JSArrowFunction::~JSArrowFunction();
+}
+
+JSArrowFunction* JSArrowFunction::create(VM& vm, FunctionExecutable* executable, JSScope* scope, JSValue boundThis)
+{
+    JSArrowFunction* result = createImpl(vm, executable, scope, boundThis);
+    executable->singletonFunction()->notifyWrite(vm, result, "Allocating an arrow function");
+    return result;
+}
+
+JSArrowFunction::JSArrowFunction(VM& vm, FunctionExecutable* executable, JSScope* scope, JSValue boundThis)
+    : Base(vm, executable, scope, scope->globalObject()->arrowFunctionStructure())
+    , m_boundThis(vm, this, boundThis)
+{
+}
+
+JSArrowFunction* JSArrowFunction::createWithInvalidatedReallocationWatchpoint(VM& vm, FunctionExecutable* executable, JSScope* scope, JSValue boundThis)
+{
+    ASSERT(executable->singletonFunction()->hasBeenInvalidated());
+    return create(vm, executable, scope, boundThis);
+}
+
+void JSArrowFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    JSArrowFunction* thisObject = jsCast<JSArrowFunction*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+    Base::visitChildren(thisObject, visitor);
+
+    visitor.append(&thisObject->m_boundThis);
+}
+
+ConstructType JSArrowFunction::getConstructData(JSCell*, ConstructData&)
+{
+    return ConstructTypeNone;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSArrowFunction.h b/Source/JavaScriptCore/runtime/JSArrowFunction.h
new file mode 100644 (file)
index 0000000..7f56f68
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2015 Aleksandr Skachkov <gskachkov@gmail.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSArrowFunction_h
+#define JSArrowFunction_h
+
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+
+namespace JSC {
+    
+class JSGlobalObject;
+class LLIntOffsetsExtractor;
+class LLIntDesiredOffsets;
+    
+class JSArrowFunction : public JSFunction {
+    friend class JIT;
+#if ENABLE(DFG_JIT)
+    friend class DFG::SpeculativeJIT;
+    friend class DFG::JITCompiler;
+#endif
+    friend class VM;
+public:
+    typedef JSFunction Base;
+
+    static JSArrowFunction* create(VM&, FunctionExecutable*, JSScope*, JSValue);
+    static JSArrowFunction* createWithInvalidatedReallocationWatchpoint(VM&, FunctionExecutable*, JSScope*, JSValue);
+
+    static void destroy(JSCell*);
+    
+    static size_t allocationSize(size_t inlineCapacity)
+    {
+        ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
+        return sizeof(JSArrowFunction);
+    }
+    
+    static JSArrowFunction* createImpl(VM& vm, FunctionExecutable* executable, JSScope* scope, JSValue boundThis)
+    {
+        JSArrowFunction* function = new (NotNull, allocateCell<JSArrowFunction>(vm.heap)) JSArrowFunction(vm, executable, scope, boundThis);
+        ASSERT(function->structure()->globalObject());
+        function->finishCreation(vm);
+        return function;
+    }
+    
+    static ConstructType getConstructData(JSCell*, ConstructData&);
+
+    JSValue boundThis() { return m_boundThis.get(); }
+    
+    DECLARE_EXPORT_INFO;
+    
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        ASSERT(globalObject);
+        return Structure::create(vm, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), info());
+    }
+    
+    static inline ptrdiff_t offsetOfThisValue()
+    {
+        return OBJECT_OFFSETOF(JSArrowFunction, m_boundThis);
+    }
+    
+    const static unsigned StructureFlags = Base::StructureFlags;
+
+protected:
+    static void visitChildren(JSCell*, SlotVisitor&);
+        
+private:
+    JSArrowFunction(VM&, FunctionExecutable*, JSScope*, JSValue);
+    
+    friend class LLIntOffsetsExtractor;
+    
+    WriteBarrier<Unknown> m_boundThis;
+};
+    
+} // namespace JSC
+
+#endif // JSArrowFunction_h
index 0b87d75..928350e 100644 (file)
@@ -141,6 +141,7 @@ public:
 protected:
     JS_EXPORT_PRIVATE JSFunction(VM&, JSGlobalObject*, Structure*);
     JSFunction(VM&, FunctionExecutable*, JSScope*);
+    JSFunction(VM&, FunctionExecutable*, JSScope*, Structure*);
 
     void finishCreation(VM&, NativeExecutable*, int length, const String& name);
     using Base::finishCreation;
index f6c6d58..f059584 100644 (file)
@@ -44,6 +44,13 @@ inline JSFunction::JSFunction(VM& vm, FunctionExecutable* executable, JSScope* s
     , m_rareData()
 {
 }
+    
+inline JSFunction::JSFunction(VM& vm, FunctionExecutable* executable, JSScope* scope, Structure* structure)
+    : Base(vm, scope, structure)
+    , m_executable(vm, this, executable)
+    , m_rareData()
+{
+}
 
 inline FunctionExecutable* JSFunction::jsExecutable() const
 {
index 25ace92..15264ef 100644 (file)
@@ -60,6 +60,7 @@
 #include "JSArrayBufferConstructor.h"
 #include "JSArrayBufferPrototype.h"
 #include "JSArrayIterator.h"
+#include "JSArrowFunction.h"
 #include "JSBoundFunction.h"
 #include "JSCInlines.h"
 #include "JSCallbackConstructor.h"
@@ -260,6 +261,7 @@ void JSGlobalObject::init(VM& vm)
     exec->setCallee(m_globalCallee.get());
 
     m_functionStructure.set(vm, this, JSFunction::createStructure(vm, this, m_functionPrototype.get()));
+    m_arrowFunctionStructure.set(vm, this, JSArrowFunction::createStructure(vm, this, m_functionPrototype.get()));
     m_boundFunctionStructure.set(vm, this, JSBoundFunction::createStructure(vm, this, m_functionPrototype.get()));
     m_namedFunctionStructure.set(vm, this, Structure::addPropertyTransition(vm, m_functionStructure.get(), vm.propertyNames->name, DontDelete | ReadOnly | DontEnum, m_functionNameOffset));
     m_internalFunctionStructure.set(vm, this, InternalFunction::createStructure(vm, this, m_functionPrototype.get()));
@@ -797,6 +799,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(&thisObject->m_calleeStructure);
     visitor.append(&thisObject->m_functionStructure);
     visitor.append(&thisObject->m_boundFunctionStructure);
+    visitor.append(&thisObject->m_arrowFunctionStructure);
     visitor.append(&thisObject->m_namedFunctionStructure);
     visitor.append(&thisObject->m_symbolObjectStructure);
     visitor.append(&thisObject->m_regExpStructure);
index 9986bcf..bd12b29 100644 (file)
@@ -232,6 +232,7 @@ protected:
     WriteBarrier<Structure> m_calleeStructure;
     WriteBarrier<Structure> m_functionStructure;
     WriteBarrier<Structure> m_boundFunctionStructure;
+    WriteBarrier<Structure> m_arrowFunctionStructure;
     WriteBarrier<Structure> m_namedFunctionStructure;
     PropertyOffset m_functionNameOffset;
     WriteBarrier<Structure> m_privateNameStructure;
@@ -462,6 +463,7 @@ public:
     Structure* calleeStructure() const { return m_calleeStructure.get(); }
     Structure* functionStructure() const { return m_functionStructure.get(); }
     Structure* boundFunctionStructure() const { return m_boundFunctionStructure.get(); }
+    Structure* arrowFunctionStructure() const { return m_arrowFunctionStructure.get(); }
     Structure* namedFunctionStructure() const { return m_namedFunctionStructure.get(); }
     PropertyOffset functionNameOffset() const { return m_functionNameOffset; }
     Structure* numberObjectStructure() const { return m_numberObjectStructure.get(); }
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 (file)
index 0000000..c1e3a66
--- /dev/null
@@ -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 (file)
index 0000000..e41bbe1
--- /dev/null
@@ -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 (file)
index 0000000..2e437af
--- /dev/null
@@ -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 (file)
index 0000000..76a79ec
--- /dev/null
@@ -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 (file)
index 0000000..9203208
--- /dev/null
@@ -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 (file)
index 0000000..6877e0a
--- /dev/null
@@ -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 (file)
index 0000000..15beb55
--- /dev/null
@@ -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 (file)
index 0000000..4cfab24
--- /dev/null
@@ -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 (file)
index 0000000..117db30
--- /dev/null
@@ -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 (file)
index 0000000..1019086
--- /dev/null
@@ -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 (file)
index 0000000..85bd363
--- /dev/null
@@ -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 (file)
index 0000000..875494c
--- /dev/null
@@ -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 (file)
index 0000000..c417bc7
--- /dev/null
@@ -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 (file)
index 0000000..ad10a31
--- /dev/null
@@ -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 (file)
index 0000000..ca43063
--- /dev/null
@@ -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 (file)
index 0000000..869e027
--- /dev/null
@@ -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 (file)
index 0000000..7ffcb3f
--- /dev/null
@@ -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 (file)
index 0000000..057ea07
--- /dev/null
@@ -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 (file)
index 0000000..14ce0c6
--- /dev/null
@@ -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 (file)
index 0000000..07a1f0a
--- /dev/null
@@ -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 (file)
index 0000000..5ddcdb3
--- /dev/null
@@ -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 (file)
index 0000000..0e5f6bc
--- /dev/null
@@ -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 (file)
index 0000000..dc4271f
--- /dev/null
@@ -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 (file)
index 0000000..d2862c6
--- /dev/null
@@ -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 (file)
index 0000000..727f3ca
--- /dev/null
@@ -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 (file)
index 0000000..8db70bb
--- /dev/null
@@ -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 (file)
index 0000000..6874923
--- /dev/null
@@ -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 (file)
index 0000000..753ec0d
--- /dev/null
@@ -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");
+}