[ES6] "super" and "this" should be lexically bound inside an arrow function and shoul...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Dec 2015 09:46:12 +0000 (09:46 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Dec 2015 09:46:12 +0000 (09:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=149338

Source/JavaScriptCore:

Patch by Aleksandr Skachkov <gskachkov@gmail.com> on 2015-12-01
Reviewed by Saam Barati.

Implemented new version of the lexically bound 'this' in arrow function. In current version
'this' is stored inside of the lexical environment of the function. To store and load we use
op_get_from_scope and op_put_to_scope operations. Also new implementation prevent raising TDZ
error for arrow functions that are declared before super() but invoke after.

* builtins/BuiltinExecutables.cpp:
(JSC::createExecutableInternal):
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
* bytecode/EvalCodeCache.h:
(JSC::EvalCodeCache::getSlow):
* bytecode/ExecutableInfo.h:
(JSC::ExecutableInfo::ExecutableInfo):
(JSC::ExecutableInfo::isDerivedConstructorContext):
(JSC::ExecutableInfo::isArrowFunctionContext):
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::isDerivedConstructorContext):
(JSC::UnlinkedCodeBlock::isArrowFunctionContext):
* bytecode/UnlinkedFunctionExecutable.cpp:
(JSC::generateUnlinkedFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
* bytecode/UnlinkedFunctionExecutable.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::initializeArrowFunctionContextScopeIfNeeded):
(JSC::BytecodeGenerator::variable):
(JSC::BytecodeGenerator::emitLoadArrowFunctionLexicalEnvironment):
(JSC::BytecodeGenerator::emitLoadThisFromArrowFunctionLexicalEnvironment):
(JSC::BytecodeGenerator::emitLoadNewTargetFromArrowFunctionLexicalEnvironment):
(JSC::BytecodeGenerator::emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment):
(JSC::BytecodeGenerator::emitPutNewTargetToArrowFunctionContextScope):
(JSC::BytecodeGenerator::emitPutDerivedConstructorToArrowFunctionContextScope):
(JSC::BytecodeGenerator::emitPutThisToArrowFunctionContextScope):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::isDerivedConstructorContext):
(JSC::BytecodeGenerator::usesArrowFunction):
(JSC::BytecodeGenerator::needsToUpdateArrowFunctionContext):
(JSC::BytecodeGenerator::usesEval):
(JSC::BytecodeGenerator::usesThis):
(JSC::BytecodeGenerator::newTarget):
(JSC::BytecodeGenerator::makeFunction):
* bytecompiler/NodesCodegen.cpp:
(JSC::ThisNode::emitBytecode):
(JSC::SuperNode::emitBytecode):
(JSC::EvalFunctionCallNode::emitBytecode):
(JSC::FunctionCallValueNode::emitBytecode):
(JSC::FunctionNode::emitBytecode):
* debugger/DebuggerCallFrame.cpp:
(JSC::DebuggerCallFrame::evaluate):
* dfg/DFGAbstractInterpreterInlines.h:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
* dfg/DFGClobberize.h:
* dfg/DFGDoesGC.cpp:
* dfg/DFGFixupPhase.cpp:
* dfg/DFGNodeType.h:
* dfg/DFGObjectAllocationSinkingPhase.cpp:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGPromotedHeapLocation.cpp:
* dfg/DFGPromotedHeapLocation.h:
* dfg/DFGSafeToExecute.h:
* dfg/DFGSpeculativeJIT.cpp:
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
* dfg/DFGSpeculativeJIT64.cpp:
* ftl/FTLCapabilities.cpp:
* ftl/FTLLowerDFGToLLVM.cpp:
* ftl/FTLOperations.cpp:
(JSC::FTL::operationMaterializeObjectInOSR):
* interpreter/Interpreter.cpp:
(JSC::eval):
* jit/JIT.cpp:
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emitNewFuncExprCommon):
* jit/JITOpcodes32_64.cpp:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createArrowFunctionExpr):
(JSC::ASTBuilder::usesArrowFunction):
* parser/Nodes.h:
(JSC::ScopeNode::usesArrowFunction):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseFunctionInfo):
* parser/ParserModes.h:
* runtime/CodeCache.cpp:
(JSC::CodeCache::getGlobalCodeBlock):
(JSC::CodeCache::getProgramCodeBlock):
(JSC::CodeCache::getEvalCodeBlock):
(JSC::CodeCache::getModuleProgramCodeBlock):
(JSC::CodeCache::getFunctionExecutableFromGlobalCode):
* runtime/CodeCache.h:
* runtime/CommonIdentifiers.h:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/Executable.cpp:
(JSC::ScriptExecutable::ScriptExecutable):
(JSC::EvalExecutable::create):
(JSC::EvalExecutable::EvalExecutable):
(JSC::ProgramExecutable::ProgramExecutable):
(JSC::ModuleProgramExecutable::ModuleProgramExecutable):
(JSC::FunctionExecutable::FunctionExecutable):
* runtime/Executable.h:
(JSC::ScriptExecutable::isArrowFunctionContext):
(JSC::ScriptExecutable::isDerivedConstructorContext):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::createEvalCodeBlock):
* runtime/JSGlobalObject.h:
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::globalFuncEval):
* tests/es6.yaml:
* tests/stress/arrowfunction-activation-sink-osrexit.js:
* tests/stress/arrowfunction-activation-sink.js:
* tests/stress/arrowfunction-lexical-bind-newtarget.js: Added.
* tests/stress/arrowfunction-lexical-bind-supercall-1.js: Added.
* tests/stress/arrowfunction-lexical-bind-supercall-2.js: Added.
* tests/stress/arrowfunction-lexical-bind-supercall-3.js: Added.
* tests/stress/arrowfunction-lexical-bind-supercall-4.js: Added.
* tests/stress/arrowfunction-lexical-bind-this-1.js:
* tests/stress/arrowfunction-lexical-bind-this-7.js: Added.
* tests/stress/arrowfunction-tdz-1.js: Added.
* tests/stress/arrowfunction-tdz-2.js: Added.
* tests/stress/arrowfunction-tdz-3.js: Added.
* tests/stress/arrowfunction-tdz-4.js: Added.
* tests/stress/arrowfunction-tdz.js: Removed.

LayoutTests:

Patch by Skachkov Oleksandr <gskachkov@gmail.com> on 2015-12-01
Reviewed by Saam Barati.

* js/arrowfunction-supercall-expected.txt: Added.
* js/arrowfunction-supercall.html: Added.
* js/arrowfunction-tdz-expected.txt: Added new expectation.
* js/script-tests/arrowfunction-supercall.js: Added.
* js/script-tests/arrowfunction-tdz.js: Added new cases.

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

77 files changed:
LayoutTests/ChangeLog
LayoutTests/js/arrowfunction-supercall-expected.txt [new file with mode: 0644]
LayoutTests/js/arrowfunction-supercall.html [new file with mode: 0644]
LayoutTests/js/arrowfunction-tdz-expected.txt
LayoutTests/js/script-tests/arrowfunction-supercall.js [new file with mode: 0644]
LayoutTests/js/script-tests/arrowfunction-tdz.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/BuiltinExecutables.cpp
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/EvalCodeCache.h
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/debugger/DebuggerCallFrame.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/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/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
Source/JavaScriptCore/ftl/FTLOperations.cpp
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/parser/ASTBuilder.h
Source/JavaScriptCore/parser/Nodes.h
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/ParserModes.h
Source/JavaScriptCore/runtime/CodeCache.cpp
Source/JavaScriptCore/runtime/CodeCache.h
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/Executable.cpp
Source/JavaScriptCore/runtime/Executable.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
Source/JavaScriptCore/tests/es6.yaml
Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink-osrexit.js
Source/JavaScriptCore/tests/stress/arrowfunction-activation-sink.js
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-newtarget.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-supercall-1.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-supercall-2.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-supercall-3.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-supercall-4.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-1.js
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-7.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-tdz-1.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-tdz-2.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-tdz-3.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-tdz-4.js [new file with mode: 0644]
Source/JavaScriptCore/tests/stress/arrowfunction-tdz.js [deleted file]

index 419d7f8..32d92a5 100644 (file)
@@ -1,3 +1,16 @@
+2015-12-01  Skachkov Oleksandr  <gskachkov@gmail.com>
+
+        [ES6] "super" and "this" should be lexically bound inside an arrow function and should live in a JSLexicalEnvironment
+        https://bugs.webkit.org/show_bug.cgi?id=149338
+
+        Reviewed by Saam Barati.
+
+        * js/arrowfunction-supercall-expected.txt: Added.
+        * js/arrowfunction-supercall.html: Added.
+        * js/arrowfunction-tdz-expected.txt: Added new expectation.
+        * js/script-tests/arrowfunction-supercall.js: Added.
+        * js/script-tests/arrowfunction-tdz.js: Added new cases.
+
 2015-12-01  Youenn Fablet  <youenn.fablet@crf.canon.fr>
 
         [Streams API] streams should not directly use Number and related methods
diff --git a/LayoutTests/js/arrowfunction-supercall-expected.txt b/LayoutTests/js/arrowfunction-supercall-expected.txt
new file mode 100644 (file)
index 0000000..8a39c37
--- /dev/null
@@ -0,0 +1,27 @@
+Tests for ES6 arrow function, calling of the super in arrow function
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS isReferenceError is true
+PASS b.id is value
+PASS isReferenceError is true
+PASS d1.id is "b"
+PASS d2.id is value
+PASS (new D()).id is value
+PASS (new E(false)).id is value
+PASS typeof (new E(true)).id is 'undefined'
+PASS (new F(false)).id is value
+PASS typeof (new F(true)).id is 'undefined'
+PASS indexOfParentClassInStackError < indexOfnestedArrowInStackError is true
+PASS indexOfnestedArrowInStackError < indexOfarrowInChildConstructorInStackError is true
+PASS indexOfarrowInChildConstructorInStackError < indexOfChildClassInStackError is true
+PASS indexOfChildClassInStackError > 0 is true
+PASS indexOfParentClassInStackError > -1 && errorStack.indexOf('ParentClass', indexOfParentClassInStackError + 1) === -1 is true
+PASS indexOfnestedArrowInStackError > -1 && errorStack.indexOf('nestedArrow', indexOfnestedArrowInStackError + 1) === -1 is true
+PASS indexOfarrowInChildConstructorInStackError > -1 && errorStack.indexOf('arrowInChildConstructor', indexOfarrowInChildConstructorInStackError + 1) === -1 is true
+PASS indexOfChildClassInStackError > -1 && errorStack.indexOf('ChildClass', indexOfChildClassInStackError + 1) === -1 is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/arrowfunction-supercall.html b/LayoutTests/js/arrowfunction-supercall.html
new file mode 100644 (file)
index 0000000..6d98e81
--- /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-supercall.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
index 17af6cd..fcb6a44 100644 (file)
@@ -4,6 +4,14 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS isReferenceError is true
+PASS isReferenceError is true
+PASS d.id is 'a'
+PASS e.id is 'a'
+PASS f.id is 'a'
+PASS isReferenceError is true
+PASS g.id is 'a'
+PASS h.id is 'a'
+PASS i.id is 'a'
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/LayoutTests/js/script-tests/arrowfunction-supercall.js b/LayoutTests/js/script-tests/arrowfunction-supercall.js
new file mode 100644 (file)
index 0000000..2cef609
--- /dev/null
@@ -0,0 +1,151 @@
+description('Tests for ES6 arrow function, calling of the super in arrow function');
+
+var value = 'abcd-1234';
+
+var A = class A {
+  constructor() {
+    this.id = value;
+  }
+};
+
+var B = class B extends A {
+  constructor(accessThisBeforeSuper) {
+    var f = () =>  { super(); };
+    if (accessThisBeforeSuper) {
+      if (this.id !== value) throw new Error('Should be reference error because of TDZ');
+      f();
+    } else {
+      f();
+      if (this.id !== value) throw new Error('wrong value');
+    }
+  }
+};
+
+var isReferenceError = false;
+try {
+    new B(true);
+} catch (e) {
+    isReferenceError = e instanceof ReferenceError;
+}
+
+shouldBe('isReferenceError', 'true');
+
+var b = new B(false);
+shouldBe('b.id', 'value');
+
+var C = class C extends A {
+  constructor(runSuperInConstructor, forceTDZ) {
+    var f1 = () =>  { if (!forceTDZ) super();  this.id = 'b'; };
+    var f2 = () =>  { if (this.id !== 'b') throw new Error('wrong bound of the this'); };
+    var f3 = () =>  { if (this.id !== value) throw new Error('wrong bound of the this'); };
+
+    if (runSuperInConstructor) {
+      super();
+      f3();
+    } else {
+      f1();
+      f2();
+    }
+  }
+};
+
+isReferenceError = false;
+try {
+    new C(false, true);
+} catch (e) {
+    isReferenceError = e instanceof ReferenceError;
+}
+shouldBe('isReferenceError', 'true');
+var d1 = new C(false, false);
+shouldBe('d1.id', '"b"');
+
+var d2 = new C(true, false);
+shouldBe('d2.id', 'value');
+
+var D = class D extends A {
+  constructor () {
+    var arrow = () => {
+      let __proto__ = 'some-text';
+      var arr = () => {
+          let value = __proto__ + 'text';
+          super();
+      };
+
+      arr();
+    };
+
+    arrow();
+  }
+};
+shouldBe('(new D()).id', 'value');
+
+class E extends A {
+  constructor(doReplaceProto) {
+    var arrow = () => {
+      if (doReplaceProto)
+        E.__proto__ = function () {};
+      super();
+    };
+
+    arrow();
+  }
+};
+shouldBe('(new E(false)).id', "value");
+shouldBe('typeof (new E(true)).id', "'undefined'");
+
+class F extends A {
+  constructor(doReplaceProto) {
+    var arrow = () => super();
+    if (doReplaceProto)
+      F.__proto__ = function () {};
+    arrow();
+  }
+};
+shouldBe('(new F(false)).id', "value");
+shouldBe('typeof (new F(true)).id',  "'undefined'");
+
+var errorStack;
+
+var ParentClass = class ParentClass {
+  constructor() {
+    try {
+      this.idValue = testValue;
+      throw new Error('Error');
+    } catch (e) {
+      errorStack  = e.stack;
+    }
+  }
+};
+
+var ChildClass = class ChildClass extends ParentClass {
+  constructor () {
+    var arrowInChildConstructor = () => {
+      var nestedArrow = () => {
+        super();
+      }
+
+      nestedArrow();
+    };
+
+    arrowInChildConstructor();
+  }
+};
+
+var c = new ChildClass();
+
+var indexOfParentClassInStackError = errorStack.indexOf('ParentClass');
+var indexOfnestedArrowInStackError = errorStack.indexOf('nestedArrow');
+var indexOfarrowInChildConstructorInStackError = errorStack.indexOf('arrowInChildConstructor');
+var indexOfChildClassInStackError = errorStack.indexOf('ChildClass');
+
+shouldBeTrue("indexOfParentClassInStackError < indexOfnestedArrowInStackError");
+shouldBeTrue("indexOfnestedArrowInStackError < indexOfarrowInChildConstructorInStackError");
+shouldBeTrue("indexOfarrowInChildConstructorInStackError < indexOfChildClassInStackError");
+shouldBeTrue("indexOfChildClassInStackError > 0");
+
+shouldBeTrue("indexOfParentClassInStackError > -1 && errorStack.indexOf('ParentClass', indexOfParentClassInStackError + 1) === -1");
+shouldBeTrue("indexOfnestedArrowInStackError > -1 && errorStack.indexOf('nestedArrow', indexOfnestedArrowInStackError + 1) === -1");
+shouldBeTrue("indexOfarrowInChildConstructorInStackError > -1 && errorStack.indexOf('arrowInChildConstructor', indexOfarrowInChildConstructorInStackError + 1) === -1");
+shouldBeTrue("indexOfChildClassInStackError > -1 && errorStack.indexOf('ChildClass', indexOfChildClassInStackError + 1) === -1");
+
+var successfullyParsed = true;
index aaf58fc..b41aa67 100644 (file)
@@ -1,13 +1,20 @@
 description('Tests for ES6 arrow function test tdz');
 
-var A = class A { };
+var A = class A {
+  constructor() {
+    this.id = 'a';
+  }
+};
+
 var B = class B extends A {
   constructor(accessThisBeforeSuper) {
+    var f = () => this;
     if (accessThisBeforeSuper) {
-      var f = () => this;
+      f();
       super();
     } else {
       super();
+      f();
     }
   }
 };
@@ -21,6 +28,65 @@ try {
 
 shouldBe('isReferenceError', 'true');
 
-var e = new B(false);
+var a = new B(false);
+
+var D = class D extends A {
+  constructor(accessThisBeforeSuper, returnThis) {
+    var f = () => returnThis ? this : {};
+    if (accessThisBeforeSuper) {
+      let val = f();
+      super();
+    } else {
+      super();
+      let val = f();
+    }
+  }
+};
+
+isReferenceError = false;
+try {
+      new D(true, true);
+} catch (e) {
+      isReferenceError = e instanceof ReferenceError;
+}
+
+shouldBe('isReferenceError', 'true');
+
+var d = new D(false, true);
+shouldBe('d.id', "'a'");
+var e = new D(false, false);
+shouldBe('e.id', "'a'");
+var f = new D(true, false);
+shouldBe('f.id', "'a'");
+
+var G = class G extends A {
+  constructor(accessThisBeforeSuper, returnThis) {
+    var f = () => returnThis ? (() => this ) : (()=>{});
+    let af = f();
+    if (accessThisBeforeSuper) {
+      let result = af();
+      super();
+    } else {
+      super();
+      let result = af();
+    }
+  }
+};
+
+try {
+      new G(true, true);
+} catch (e) {
+    exception = e;
+    isReferenceError = e instanceof ReferenceError;
+}
+
+shouldBe('isReferenceError', 'true');
+
+var g = new G(false, true);
+shouldBe('g.id', "'a'");
+var h = new G(false, false);
+shouldBe('h.id', "'a'");
+var i = new G(true, false);
+shouldBe('i.id', "'a'");
 
 var successfullyParsed = true;
index e080def..33b4244 100644 (file)
@@ -1,3 +1,145 @@
+2015-12-01 Aleksandr Skachkov   <gskachkov@gmail.com>
+
+        [ES6] "super" and "this" should be lexically bound inside an arrow function and should live in a JSLexicalEnvironment
+        https://bugs.webkit.org/show_bug.cgi?id=149338
+
+        Reviewed by Saam Barati.
+
+        Implemented new version of the lexically bound 'this' in arrow function. In current version 
+        'this' is stored inside of the lexical environment of the function. To store and load we use
+        op_get_from_scope and op_put_to_scope operations. Also new implementation prevent raising TDZ
+        error for arrow functions that are declared before super() but invoke after.
+
+        * builtins/BuiltinExecutables.cpp:
+        (JSC::createExecutableInternal):
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        * bytecode/EvalCodeCache.h:
+        (JSC::EvalCodeCache::getSlow):
+        * bytecode/ExecutableInfo.h:
+        (JSC::ExecutableInfo::ExecutableInfo):
+        (JSC::ExecutableInfo::isDerivedConstructorContext):
+        (JSC::ExecutableInfo::isArrowFunctionContext):
+        * bytecode/UnlinkedCodeBlock.cpp:
+        (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
+        * bytecode/UnlinkedCodeBlock.h:
+        (JSC::UnlinkedCodeBlock::isDerivedConstructorContext):
+        (JSC::UnlinkedCodeBlock::isArrowFunctionContext):
+        * bytecode/UnlinkedFunctionExecutable.cpp:
+        (JSC::generateUnlinkedFunctionCodeBlock):
+        (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
+        * bytecode/UnlinkedFunctionExecutable.h:
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        (JSC::BytecodeGenerator::initializeArrowFunctionContextScopeIfNeeded):
+        (JSC::BytecodeGenerator::variable):
+        (JSC::BytecodeGenerator::emitLoadArrowFunctionLexicalEnvironment):
+        (JSC::BytecodeGenerator::emitLoadThisFromArrowFunctionLexicalEnvironment):
+        (JSC::BytecodeGenerator::emitLoadNewTargetFromArrowFunctionLexicalEnvironment):
+        (JSC::BytecodeGenerator::emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment):
+        (JSC::BytecodeGenerator::emitPutNewTargetToArrowFunctionContextScope):
+        (JSC::BytecodeGenerator::emitPutDerivedConstructorToArrowFunctionContextScope):
+        (JSC::BytecodeGenerator::emitPutThisToArrowFunctionContextScope):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::isDerivedConstructorContext):
+        (JSC::BytecodeGenerator::usesArrowFunction):
+        (JSC::BytecodeGenerator::needsToUpdateArrowFunctionContext):
+        (JSC::BytecodeGenerator::usesEval):
+        (JSC::BytecodeGenerator::usesThis):
+        (JSC::BytecodeGenerator::newTarget):
+        (JSC::BytecodeGenerator::makeFunction):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ThisNode::emitBytecode):
+        (JSC::SuperNode::emitBytecode):
+        (JSC::EvalFunctionCallNode::emitBytecode):
+        (JSC::FunctionCallValueNode::emitBytecode):
+        (JSC::FunctionNode::emitBytecode):
+        * debugger/DebuggerCallFrame.cpp:
+        (JSC::DebuggerCallFrame::evaluate):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        * dfg/DFGClobberize.h:
+        * dfg/DFGDoesGC.cpp:
+        * dfg/DFGFixupPhase.cpp:
+        * dfg/DFGNodeType.h:
+        * dfg/DFGObjectAllocationSinkingPhase.cpp:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGPromotedHeapLocation.cpp:
+        * dfg/DFGPromotedHeapLocation.h:
+        * dfg/DFGSafeToExecute.h:
+        * dfg/DFGSpeculativeJIT.cpp:
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        * dfg/DFGSpeculativeJIT64.cpp:
+        * ftl/FTLCapabilities.cpp:
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        * ftl/FTLOperations.cpp:
+        (JSC::FTL::operationMaterializeObjectInOSR):
+        * interpreter/Interpreter.cpp:
+        (JSC::eval):
+        * jit/JIT.cpp:
+        * jit/JIT.h:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emitNewFuncExprCommon):
+        * jit/JITOpcodes32_64.cpp:
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::createArrowFunctionExpr):
+        (JSC::ASTBuilder::usesArrowFunction):
+        * parser/Nodes.h:
+        (JSC::ScopeNode::usesArrowFunction):
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseFunctionInfo):
+        * parser/ParserModes.h:
+        * runtime/CodeCache.cpp:
+        (JSC::CodeCache::getGlobalCodeBlock):
+        (JSC::CodeCache::getProgramCodeBlock):
+        (JSC::CodeCache::getEvalCodeBlock):
+        (JSC::CodeCache::getModuleProgramCodeBlock):
+        (JSC::CodeCache::getFunctionExecutableFromGlobalCode):
+        * runtime/CodeCache.h:
+        * runtime/CommonIdentifiers.h:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/Executable.cpp:
+        (JSC::ScriptExecutable::ScriptExecutable):
+        (JSC::EvalExecutable::create):
+        (JSC::EvalExecutable::EvalExecutable):
+        (JSC::ProgramExecutable::ProgramExecutable):
+        (JSC::ModuleProgramExecutable::ModuleProgramExecutable):
+        (JSC::FunctionExecutable::FunctionExecutable):
+        * runtime/Executable.h:
+        (JSC::ScriptExecutable::isArrowFunctionContext):
+        (JSC::ScriptExecutable::isDerivedConstructorContext):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::createEvalCodeBlock):
+        * runtime/JSGlobalObject.h:
+        * runtime/JSGlobalObjectFunctions.cpp:
+        (JSC::globalFuncEval):
+        * tests/es6.yaml:
+        * tests/stress/arrowfunction-activation-sink-osrexit.js:
+        * tests/stress/arrowfunction-activation-sink.js:
+        * tests/stress/arrowfunction-lexical-bind-newtarget.js: Added.
+        * tests/stress/arrowfunction-lexical-bind-supercall-1.js: Added.
+        * tests/stress/arrowfunction-lexical-bind-supercall-2.js: Added.
+        * tests/stress/arrowfunction-lexical-bind-supercall-3.js: Added.
+        * tests/stress/arrowfunction-lexical-bind-supercall-4.js: Added.
+        * tests/stress/arrowfunction-lexical-bind-this-1.js:
+        * tests/stress/arrowfunction-lexical-bind-this-7.js: Added.
+        * tests/stress/arrowfunction-tdz-1.js: Added.
+        * tests/stress/arrowfunction-tdz-2.js: Added.
+        * tests/stress/arrowfunction-tdz-3.js: Added.
+        * tests/stress/arrowfunction-tdz-4.js: Added.
+        * tests/stress/arrowfunction-tdz.js: Removed.
+
 2015-12-01  Youenn Fablet  <youenn.fablet@crf.canon.fr>
 
         [Streams API] streams should not directly use Number and related methods
index 816b4a5..c81e26c 100644 (file)
@@ -115,7 +115,7 @@ UnlinkedFunctionExecutable* createExecutableInternal(VM& vm, const SourceCode& s
     }
     metadata->overrideName(name);
     VariableEnvironment dummyTDZVariables;
-    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, kind, constructAbility, dummyTDZVariables, WTF::move(sourceOverride));
+    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, kind, constructAbility, dummyTDZVariables, false, WTF::move(sourceOverride));
     functionExecutable->setNameValue(vm, jsString(&vm, name.string()));
     return functionExecutable;
 }
index f6c89a9..61ee4d7 100644 (file)
@@ -90,7 +90,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_new_arrow_func_exp", "length" : 4 },
             { "name" : "op_call", "length" : 9 },
             { "name" : "op_tail_call", "length" : 9 },
             { "name" : "op_call_eval", "length" : 9 },
             { "name" : "op_enumerator_structure_pname", "length" : 4 },
             { "name" : "op_enumerator_generic_pname", "length" : 4 },
             { "name" : "op_to_index_string", "length" : 3 },
-            { "name" : "op_load_arrowfunction_this", "length" : 2 },
             { "name" : "op_assert", "length" : 3 },
             { "name" : "op_copy_rest", "length": 4 },
             { "name" : "op_get_rest_length", "length": 3 }
index cbb8948..5a20f48 100644 (file)
@@ -57,7 +57,6 @@ void computeUsesForBytecodeOffset(
         return;
     case op_assert:
     case op_get_scope:
-    case op_load_arrowfunction_this:
     case op_to_this:
     case op_check_tdz:
     case op_profile_will_call:
@@ -371,7 +370,6 @@ 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 9e1386e..ce51aef 100644 (file)
@@ -757,11 +757,6 @@ 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");
@@ -1307,9 +1302,8 @@ void CodeBlock::dumpBytecode(
             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());
+            out.printf("%s, %s, f%d", registerName(r0).data(), registerName(r1).data(), f0);
             break;
         }
         case op_new_func_exp: {
index 62521fc..e2d6a41 100644 (file)
@@ -50,12 +50,12 @@ namespace JSC {
                 return m_cacheMap.get(evalSource.impl()).get();
             return 0;
         }
-        
-        EvalExecutable* getSlow(ExecState* exec, JSCell* owner, bool inStrictContext, ThisTDZMode thisTDZMode, const String& evalSource, JSScope* scope)
+
+        EvalExecutable* getSlow(ExecState* exec, JSCell* owner, bool inStrictContext, ThisTDZMode thisTDZMode, bool isDerivedConstructorContext, bool isArrowFunctionContext, const String& evalSource, JSScope* scope)
         {
             VariableEnvironment variablesUnderTDZ;
             JSScope::collectVariablesUnderTDZ(scope, variablesUnderTDZ);
-            EvalExecutable* evalExecutable = EvalExecutable::create(exec, makeSource(evalSource), inStrictContext, thisTDZMode, &variablesUnderTDZ);
+            EvalExecutable* evalExecutable = EvalExecutable::create(exec, makeSource(evalSource), inStrictContext, thisTDZMode, isDerivedConstructorContext, isArrowFunctionContext, &variablesUnderTDZ);
             if (!evalExecutable)
                 return 0;
 
index 92144f8..13246cc 100644 (file)
@@ -31,7 +31,7 @@
 namespace JSC {
 
 struct ExecutableInfo {
-    ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind, bool isArrowFunction)
+    ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind, bool isArrowFunction, bool isDerivedConstructorContext, bool isArrowFunctionContext)
         : m_needsActivation(needsActivation)
         , m_usesEval(usesEval)
         , m_isStrictMode(isStrictMode)
@@ -39,6 +39,8 @@ struct ExecutableInfo {
         , m_isBuiltinFunction(isBuiltinFunction)
         , m_constructorKind(static_cast<unsigned>(constructorKind))
         , m_isArrowFunction(isArrowFunction)
+        , m_isDerivedConstructorContext(isDerivedConstructorContext)
+        , m_isArrowFunctionContext(isArrowFunctionContext)
     {
         ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind));
     }
@@ -50,6 +52,8 @@ struct ExecutableInfo {
     bool isBuiltinFunction() const { return m_isBuiltinFunction; }
     ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
     bool isArrowFunction() const { return m_isArrowFunction; }
+    bool isDerivedConstructorContext() const { return m_isDerivedConstructorContext; }
+    bool isArrowFunctionContext() const { return m_isArrowFunctionContext; }
 
 private:
     unsigned m_needsActivation : 1;
@@ -59,6 +63,8 @@ private:
     unsigned m_isBuiltinFunction : 1;
     unsigned m_constructorKind : 2;
     unsigned m_isArrowFunction : 1;
+    unsigned m_isDerivedConstructorContext : 1;
+    unsigned m_isArrowFunctionContext : 1;
 };
 
 } // namespace JSC
index c114b9b..4de594d 100644 (file)
@@ -66,6 +66,8 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType code
     , m_isBuiltinFunction(info.isBuiltinFunction())
     , m_constructorKind(static_cast<unsigned>(info.constructorKind()))
     , m_isArrowFunction(info.isArrowFunction())
+    , m_isDerivedConstructorContext(info.isDerivedConstructorContext())
+    , m_isArrowFunctionContext(info.isArrowFunctionContext())
     , m_firstLine(0)
     , m_lineCount(0)
     , m_endColumn(UINT_MAX)
index fa514c1..8807bee 100644 (file)
@@ -117,6 +117,8 @@ public:
     bool isStrictMode() const { return m_isStrictMode; }
     bool usesEval() const { return m_usesEval; }
     bool isArrowFunction() const { return m_isArrowFunction; }
+    bool isDerivedConstructorContext() const { return m_isDerivedConstructorContext; }
+    bool isArrowFunctionContext() const { return m_isArrowFunctionContext; }
 
     bool needsFullScopeChain() const { return m_needsFullScopeChain; }
 
@@ -388,6 +390,8 @@ private:
     unsigned m_isBuiltinFunction : 1;
     unsigned m_constructorKind : 2;
     unsigned m_isArrowFunction : 1;
+    unsigned m_isDerivedConstructorContext : 1;
+    unsigned m_isArrowFunctionContext : 1;
 
     unsigned m_firstLine;
     unsigned m_lineCount;
index 6da1859..2eab1b5 100644 (file)
@@ -67,7 +67,7 @@ static UnlinkedFunctionCodeBlock* generateUnlinkedFunctionCodeBlock(
     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(), isArrowFunction));
+        ExecutableInfo(function->needsActivation(), function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind(), isArrowFunction, executable->isDerivedConstructorContext(), false));
     auto generator(std::make_unique<BytecodeGenerator>(vm, function.get(), result, debuggerMode, profilerMode, executable->parentScopeTDZVariables()));
     error = generator->generate();
     if (error.isValid())
@@ -75,7 +75,7 @@ static UnlinkedFunctionCodeBlock* generateUnlinkedFunctionCodeBlock(
     return result;
 }
 
-UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, VariableEnvironment& parentScopeTDZVariables)
+UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, VariableEnvironment& parentScopeTDZVariables, bool isDerivedConstructorContext)
     : Base(*vm, structure)
     , m_name(node->ident())
     , m_inferredName(node->inferredName())
@@ -100,6 +100,7 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct
     , m_constructorKind(static_cast<unsigned>(node->constructorKind()))
     , m_functionMode(node->functionMode())
     , m_isArrowFunction(node->isArrowFunction())
+    , m_isDerivedConstructorContext(isDerivedConstructorContext)
 {
     ASSERT(m_constructorKind == static_cast<unsigned>(node->constructorKind()));
     m_parentScopeTDZVariables.swap(parentScopeTDZVariables);
index d8e8229..7b2d7b2 100644 (file)
@@ -65,10 +65,10 @@ public:
     typedef JSCell Base;
     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 
-    static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, VariableEnvironment& parentScopeTDZVariables, RefPtr<SourceProvider>&& sourceOverride = nullptr)
+    static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, VariableEnvironment& parentScopeTDZVariables, bool isDerivedConstructorContext, RefPtr<SourceProvider>&& sourceOverride = nullptr)
     {
         UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm->heap))
-            UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, WTF::move(sourceOverride), node, unlinkedFunctionKind, constructAbility, parentScopeTDZVariables);
+            UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, WTF::move(sourceOverride), node, unlinkedFunctionKind, constructAbility, parentScopeTDZVariables, isDerivedConstructorContext);
         instance->finishCreation(*vm);
         return instance;
     }
@@ -126,9 +126,10 @@ public:
     bool isClassConstructorFunction() const { return constructorKind() != ConstructorKind::None; }
     const VariableEnvironment* parentScopeTDZVariables() const { return &m_parentScopeTDZVariables; }
     bool isArrowFunction() const { return m_isArrowFunction; }
+    bool isDerivedConstructorContext() const {return m_isDerivedConstructorContext; }
 
 private:
-    UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, VariableEnvironment&);
+    UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, VariableEnvironment&, bool isDerivedConstructorContext);
     WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForCall;
     WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct;
 
@@ -159,6 +160,7 @@ private:
     unsigned m_constructorKind : 2;
     unsigned m_functionMode : 1; // FunctionMode
     unsigned m_isArrowFunction : 1;
+    unsigned m_isDerivedConstructorContext : 1;
 
 protected:
     void finishCreation(VM& vm)
index 1abbba4..d58ff41 100644 (file)
@@ -155,6 +155,8 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedP
     , m_thisRegister(CallFrame::thisArgumentOffset())
     , m_codeType(GlobalCode)
     , m_vm(&vm)
+    , m_isDerivedConstructorContext(false)
+    , m_needsToUpdateArrowFunctionContext(programNode->usesArrowFunction() || programNode->usesEval())
 {
     ASSERT_UNUSED(parentScopeTDZVariables, !parentScopeTDZVariables->size());
 
@@ -185,6 +187,11 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedP
     // operations we emit we will have ResolveTypes that implictly do TDZ checks. Therefore, we don't need
     // additional TDZ checks on top of those. This is why we can omit pushing programNode->lexicalVariables()
     // to the TDZ stack.
+    
+    if (needsToUpdateArrowFunctionContext()) {
+        initializeArrowFunctionContextScopeIfNeeded();
+        emitPutThisToArrowFunctionContextScope();
+    }
 }
 
 BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, UnlinkedFunctionCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode, const VariableEnvironment* parentScopeTDZVariables)
@@ -202,6 +209,8 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     // compatible with tail calls (we have no way of emitting op_did_call).
     // https://bugs.webkit.org/show_bug.cgi?id=148819
     , m_inTailPosition(Options::useTailCalls() && !isConstructor() && constructorKind() == ConstructorKind::None && isStrictMode() && !m_shouldEmitProfileHooks)
+    , m_isDerivedConstructorContext(codeBlock->isDerivedConstructorContext())
+    , m_needsToUpdateArrowFunctionContext(functionNode->usesArrowFunction() || functionNode->usesEval())
 {
     for (auto& constantRegister : m_linkTimeConstantRegisters)
         constantRegister = nullptr;
@@ -226,8 +235,9 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
             pattern->collectBoundIdentifiers(boundParameterProperties);
         }
     }
-
-    bool shouldCaptureSomeOfTheThings = m_shouldEmitDebugHooks || m_codeBlock->needsFullScopeChain();
+    
+    bool containsArrowOrEvalButNotInArrowBlock = needsToUpdateArrowFunctionContext() && !m_codeBlock->isArrowFunction();
+    bool shouldCaptureSomeOfTheThings = m_shouldEmitDebugHooks || m_codeBlock->needsFullScopeChain() || containsArrowOrEvalButNotInArrowBlock;
     bool shouldCaptureAllOfTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval();
     bool needsArguments = functionNode->usesArguments() || codeBlock->usesEval();
     if (shouldCaptureAllOfTheThings)
@@ -492,16 +502,21 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
             instructions().append(0);
             instructions().append(0);
         }
-    } else {
-        if (functionNode->usesThis() || codeBlock->usesEval())
-            emitLoadArrowFunctionThis(&m_thisRegister);
-    }
+    } else if (functionNode->usesThis())
+        emitLoadThisFromArrowFunctionLexicalEnvironment();
 
     // All "addVar()"s needs to happen before "initializeDefaultParameterValuesAndSetupFunctionScopeStack()" is called
     // because a function's default parameter ExpressionNodes will use temporary registers.
     m_TDZStack.append(std::make_pair(*parentScopeTDZVariables, false));
     initializeDefaultParameterValuesAndSetupFunctionScopeStack(parameters, functionNode, functionSymbolTable, symbolTableConstantIndex, captures);
 
+    if (needsToUpdateArrowFunctionContext() && !codeBlock->isArrowFunction()) {
+        initializeArrowFunctionContextScopeIfNeeded(functionSymbolTable);
+        emitPutThisToArrowFunctionContextScope();
+        emitPutNewTargetToArrowFunctionContextScope();
+        emitPutDerivedConstructorToArrowFunctionContextScope();
+    }
+
     pushLexicalScope(m_scopeNode, true);
 }
 
@@ -514,6 +529,8 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCod
     , m_codeType(EvalCode)
     , m_vm(&vm)
     , m_usesNonStrictEval(codeBlock->usesEval() && !codeBlock->isStrictMode())
+    , m_isDerivedConstructorContext(codeBlock->isDerivedConstructorContext())
+    , m_needsToUpdateArrowFunctionContext(evalNode->usesArrowFunction() || evalNode->usesEval())
 {
     for (auto& constantRegister : m_linkTimeConstantRegisters)
         constantRegister = nullptr;
@@ -543,6 +560,14 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCod
 
     m_TDZStack.append(std::make_pair(*parentScopeTDZVariables, false));
 
+    if (codeBlock->isArrowFunctionContext() && evalNode->usesThis())
+        emitLoadThisFromArrowFunctionLexicalEnvironment();
+
+    if (needsToUpdateArrowFunctionContext() && !codeBlock->isArrowFunctionContext()) {
+        initializeArrowFunctionContextScopeIfNeeded();
+        emitPutThisToArrowFunctionContextScope();
+    }
+    
     pushLexicalScope(m_scopeNode, true);
 }
 
@@ -555,6 +580,8 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, ModuleProgramNode* moduleProgramNod
     , m_codeType(ModuleCode)
     , m_vm(&vm)
     , m_usesNonStrictEval(false)
+    , m_isDerivedConstructorContext(false)
+    , m_needsToUpdateArrowFunctionContext(moduleProgramNode->usesArrowFunction() || moduleProgramNode->usesEval())
 {
     ASSERT_UNUSED(parentScopeTDZVariables, !parentScopeTDZVariables->size());
 
@@ -790,6 +817,59 @@ void BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeSta
     }
 }
 
+void BytecodeGenerator::initializeArrowFunctionContextScopeIfNeeded(SymbolTable* symbolTable)
+{
+    if (m_arrowFunctionContextLexicalEnvironmentRegister != nullptr)
+        return;
+    
+    if (m_lexicalEnvironmentRegister != nullptr) {
+        m_arrowFunctionContextLexicalEnvironmentRegister = m_lexicalEnvironmentRegister;
+        
+        if (!m_codeBlock->isArrowFunction()) {
+            ScopeOffset offset;
+
+            offset = symbolTable->takeNextScopeOffset();
+            symbolTable->set(propertyNames().thisIdentifier.impl(), SymbolTableEntry(VarOffset(offset)));
+
+            if (m_codeType == FunctionCode) {
+                offset = symbolTable->takeNextScopeOffset();
+                symbolTable->set(propertyNames().newTargetLocalPrivateName.impl(), SymbolTableEntry(VarOffset(offset)));
+            }
+            
+            if (isConstructor() && constructorKind() == ConstructorKind::Derived) {
+                offset = symbolTable->takeNextScopeOffset();
+                symbolTable->set(propertyNames().derivedConstructorPrivateName.impl(), SymbolTableEntry(VarOffset(offset)));
+            }
+        }
+
+        return;
+    }
+
+    VariableEnvironment environment;
+    auto addResult = environment.add(propertyNames().thisIdentifier);
+    addResult.iterator->value.setIsCaptured();
+    addResult.iterator->value.setIsConst();
+    
+    if (m_codeType == FunctionCode)  {
+        auto addTarget = environment.add(propertyNames().newTargetLocalPrivateName);
+        addTarget.iterator->value.setIsCaptured();
+        addTarget.iterator->value.setIsLet();
+    }
+
+    if (isConstructor() && constructorKind() == ConstructorKind::Derived) {
+        auto derivedConstructor = environment.add(propertyNames().derivedConstructorPrivateName);
+        derivedConstructor.iterator->value.setIsCaptured();
+        derivedConstructor.iterator->value.setIsLet();
+    }
+
+    size_t size = m_symbolTableStack.size();
+    pushLexicalScopeInternal(environment, true, nullptr, TDZRequirement::UnderTDZ, ScopeType::LetConstScope, ScopeRegisterType::Block);
+
+    ASSERT_UNUSED(size, m_symbolTableStack.size() == size + 1);
+
+    m_arrowFunctionContextLexicalEnvironmentRegister = m_symbolTableStack.last().m_scope;
+}
+
 RegisterID* BytecodeGenerator::initializeNextParameter()
 {
     VirtualRegister reg = virtualRegisterForArgument(m_codeBlock->numParameters());
@@ -1816,9 +1896,9 @@ void BytecodeGenerator::prepareLexicalScopeForNextForLoopIteration(VariableEnvir
     }
 }
 
-Variable BytecodeGenerator::variable(const Identifier& property)
+Variable BytecodeGenerator::variable(const Identifier& property, ThisResolutionType thisResolutionType)
 {
-    if (property == propertyNames().thisIdentifier) {
+    if (property == propertyNames().thisIdentifier && thisResolutionType == ThisResolutionType::Local) {
         return Variable(property, VarOffset(thisRegister()->virtualRegister()), thisRegister(),
             ReadOnly, Variable::SpecialVariable, 0, false);
     }
@@ -2515,9 +2595,6 @@ void BytecodeGenerator::emitNewFunctionCommon(RegisterID* dst, BaseFuncExprNode*
     instructions().append(dst->index());
     instructions().append(scopeRegister()->index());
     instructions().append(index);
-    
-    if (opcodeID == op_new_arrow_func_exp)
-        instructions().append(thisRegister()->index());
 }
 
 RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func)
@@ -2528,10 +2605,6 @@ RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* dst, FuncEx
 
 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;
 }
@@ -3127,13 +3200,6 @@ void BytecodeGenerator::allocateAndEmitScope()
     m_topMostScope = addVar();
     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)
 {
@@ -3802,6 +3868,64 @@ void BytecodeGenerator::popIndexedForInScope(RegisterID* localRegister)
     m_forInContextStack.removeLast();
 }
 
+RegisterID* BytecodeGenerator::emitLoadArrowFunctionLexicalEnvironment()
+{
+    ASSERT(m_codeBlock->isArrowFunction() || m_codeBlock->isArrowFunctionContext() || constructorKind() == ConstructorKind::Derived);
+    
+    m_resolvedArrowFunctionScopeContextRegister = emitResolveScope(nullptr, variable(propertyNames().thisIdentifier, ThisResolutionType::Scoped));
+    return m_resolvedArrowFunctionScopeContextRegister.get();
+}
+
+void BytecodeGenerator::emitLoadThisFromArrowFunctionLexicalEnvironment()
+{
+    emitGetFromScope(thisRegister(), emitLoadArrowFunctionLexicalEnvironment(), variable(propertyNames().thisIdentifier, ThisResolutionType::Scoped), DoNotThrowIfNotFound);
+}
+    
+RegisterID* BytecodeGenerator::emitLoadNewTargetFromArrowFunctionLexicalEnvironment()
+{
+    m_isNewTargetLoadedInArrowFunction = true;
+
+    Variable newTargetVar = variable(propertyNames().newTargetLocalPrivateName);
+    emitMove(m_newTargetRegister, emitGetFromScope(newTemporary(), emitLoadArrowFunctionLexicalEnvironment(), newTargetVar, ThrowIfNotFound));
+    
+    return m_newTargetRegister;
+}
+
+RegisterID* BytecodeGenerator::emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment()
+{
+    Variable protoScopeVar = variable(propertyNames().derivedConstructorPrivateName);
+    return emitGetFromScope(newTemporary(), emitLoadArrowFunctionLexicalEnvironment(), protoScopeVar, ThrowIfNotFound);
+}
+    
+void BytecodeGenerator::emitPutNewTargetToArrowFunctionContextScope()
+{
+    ASSERT(m_arrowFunctionContextLexicalEnvironmentRegister != nullptr);
+        
+    Variable newTargetVar = variable(propertyNames().newTargetLocalPrivateName);
+    emitPutToScope(m_arrowFunctionContextLexicalEnvironmentRegister, newTargetVar, newTarget(), DoNotThrowIfNotFound, Initialization);
+}
+    
+void BytecodeGenerator::emitPutDerivedConstructorToArrowFunctionContextScope()
+{
+    if (isConstructor() && constructorKind() == ConstructorKind::Derived) {
+        ASSERT(m_arrowFunctionContextLexicalEnvironmentRegister != nullptr);
+            
+        Variable protoScope = variable(propertyNames().derivedConstructorPrivateName);
+        emitPutToScope(m_arrowFunctionContextLexicalEnvironmentRegister, protoScope, &m_calleeRegister, DoNotThrowIfNotFound, Initialization);
+    }
+}
+    
+void BytecodeGenerator::emitPutThisToArrowFunctionContextScope()
+{
+    ASSERT(isDerivedConstructorContext() || m_arrowFunctionContextLexicalEnvironmentRegister != nullptr);
+        
+    if (isDerivedConstructorContext())
+        emitLoadArrowFunctionLexicalEnvironment();
+
+    Variable thisVar = variable(propertyNames().thisIdentifier, ThisResolutionType::Scoped);
+    emitPutToScope(isDerivedConstructorContext() ? m_resolvedArrowFunctionScopeContextRegister.get() : m_arrowFunctionContextLexicalEnvironmentRegister, thisVar, thisRegister(), DoNotThrowIfNotFound, NotInitialization);
+}
+
 void BytecodeGenerator::pushStructureForInScope(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister)
 {
     if (!localRegister)
index 07316b1..2c2ec96 100644 (file)
@@ -65,6 +65,8 @@ namespace JSC {
         ExpectArrayConstructor
     };
 
+    enum class ThisResolutionType { Local, Scoped };
+    
     class CallArguments {
     public:
         CallArguments(BytecodeGenerator&, ArgumentsNode*, unsigned additionalArguments = 0);
@@ -279,13 +281,18 @@ namespace JSC {
         const CommonIdentifiers& propertyNames() const { return *m_vm->propertyNames; }
 
         bool isConstructor() const { return m_codeBlock->isConstructor(); }
+        bool isDerivedConstructorContext() const { return m_codeBlock->isDerivedConstructorContext(); }
+        bool usesArrowFunction() const { return m_scopeNode->usesArrowFunction(); }
+        bool needsToUpdateArrowFunctionContext() const { return m_needsToUpdateArrowFunctionContext; }
+        bool usesEval() const { return m_scopeNode->usesEval(); }
+        bool usesThis() const { return m_scopeNode->usesThis(); }
         ConstructorKind constructorKind() const { return m_codeBlock->constructorKind(); }
 
         ParserError generate();
 
         bool isArgumentNumber(const Identifier&, int);
 
-        Variable variable(const Identifier&);
+        Variable variable(const Identifier&, ThisResolutionType = ThisResolutionType::Local);
         
         enum ExistingVariableMode { VerifyExisting, IgnoreExisting };
         void createVariable(const Identifier&, VarKind, SymbolTable*, ExistingVariableMode = VerifyExisting); // Creates the variable, or asserts that the already-created variable is sufficiently compatible.
@@ -293,7 +300,11 @@ namespace JSC {
         // Returns the register storing "this"
         RegisterID* thisRegister() { return &m_thisRegister; }
         RegisterID* argumentsRegister() { return m_argumentsRegister; }
-        RegisterID* newTarget() { return m_newTargetRegister; }
+        RegisterID* newTarget()
+        {
+            return !m_codeBlock->isArrowFunction() || m_isNewTargetLoadedInArrowFunction
+                ? m_newTargetRegister : emitLoadNewTargetFromArrowFunctionLexicalEnvironment();
+        }
 
         RegisterID* scopeRegister() { return m_scopeRegister; }
 
@@ -479,6 +490,10 @@ namespace JSC {
         void emitProfileType(RegisterID* registerToProfile, const JSTextPosition& startDivot, const JSTextPosition& endDivot);
 
         void emitProfileControlFlow(int);
+        
+        RegisterID* emitLoadArrowFunctionLexicalEnvironment();
+        void emitLoadThisFromArrowFunctionLexicalEnvironment();
+        RegisterID* emitLoadNewTargetFromArrowFunctionLexicalEnvironment();
 
         RegisterID* emitLoad(RegisterID* dst, bool);
         RegisterID* emitLoad(RegisterID* dst, const Identifier&);
@@ -623,6 +638,10 @@ namespace JSC {
         void emitGetScope();
         RegisterID* emitPushWithScope(RegisterID* objectScope);
         void emitPopWithScope();
+        void emitPutThisToArrowFunctionContextScope();
+        void emitPutNewTargetToArrowFunctionContextScope();
+        void emitPutDerivedConstructorToArrowFunctionContextScope();
+        RegisterID* emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment();
 
         void emitDebugHook(DebugHookID, unsigned line, unsigned charOffset, unsigned lineStart);
 
@@ -698,7 +717,6 @@ namespace JSC {
 
         void allocateCalleeSaveSpace();
         void allocateAndEmitScope();
-        RegisterID* emitLoadArrowFunctionThis(RegisterID*);
         void emitComplexPopScopes(RegisterID*, ControlFlowContext* topScope, ControlFlowContext* bottomScope);
 
         typedef HashMap<double, JSValue> NumberMap;
@@ -750,6 +768,8 @@ namespace JSC {
         
         UnlinkedFunctionExecutable* makeFunction(FunctionMetadataNode* metadata)
         {
+            bool newisDerivedConstructorContext = constructorKind() == ConstructorKind::Derived || (m_isDerivedConstructorContext && metadata->isArrowFunction());
+
             VariableEnvironment variablesUnderTDZ;
             getVariablesUnderTDZ(variablesUnderTDZ);
 
@@ -758,7 +778,7 @@ namespace JSC {
             if (parseMode == SourceParseMode::GetterMode || parseMode == SourceParseMode::SetterMode || parseMode == SourceParseMode::ArrowFunctionMode || (parseMode == SourceParseMode::MethodMode && metadata->constructorKind() == ConstructorKind::None))
                 constructAbility = ConstructAbility::CannotConstruct;
 
-            return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, variablesUnderTDZ);
+            return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, variablesUnderTDZ, newisDerivedConstructorContext);
         }
 
         void getVariablesUnderTDZ(VariableEnvironment&);
@@ -768,6 +788,7 @@ namespace JSC {
 
         void initializeVarLexicalEnvironment(int symbolTableConstantIndex);
         void initializeDefaultParameterValuesAndSetupFunctionScopeStack(FunctionParameters&, FunctionNode*, SymbolTable*, int symbolTableConstantIndex, const std::function<bool (UniquedStringImpl*)>& captures);
+        void initializeArrowFunctionContextScopeIfNeeded(SymbolTable* = nullptr);
 
     public:
         JSString* addStringConstant(const Identifier&);
@@ -809,6 +830,8 @@ namespace JSC {
         RegisterID* m_globalObjectRegister { nullptr };
         RegisterID* m_newTargetRegister { nullptr };
         RegisterID* m_linkTimeConstantRegisters[LinkTimeConstantCount];
+        RegisterID* m_arrowFunctionContextLexicalEnvironmentRegister { nullptr };
+        RefPtr<RegisterID> m_resolvedArrowFunctionScopeContextRegister;
 
         SegmentedVector<RegisterID*, 16> m_localRegistersForCalleeSaveRegisters;
         SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
@@ -863,6 +886,9 @@ namespace JSC {
         bool m_isBuiltinFunction { false };
         bool m_usesNonStrictEval { false };
         bool m_inTailPosition { false };
+        bool m_isDerivedConstructorContext { false };
+        bool m_needsToUpdateArrowFunctionContext;
+        bool m_isNewTargetLoadedInArrowFunction { false };
     };
 
 }
index 242738e..a2e84f2 100644 (file)
@@ -145,7 +145,10 @@ RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d
 
 RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived)
+    if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext())
+        generator.emitLoadThisFromArrowFunctionLexicalEnvironment();
+    
+    if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived || generator.isDerivedConstructorContext())
         generator.emitTDZCheck(generator.thisRegister());
 
     if (dst == generator.ignoredResult())
@@ -164,10 +167,17 @@ RegisterID* SuperNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
     if (dst == generator.ignoredResult())
         return 0;
 
-    RegisterID callee;
-    callee.setIndex(JSStack::Callee);
+    RegisterID* scopeId;
+    if (generator.isDerivedConstructorContext())
+        scopeId = generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment();
+    else {
+        RegisterID callee;
+        callee.setIndex(JSStack::Callee);
 
-    return generator.emitGetById(generator.finalDestination(dst), &callee, generator.propertyNames().underscoreProto);
+        scopeId = &callee;
+    }
+    
+    return generator.emitGetById(generator.finalDestination(dst), scopeId, generator.propertyNames().underscoreProto);
 }
 
 static RegisterID* emitSuperBaseForCallee(BytecodeGenerator& generator)
@@ -691,6 +701,21 @@ CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argume
 
 RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
+    // We need try to load 'this' before call eval in constructor, because 'this' can created by 'super' in some of the arrow function
+    // var A = class A {
+    //   constructor () { this.id = 'A'; }
+    // }
+    //
+    // var B = class B extend A {
+    //    constructor () {
+    //       var arrow = () => super();
+    //       arrow();
+    //       eval("this.id = 'B'");
+    //    }
+    // }
+    if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext())
+        generator.emitLoadThisFromArrowFunctionLexicalEnvironment();
+
     Variable var = generator.variable(generator.propertyNames().eval);
     if (RegisterID* local = var.local()) {
         RefPtr<RegisterID> func = generator.emitMove(generator.tempDestination(dst), local);
@@ -718,11 +743,16 @@ RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, Re
     RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get());
     CallArguments callArguments(generator, m_args);
     if (m_expr->isSuperNode()) {
-        ASSERT(generator.isConstructor());
-        ASSERT(generator.constructorKind() == ConstructorKind::Derived);
+        ASSERT(generator.isConstructor() || generator.isDerivedConstructorContext());
+        ASSERT(generator.constructorKind() == ConstructorKind::Derived || generator.isDerivedConstructorContext());
         generator.emitMove(callArguments.thisRegister(), generator.newTarget());
         RegisterID* ret = generator.emitConstruct(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd());
         generator.emitMove(generator.thisRegister(), ret);
+        
+        bool isConstructorKindDerived = generator.constructorKind() == ConstructorKind::Derived;
+        if (generator.isDerivedConstructorContext() || (isConstructorKindDerived && generator.needsToUpdateArrowFunctionContext()))
+            generator.emitPutThisToArrowFunctionContextScope();
+        
         return ret;
     }
     generator.emitLoad(callArguments.thisRegister(), jsUndefined());
@@ -2980,6 +3010,9 @@ void FunctionNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
 
     // If there is no return we must automatically insert one.
     if (!returnNode) {
+        if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext())
+            generator.emitLoadThisFromArrowFunctionLexicalEnvironment(); // Arrow function can invoke 'super' in constructor and before leave constructor we need load 'this' from lexical arrow function environment
+
         RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined());
         generator.emitProfileType(r0, ProfileTypeBytecodeFunctionReturnStatement); // Do not emit expression info for this profile because it's not in the user's source code.
         ASSERT(startOffset() >= lineStartOffset());
index d383c3f..d540550 100644 (file)
@@ -196,7 +196,7 @@ JSValue DebuggerCallFrame::evaluate(const String& script, NakedPtr<Exception>& e
     VariableEnvironment variablesUnderTDZ;
     JSScope::collectVariablesUnderTDZ(scope()->jsScope(), variablesUnderTDZ);
 
-    EvalExecutable* eval = EvalExecutable::create(callFrame, makeSource(script), codeBlock.isStrictMode(), thisTDZMode, &variablesUnderTDZ);
+    EvalExecutable* eval = EvalExecutable::create(callFrame, makeSource(script), codeBlock.isStrictMode(), thisTDZMode, codeBlock.unlinkedCodeBlock()->isDerivedConstructorContext(), codeBlock.unlinkedCodeBlock()->isArrowFunction(), &variablesUnderTDZ);
     if (vm.exception()) {
         exception = vm.exception();
         vm.clearException();
index fbe82e9..35cae39 100644 (file)
@@ -1805,15 +1805,6 @@ 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 439e620..268e267 100644 (file)
@@ -4514,17 +4514,6 @@ 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();
@@ -4574,24 +4563,20 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             NEXT_OPCODE(op_new_func);
         }
 
-        case op_new_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(NewFunction, OpInfo(frozen), get(VirtualRegister(currentInstruction[2].u.operand))));
-            NEXT_OPCODE(op_new_func_exp);
-        }
-
+        case 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))));
+                addToGraph(NewFunction, OpInfo(frozen), get(VirtualRegister(currentInstruction[2].u.operand))));
             
-            NEXT_OPCODE(op_new_arrow_func_exp);
+            if (opcodeID == op_new_func_exp) {
+                // Curly braces are necessary
+                NEXT_OPCODE(op_new_func_exp);
+            } else {
+                // Curly braces are necessary
+                NEXT_OPCODE(op_new_arrow_func_exp);
+            }
         }
 
         case op_typeof: {
index 7a5ec3f..6164972 100644 (file)
@@ -202,7 +202,6 @@ 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:
index a85586d..2637911 100644 (file)
@@ -139,7 +139,6 @@ 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:
index b26e0a5..16f973d 100644 (file)
@@ -107,7 +107,6 @@ bool doesGC(Graph& graph, Node* node)
     case GetButterflyReadOnly:
     case CheckArray:
     case GetScope:
-    case LoadArrowFunctionThis:
     case SkipScope:
     case GetClosureVar:
     case PutClosureVar:
index a957d2b..77bd380 100644 (file)
@@ -1012,11 +1012,6 @@ private:
             break;
         }
 
-        case LoadArrowFunctionThis: {
-            fixEdge<KnownCellUse>(node->child1());
-            break;
-        }
-
         case SkipScope:
         case GetScope:
         case GetGetter:
index 2ed3ce4..008d8c7 100644 (file)
@@ -207,7 +207,6 @@ 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) \
index db8dd6f..12ab163 100644 (file)
@@ -838,17 +838,14 @@ private:
 
         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, isArrowFunction ? Allocation::Kind::NewArrowFunction : Allocation::Kind::Function);
+            target = &m_heap.newAllocation(node, 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;
         }
 
@@ -1018,14 +1015,6 @@ 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())
@@ -2045,9 +2034,8 @@ private:
         
         case NewFunction:
         case NewArrowFunction: {
-            bool isArrowFunction = node->op() == NewArrowFunction;
             Vector<PromotedHeapLocation> locations = m_locationsForAllocation.get(escapee);
-            ASSERT(locations.size() == (isArrowFunction ? 3 : 2));
+            ASSERT(locations.size() == 2);
                 
             PromotedHeapLocation executable(FunctionExecutablePLoc, allocation.identifier());
             ASSERT_UNUSED(executable, locations.contains(executable));
@@ -2056,13 +2044,6 @@ private:
             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 59ae9f3..49d5c74 100644 (file)
@@ -594,10 +594,6 @@ private:
             changed |= setPrediction(SpecObjectOther);
             break;
 
-        case LoadArrowFunctionThis:
-            changed |= setPrediction(SpecFinalObject);
-            break;
-
         case In:
             changed |= setPrediction(SpecBoolean);
             break;
index 8fe1591..24f6977 100644 (file)
@@ -102,10 +102,6 @@ void printInternal(PrintStream& out, PromotedLocationKind kind)
     case ClosureVarPLoc:
         out.print("ClosureVarPLoc");
         return;
-
-    case ArrowFunctionBoundThisPLoc:
-        out.print("ArrowFunctionBoundThisPLoc");
-        return;
     }
     
     RELEASE_ASSERT_NOT_REACHED();
index 97293f3..b4e3c2b 100644 (file)
@@ -46,8 +46,7 @@ enum PromotedLocationKind {
     FunctionExecutablePLoc,
     FunctionActivationPLoc,
     ActivationScopePLoc,
-    ClosureVarPLoc,
-    ArrowFunctionBoundThisPLoc
+    ClosureVarPLoc
 };
 
 class PromotedLocationDescriptor {
index f5c68db..616c3b0 100644 (file)
@@ -202,7 +202,6 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case Arrayify:
     case ArrayifyToStructure:
     case GetScope:
-    case LoadArrowFunctionThis:
     case SkipScope:
     case GetClosureVar:
     case PutClosureVar:
index 800613c..d0781e6 100755 (executable)
@@ -4739,15 +4739,6 @@ void SpeculativeJIT::compileGetScope(Node* node)
     m_jit.loadPtr(JITCompiler::Address(function.gpr(), JSFunction::offsetOfScopeChain()), result.gpr());
     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)
 {
index 8660b04..c42ba31 100755 (executable)
@@ -2200,7 +2200,6 @@ public:
     void compileGetByValOnScopedArguments(Node*);
     
     void compileGetScope(Node*);
-    void compileLoadArrowFunctionThis(Node*);
     void compileSkipScope(Node*);
 
     void compileGetArrayLength(Node*);
index b0c4e94..6e0f146 100644 (file)
@@ -3799,10 +3799,6 @@ void SpeculativeJIT::compile(Node* node)
     case GetScope:
         compileGetScope(node);
         break;
-
-    case LoadArrowFunctionThis:
-        compileLoadArrowFunctionThis(node);
-        break;
             
     case SkipScope:
         compileSkipScope(node);
index 570332c..f11822d 100644 (file)
@@ -3837,10 +3837,6 @@ void SpeculativeJIT::compile(Node* node)
         compileGetScope(node);
         break;
             
-    case LoadArrowFunctionThis:
-        compileLoadArrowFunctionThis(node);
-        break;
-            
     case SkipScope:
         compileSkipScope(node);
         break;
index 64a4822..8728d9e 100644 (file)
@@ -152,7 +152,6 @@ inline CapabilityLevel canCompile(Node* node)
     case CountExecution:
     case GetExecutable:
     case GetScope:
-    case LoadArrowFunctionThis:
     case GetCallee:
     case GetArgumentCount:
     case ToString:
index 4adc1aa..072a32a 100644 (file)
@@ -810,9 +810,6 @@ private:
         case GetScope:
             compileGetScope();
             break;
-        case LoadArrowFunctionThis:
-            compileLoadArrowFunctionThis();
-            break;
         case SkipScope:
             compileSkipScope();
             break;
@@ -4507,11 +4504,6 @@ 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 c3672e8..37015b6 100644 (file)
@@ -164,25 +164,17 @@ 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 = isArrowFunction
-            ? JSArrowFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation, boundThis)
-            : JSFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation);
+        JSFunction* result = JSFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation);
 
         return result;
     }
index c54751c..ea3db19 100644 (file)
@@ -172,7 +172,7 @@ JSValue eval(CallFrame* callFrame)
         ASSERT(!callFrame->vm().exception());
 
         ThisTDZMode thisTDZMode = callerCodeBlock->unlinkedCodeBlock()->constructorKind() == ConstructorKind::Derived ? ThisTDZMode::AlwaysCheck : ThisTDZMode::CheckIfNeeded;
-        eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock, callerCodeBlock->isStrictMode(), thisTDZMode, programSource, callerScopeChain);
+        eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock, callerCodeBlock->isStrictMode(), thisTDZMode, callerCodeBlock->unlinkedCodeBlock()->isDerivedConstructorContext(), callerCodeBlock->unlinkedCodeBlock()->isArrowFunction(), programSource, callerScopeChain);
         if (!eval)
             return jsUndefined();
     }
index 2d6f02c..cb52c45 100644 (file)
@@ -221,7 +221,6 @@ 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_array_length:
index 6850f7a..515279f 100755 (executable)
@@ -500,7 +500,6 @@ 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*);
index f60ae57..cbbcf3f 100755 (executable)
@@ -684,14 +684,6 @@ 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)
 {
@@ -988,23 +980,14 @@ void JIT::emit_op_new_func_exp(Instruction* 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) {
-        int value = currentInstruction[4].u.operand;
-        emitLoad(value, regT3, regT2);
-    }
     notUndefinedScope = branch32(NotEqual, tagFor(currentInstruction[2].u.operand), TrustedImm32(JSValue::UndefinedTag));
     emitStore(dst, jsUndefined());
 #endif
@@ -1012,14 +995,7 @@ void JIT::emitNewFuncExprCommon(Instruction* currentInstruction)
     notUndefinedScope.link(this);
         
     FunctionExecutable* function = m_codeBlock->functionExpr(currentInstruction[3].u.operand);
-    if (isArrowFunction)
-#if USE(JSVALUE64)
-        callOperation(operationNewArrowFunction, dst, regT0, function, regT1);
-#else 
-        callOperation(operationNewArrowFunction, dst, regT0, function, regT3, regT2);
-#endif
-    else
-        callOperation(operationNewFunction, dst, regT0, function);
+    callOperation(operationNewFunction, dst, regT0, function);
     done.link(this);
 }
     
index 4e04365..89455ed 100644 (file)
@@ -938,14 +938,6 @@ 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 765f197..1a52aff 100644 (file)
@@ -1055,13 +1055,12 @@ LLINT_SLOW_PATH_DECL(slow_path_new_func_exp)
 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));
+    LLINT_RETURN(JSFunction::create(vm, executable, scope));
 }
 
 static SlowPathReturnType handleHostCall(ExecState* execCallee, Instruction* pc, JSValue callee, CodeSpecializationKind kind)
index 5ad5b3f..1bf13eb 100644 (file)
@@ -1461,7 +1461,7 @@ _llint_op_new_func_exp:
 _llint_op_new_arrow_func_exp:
     traceExecution()
     callSlowPath(_llint_slow_path_new_arrow_func_exp)
-    dispatch(5)
+    dispatch(4)
 
 _llint_op_call:
     traceExecution()
index e1d122c..c5a87e3 100644 (file)
@@ -2422,16 +2422,6 @@ _llint_op_profile_control_flow:
     dispatch(2)
 
 
-_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)
-
-
 _llint_op_get_rest_length:
     traceExecution()
     loadi PayloadOffset + ArgumentCount[cfr], t0
index 49f3cd7..e18d81c 100644 (file)
@@ -2284,22 +2284,14 @@ _llint_op_profile_type:
 .opProfileTypeDone:
     dispatch(6)
 
+
+
 _llint_op_profile_control_flow:
     traceExecution()
     loadpFromInstruction(1, t0)
     addq 1, BasicBlockLocation::m_executionCount[t0]
     dispatch(2)
 
-
-_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)
-
-
 _llint_op_get_rest_length:
     traceExecution()
     loadi PayloadOffset + ArgumentCount[cfr], t0
index ce985ca..b15a813 100644 (file)
@@ -374,7 +374,7 @@ public:
 
     ExpressionNode* createArrowFunctionExpr(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
     {
-        usesThis();
+        usesArrowFunction();
         SourceCode source = m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.body->isArrowFunctionBodyExpression() ? functionInfo.endOffset - 1 : functionInfo.endOffset, functionInfo.startLine, functionInfo.bodyStartColumn);
         ArrowFuncExprNode* result = new (m_parserArena) ArrowFuncExprNode(location, *functionInfo.name, functionInfo.body, source);
         functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);
@@ -912,6 +912,7 @@ private:
 
     void incConstants() { m_scope.m_numConstants++; }
     void usesThis() { m_scope.m_features |= ThisFeature; }
+    void usesArrowFunction() { m_scope.m_features |= ArrowFunctionFeature; }
     void usesArguments() { m_scope.m_features |= ArgumentsFeature; }
     void usesWith() { m_scope.m_features |= WithFeature; }
     void usesEval() 
index 5ca3466..d839c12 100644 (file)
@@ -1559,6 +1559,7 @@ namespace JSC {
 
         bool usesEval() const { return m_features & EvalFeature; }
         bool usesArguments() const { return (m_features & ArgumentsFeature) && !(m_features & ShadowsArgumentsFeature); }
+        bool usesArrowFunction() const { return m_features & ArrowFunctionFeature; }
         bool modifiesParameter() const { return m_features & ModifiedParameterFeature; }
         bool modifiesArguments() const { return m_features & (EvalFeature | ModifiedArgumentsFeature); }
         bool isStrictMode() const { return m_features & StrictModeFeature; }
index 0af2c5a..4f6ade8 100644 (file)
@@ -1876,11 +1876,11 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
         semanticFailIfTrue(m_vm->propertyNames->arguments == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
         semanticFailIfTrue(m_vm->propertyNames->eval == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
     }
-    if (functionScope->hasDirectSuper()) {
+    if (functionScope->hasDirectSuper() && functionBodyType == StandardFunctionBodyBlock) {
         semanticFailIfTrue(!isClassConstructor, "Cannot call super() outside of a class constructor");
         semanticFailIfTrue(constructorKind != ConstructorKind::Derived, "Cannot call super() in a base class constructor");
     }
-    if (functionScope->needsSuperBinding())
+    if (functionScope->needsSuperBinding() && functionBodyType == StandardFunctionBodyBlock)
         semanticFailIfTrue(expectedSuperBinding == SuperBinding::NotNeeded, "super can only be used in a method of a derived class");
 
     JSTokenLocation location = JSTokenLocation(m_token.m_location);
index 49585cb..5268d78 100644 (file)
@@ -143,17 +143,19 @@ inline bool functionNameScopeIsDynamic(bool usesEval, bool isStrictMode)
 
 typedef unsigned CodeFeatures;
 
-const CodeFeatures NoFeatures =                    0;
-const CodeFeatures EvalFeature =              1 << 0;
-const CodeFeatures ArgumentsFeature =         1 << 1;
-const CodeFeatures WithFeature =              1 << 2;
-const CodeFeatures ThisFeature =              1 << 3;
-const CodeFeatures StrictModeFeature =        1 << 4;
-const CodeFeatures ShadowsArgumentsFeature =  1 << 5;
-const CodeFeatures ModifiedParameterFeature = 1 << 6;
-const CodeFeatures ModifiedArgumentsFeature = 1 << 7;
-
-const CodeFeatures AllFeatures = EvalFeature | ArgumentsFeature | WithFeature | ThisFeature | StrictModeFeature | ShadowsArgumentsFeature | ModifiedParameterFeature;
+const CodeFeatures NoFeatures =                       0;
+const CodeFeatures EvalFeature =                 1 << 0;
+const CodeFeatures ArgumentsFeature =            1 << 1;
+const CodeFeatures WithFeature =                 1 << 2;
+const CodeFeatures ThisFeature =                 1 << 3;
+const CodeFeatures StrictModeFeature =           1 << 4;
+const CodeFeatures ShadowsArgumentsFeature =     1 << 5;
+const CodeFeatures ModifiedParameterFeature =    1 << 6;
+const CodeFeatures ModifiedArgumentsFeature =    1 << 7;
+const CodeFeatures ArrowFunctionFeature =        1 << 8;
+const CodeFeatures ArrowFunctionContextFeature = 1 << 9;
+
+const CodeFeatures AllFeatures = EvalFeature | ArgumentsFeature | WithFeature | ThisFeature | StrictModeFeature | ShadowsArgumentsFeature | ModifiedParameterFeature | ArrowFunctionFeature | ArrowFunctionContextFeature;
 
 } // namespace JSC
 
index f13b25e..c3ae1e3 100644 (file)
@@ -83,8 +83,7 @@ template <> struct CacheTypes<UnlinkedModuleProgramCodeBlock> {
 };
 
 template <class UnlinkedCodeBlockType, class ExecutableType>
-UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserBuiltinMode builtinMode,
-    JSParserStrictMode strictMode, ThisTDZMode thisTDZMode, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error, const VariableEnvironment* variablesUnderTDZ)
+UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, ThisTDZMode thisTDZMode, bool, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error, const VariableEnvironment* variablesUnderTDZ)
 {
     SourceCodeKey key = SourceCodeKey(source, String(), CacheTypes<UnlinkedCodeBlockType>::codeType, builtinMode, strictMode, thisTDZMode);
     SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key);
@@ -112,7 +111,8 @@ UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* exe
     bool endColumnIsOnStartLine = !lineCount;
     unsigned unlinkedEndColumn = rootNode->endColumn();
     unsigned endColumn = unlinkedEndColumn + (endColumnIsOnStartLine ? startColumn : 1);
-    executable->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->firstLine(), rootNode->lastLine(), startColumn, endColumn);
+    unsigned arrowContextFeature = executable->isArrowFunctionContext() ? ArrowFunctionContextFeature : 0;
+    executable->recordParse(rootNode->features() | arrowContextFeature, rootNode->hasCapturedVariables(), rootNode->firstLine(), rootNode->lastLine(), startColumn, endColumn);
 
     UnlinkedCodeBlockType* unlinkedCodeBlock = UnlinkedCodeBlockType::create(&vm, executable->executableInfo());
     unlinkedCodeBlock->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), rootNode->firstLine() - source.firstLine(), lineCount, unlinkedEndColumn);
@@ -132,18 +132,18 @@ UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* exe
 UnlinkedProgramCodeBlock* CodeCache::getProgramCodeBlock(VM& vm, ProgramExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
 {
     VariableEnvironment emptyParentTDZVariables;
-    return getGlobalCodeBlock<UnlinkedProgramCodeBlock>(vm, executable, source, builtinMode, strictMode, ThisTDZMode::CheckIfNeeded, debuggerMode, profilerMode, error, &emptyParentTDZVariables);
+    return getGlobalCodeBlock<UnlinkedProgramCodeBlock>(vm, executable, source, builtinMode, strictMode, ThisTDZMode::CheckIfNeeded, false, debuggerMode, profilerMode, error, &emptyParentTDZVariables);
 }
 
-UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, EvalExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, ThisTDZMode thisTDZMode, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error, const VariableEnvironment* variablesUnderTDZ)
+UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, EvalExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, ThisTDZMode thisTDZMode, bool isArrowFunctionContext, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error, const VariableEnvironment* variablesUnderTDZ)
 {
-    return getGlobalCodeBlock<UnlinkedEvalCodeBlock>(vm, executable, source, builtinMode, strictMode, thisTDZMode, debuggerMode, profilerMode, error, variablesUnderTDZ);
+    return getGlobalCodeBlock<UnlinkedEvalCodeBlock>(vm, executable, source, builtinMode, strictMode, thisTDZMode, isArrowFunctionContext, debuggerMode, profilerMode, error, variablesUnderTDZ);
 }
 
 UnlinkedModuleProgramCodeBlock* CodeCache::getModuleProgramCodeBlock(VM& vm, ModuleProgramExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
 {
     VariableEnvironment emptyParentTDZVariables;
-    return getGlobalCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, executable, source, builtinMode, JSParserStrictMode::Strict, ThisTDZMode::CheckIfNeeded, debuggerMode, profilerMode, error, &emptyParentTDZVariables);
+    return getGlobalCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, executable, source, builtinMode, JSParserStrictMode::Strict, ThisTDZMode::CheckIfNeeded, false, debuggerMode, profilerMode, error, &emptyParentTDZVariables);
 }
 
 // FIXME: There's no need to add the function's name to the key here. It's already in the source code.
@@ -188,7 +188,7 @@ UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& v
     metadata->setEndPosition(positionBeforeLastNewline);
     // The Function constructor only has access to global variables, so no variables will be under TDZ.
     VariableEnvironment emptyTDZVariables;
-    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, ConstructAbility::CanConstruct, emptyTDZVariables);
+    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, ConstructAbility::CanConstruct, emptyTDZVariables, false);
     functionExecutable->m_nameValue.set(vm, functionExecutable, jsString(&vm, name.string()));
 
     m_sourceCode.addCache(key, SourceCodeValue(vm, functionExecutable, m_sourceCode.age()));
index 48c8cfe..6d06de7 100644 (file)
@@ -258,7 +258,7 @@ public:
     ~CodeCache();
 
     UnlinkedProgramCodeBlock* getProgramCodeBlock(VM&, ProgramExecutable*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, DebuggerMode, ProfilerMode, ParserError&);
-    UnlinkedEvalCodeBlock* getEvalCodeBlock(VM&, EvalExecutable*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, ThisTDZMode, DebuggerMode, ProfilerMode, ParserError&, const VariableEnvironment*);
+    UnlinkedEvalCodeBlock* getEvalCodeBlock(VM&, EvalExecutable*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, ThisTDZMode, bool, DebuggerMode, ProfilerMode, ParserError&, const VariableEnvironment*);
     UnlinkedModuleProgramCodeBlock* getModuleProgramCodeBlock(VM&, ModuleProgramExecutable*, const SourceCode&, JSParserBuiltinMode, DebuggerMode, ProfilerMode, ParserError&);
     UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(VM&, const Identifier&, const SourceCode&, ParserError&);
 
@@ -269,7 +269,7 @@ public:
 
 private:
     template <class UnlinkedCodeBlockType, class ExecutableType> 
-    UnlinkedCodeBlockType* getGlobalCodeBlock(VM&, ExecutableType*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, ThisTDZMode, DebuggerMode, ProfilerMode, ParserError&, const VariableEnvironment*);
+    UnlinkedCodeBlockType* getGlobalCodeBlock(VM&, ExecutableType*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, ThisTDZMode, bool, DebuggerMode, ProfilerMode, ParserError&, const VariableEnvironment*);
 
     CodeCacheMap m_sourceCode;
 };
index 495f235..bdd76a0 100644 (file)
     macro(Uint32Array) \
     macro(Float32Array) \
     macro(Float64Array) \
+    macro(newTargetLocal) \
+    macro(derivedConstructor) \
+
 
 
 namespace JSC {
index 490636f..0b605fa 100644 (file)
@@ -225,7 +225,7 @@ SLOW_PATH_DECL(slow_path_create_this)
     
 #if !ASSERT_DISABLED
     ConstructData constructData;
-    ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS);
+    ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS || constructor->jsExecutable()->isArrowFunction());
 #endif
 
     auto& cacheWriteBarrier = pc[4].u.jsCell;
index 8365292..1892ac1 100644 (file)
@@ -131,13 +131,15 @@ Intrinsic NativeExecutable::intrinsic() const
 
 const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, CREATE_METHOD_TABLE(ScriptExecutable) };
 
-ScriptExecutable::ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext)
+ScriptExecutable::ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext, bool isInDerivedConstructorContext, bool isInArrowFunctionContext)
     : ExecutableBase(vm, structure, NUM_PARAMETERS_NOT_COMPILED)
     , m_source(source)
     , m_features(isInStrictContext ? StrictModeFeature : 0)
     , m_hasCapturedVariables(false)
     , m_neverInline(false)
     , m_didTryToEnterInLoop(false)
+    , m_isDerivedConstructorContext(isInDerivedConstructorContext)
+    , m_isArrowFunctionContext(isInArrowFunctionContext)
     , m_overrideLineNumber(-1)
     , m_firstLine(-1)
     , m_lastLine(-1)
@@ -412,7 +414,7 @@ JSObject* ScriptExecutable::prepareForExecutionImpl(
 
 const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(EvalExecutable) };
 
-EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext, ThisTDZMode thisTDZMode, const VariableEnvironment* variablesUnderTDZ)
+EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext, ThisTDZMode thisTDZMode, bool isDerivedConstructorContext, bool isArrowFunctionContext, const VariableEnvironment* variablesUnderTDZ)
 {
     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
     if (!globalObject->evalEnabled()) {
@@ -420,10 +422,10 @@ EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source
         return 0;
     }
 
-    EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext);
+    EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext, isDerivedConstructorContext, isArrowFunctionContext);
     executable->finishCreation(exec->vm());
 
-    UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable, thisTDZMode, variablesUnderTDZ);
+    UnlinkedEvalCodeBlock* unlinkedEvalCode = globalObject->createEvalCodeBlock(exec, executable, thisTDZMode, isArrowFunctionContext, variablesUnderTDZ);
     if (!unlinkedEvalCode)
         return 0;
 
@@ -432,8 +434,8 @@ EvalExecutable* EvalExecutable::create(ExecState* exec, const SourceCode& source
     return executable;
 }
 
-EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext)
-    : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec->vm(), source, inStrictContext)
+EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext, bool isDerivedConstructorContext, bool isArrowFunctionContext)
+    : ScriptExecutable(exec->vm().evalExecutableStructure.get(), exec->vm(), source, inStrictContext, isDerivedConstructorContext, isArrowFunctionContext)
 {
 }
 
@@ -445,7 +447,7 @@ void EvalExecutable::destroy(JSCell* cell)
 const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(ProgramExecutable) };
 
 ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source)
-    : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec->vm(), source, false)
+    : ScriptExecutable(exec->vm().programExecutableStructure.get(), exec->vm(), source, false, false, false)
 {
     m_typeProfilingStartOffset = 0;
     m_typeProfilingEndOffset = source.length() - 1;
@@ -461,7 +463,7 @@ void ProgramExecutable::destroy(JSCell* cell)
 const ClassInfo ModuleProgramExecutable::s_info = { "ModuleProgramExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(ModuleProgramExecutable) };
 
 ModuleProgramExecutable::ModuleProgramExecutable(ExecState* exec, const SourceCode& source)
-    : ScriptExecutable(exec->vm().moduleProgramExecutableStructure.get(), exec->vm(), source, false)
+    : ScriptExecutable(exec->vm().moduleProgramExecutableStructure.get(), exec->vm(), source, false, false, false)
 {
     m_typeProfilingStartOffset = 0;
     m_typeProfilingEndOffset = source.length() - 1;
@@ -492,10 +494,8 @@ void ModuleProgramExecutable::destroy(JSCell* cell)
 
 const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(FunctionExecutable) };
 
-FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, 
-    UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, 
-    unsigned lastLine, unsigned startColumn, unsigned endColumn)
-    : ScriptExecutable(vm.functionExecutableStructure.get(), vm, source, unlinkedExecutable->isInStrictContext())
+FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, UnlinkedFunctionExecutable* unlinkedExecutable, unsigned firstLine, unsigned lastLine, unsigned startColumn, unsigned endColumn)
+    : ScriptExecutable(vm.functionExecutableStructure.get(), vm, source, unlinkedExecutable->isInStrictContext(), unlinkedExecutable->isDerivedConstructorContext(), false)
     , m_unlinkedExecutable(vm, this, unlinkedExecutable)
 {
     RELEASE_ASSERT(!source.isNull());
index 9fc9be7..25068e9 100644 (file)
@@ -344,7 +344,9 @@ public:
     bool usesEval() const { return m_features & EvalFeature; }
     bool usesArguments() const { return m_features & ArgumentsFeature; }
     bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature); }
+    bool isArrowFunctionContext() const { return m_isArrowFunctionContext; }
     bool isStrictMode() const { return m_features & StrictModeFeature; }
+    bool isDerivedConstructorContext() const { return m_isDerivedConstructorContext; }
     ECMAMode ecmaMode() const { return isStrictMode() ? StrictMode : NotStrictMode; }
         
     void setNeverInline(bool value) { m_neverInline = value; }
@@ -393,7 +395,7 @@ private:
     JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind);
 
 protected:
-    ScriptExecutable(Structure* structure, VM& vm, const SourceCode& source, bool isInStrictContext);
+    ScriptExecutable(Structure*, VM&, const SourceCode&, bool isInStrictContext, bool isInDerivedConstructorContext, bool isInArrowFunctionContext);
 
     void finishCreation(VM& vm)
     {
@@ -412,6 +414,8 @@ protected:
     bool m_neverInline;
     bool m_neverOptimize { false };
     bool m_didTryToEnterInLoop;
+    bool m_isDerivedConstructorContext;
+    bool m_isArrowFunctionContext;
     int m_overrideLineNumber;
     int m_firstLine;
     int m_lastLine;
@@ -434,7 +438,7 @@ public:
         return m_evalCodeBlock.get();
     }
 
-    static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, ThisTDZMode, const VariableEnvironment*);
+    static EvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, ThisTDZMode, bool isDerivedConstructorContext, bool isArrowFunctionContext, const VariableEnvironment*);
 
     PassRefPtr<JITCode> generatedJITCode()
     {
@@ -448,7 +452,7 @@ public:
         
     DECLARE_INFO;
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false); }
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false, isDerivedConstructorContext(), isArrowFunctionContext()); }
 
     unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }
     unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }
@@ -456,7 +460,7 @@ public:
 private:
     friend class ExecutableBase;
     friend class ScriptExecutable;
-    EvalExecutable(ExecState*, const SourceCode&, bool);
+    EvalExecutable(ExecState*, const SourceCode&, bool inStrictContext, bool isDerivedConstructorContext, bool isArrowFunctionContext);
 
     static void visitChildren(JSCell*, SlotVisitor&);
 
@@ -501,7 +505,7 @@ public:
         
     DECLARE_INFO;
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false); }
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false, isDerivedConstructorContext(), false); }
 
 private:
     friend class ExecutableBase;
@@ -542,7 +546,8 @@ public:
 
     DECLARE_INFO;
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false); }
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false, isDerivedConstructorContext(), false); }
+
     UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCodeBlock() { return m_unlinkedModuleProgramCodeBlock.get(); }
 
     SymbolTable* moduleEnvironmentSymbolTable() { return m_moduleEnvironmentSymbolTable.get(); }
@@ -651,6 +656,7 @@ public:
     bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); }
     ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); }
     bool isArrowFunction() const { return m_unlinkedExecutable->isArrowFunction(); }
+    bool isDerivedConstructorContext() const { return m_unlinkedExecutable->isDerivedConstructorContext(); }
     bool isClassConstructorFunction() const { return m_unlinkedExecutable->isClassConstructorFunction(); }
     const Identifier& name() { return m_unlinkedExecutable->name(); }
     const Identifier& inferredName() { return m_unlinkedExecutable->inferredName(); }
index bc08f96..208ce47 100644 (file)
@@ -949,14 +949,14 @@ UnlinkedProgramCodeBlock* JSGlobalObject::createProgramCodeBlock(CallFrame* call
     return unlinkedCodeBlock;
 }
 
-UnlinkedEvalCodeBlock* JSGlobalObject::createEvalCodeBlock(CallFrame* callFrame, EvalExecutable* executable, ThisTDZMode thisTDZMode, const VariableEnvironment* variablesUnderTDZ)
+UnlinkedEvalCodeBlock* JSGlobalObject::createEvalCodeBlock(CallFrame* callFrame, EvalExecutable* executable, ThisTDZMode thisTDZMode, bool isArrowFunctionContext, const VariableEnvironment* variablesUnderTDZ)
 {
     ParserError error;
     JSParserStrictMode strictMode = executable->isStrictMode() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict;
     DebuggerMode debuggerMode = hasDebugger() ? DebuggerOn : DebuggerOff;
     ProfilerMode profilerMode = hasProfiler() ? ProfilerOn : ProfilerOff;
     UnlinkedEvalCodeBlock* unlinkedCodeBlock = vm().codeCache()->getEvalCodeBlock(
-        vm(), executable, executable->source(), JSParserBuiltinMode::NotBuiltin, strictMode, thisTDZMode, debuggerMode, profilerMode, error, variablesUnderTDZ);
+        vm(), executable, executable->source(), JSParserBuiltinMode::NotBuiltin, strictMode, thisTDZMode, isArrowFunctionContext, debuggerMode, profilerMode, error, variablesUnderTDZ);
 
     if (hasDebugger())
         debugger()->sourceParsed(callFrame, executable->source().provider(), error.line(), error.message());
index 8e1629c..37738e2 100644 (file)
@@ -661,7 +661,7 @@ public:
     unsigned weakRandomInteger() { return m_weakRandom.getUint32(); }
 
     UnlinkedProgramCodeBlock* createProgramCodeBlock(CallFrame*, ProgramExecutable*, JSObject** exception);
-    UnlinkedEvalCodeBlock* createEvalCodeBlock(CallFrame*, EvalExecutable*, ThisTDZMode, const VariableEnvironment*);
+    UnlinkedEvalCodeBlock* createEvalCodeBlock(CallFrame*, EvalExecutable*, ThisTDZMode, bool isArrowFunctionContext, const VariableEnvironment*);
     UnlinkedModuleProgramCodeBlock* createModuleProgramCodeBlock(CallFrame*, ModuleProgramExecutable*);
 
 protected:
index 2bf13bb..ce1e3bb 100644 (file)
@@ -581,7 +581,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
 
     JSGlobalObject* calleeGlobalObject = exec->callee()->globalObject();
     VariableEnvironment emptyTDZVariables; // Indirect eval does not have access to the lexical scope.
-    EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false, ThisTDZMode::CheckIfNeeded, &emptyTDZVariables);
+    EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false, ThisTDZMode::CheckIfNeeded, false, false, &emptyTDZVariables);
     if (!eval)
         return JSValue::encode(jsUndefined());
 
index 88d4a7c..771a3b5 100644 (file)
 - path: es6/arrow_functions_lexical_arguments_binding.js
   cmd: runES6 :fail
 - path: es6/arrow_functions_lexical_new.target_binding.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/arrow_functions_lexical_super_binding.js
   cmd: runES6 :fail
 - path: es6/arrow_functions_no_prototype_property.js
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-newtarget.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-newtarget.js
new file mode 100644 (file)
index 0000000..7a8d27c
--- /dev/null
@@ -0,0 +1,78 @@
+var testCase = function (actual, expected, message) {
+    if (actual !== expected) {
+        throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+    }
+};
+
+function getTarget(name) {
+    return x => new.target;
+}
+
+noInline(getTarget)
+
+for (var i=0; i < 1000; i++) {
+    var undefinedTarget = getTarget()();
+    testCase(undefinedTarget, undefined, "Error: new.target is not lexically binded inside of the arrow function #1");
+}
+
+for (var i = 0; i < 1000; i++) {
+    var newTarget = new getTarget()();
+    testCase(newTarget, getTarget, "Error: new.target is not lexically binded inside of the arrow function #2");
+}
+
+var passed = false;
+var A = class A {
+    constructor() {
+        this.idValue = 123;
+        passed = passed && new.target === B;
+    }
+};
+
+var B  = class B extends A {
+    constructor() {
+        var f = () => {
+            passed = new.target === B;
+            super();
+        };
+        f();
+    }
+};
+
+for (var i = 0; i < 1000; i++) {
+    passed = false;
+    var b = new B();
+
+    testCase(passed, true, "Error: new.target is not lexically binded inside of the arrow function in constructor #3");
+}
+
+var C = class C extends A {
+    constructor(tryToAccessToVarInArrow) {
+        var f = () => {
+            super();
+            if (tryToAccessToVarInArrow)
+                this.id2 = newTargetLocal;
+        };
+
+        f();
+
+        if (!tryToAccessToVarInArrow)
+            this.id = newTargetLocal;
+    }
+};
+
+var tryToCreateClass = function (val) {
+    var result = false;
+    try {
+        new C(val);
+    }
+    catch (e) {
+        result = e instanceof ReferenceError; 
+    }
+
+    return result;
+};
+
+for (var i = 0; i < 1000; i++) {
+    testCase(tryToCreateClass(true), true, "Error: newTargetLocal should be hided variable");
+    testCase(tryToCreateClass(false), true, "Error: newTargetLocal should be hided variable");
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-supercall-1.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-supercall-1.js
new file mode 100644 (file)
index 0000000..c247147
--- /dev/null
@@ -0,0 +1,67 @@
+var testCase = function (actual, expected, message) {
+    if (actual !== expected) {
+        throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+    }
+};
+
+var testValue  = 'test-value';
+
+var A = class A {
+    constructor() {
+        this.idValue = testValue;
+    }
+};
+
+var B = class B extends A {
+    constructor (inArrowFuction, inConstructor) {
+        var arrow = () => {
+            if (inArrowFuction) {
+                super();
+                testCase(this.idValue, testValue, "Error: super() should create this and put value into idValue property");
+            }
+        }
+
+        if (inArrowFuction)
+            arrow();
+
+        if (inConstructor)
+            super();
+
+        testCase(this.idValue, testValue, "Error: arrow function should return this to constructor");
+    }
+};
+
+for (var i = 0; i < 1000; i++) {
+    new B(true, false);
+    new B(false, true);
+}
+
+var testException = function (value1, value2, index) {
+    var exception;
+    try {
+        new B(value1, value2);
+    } 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 " + index;
+}
+
+for (var i=0; i < 1000; i++) {
+    testException(false, false, i);
+}
+
+var C = class C extends A {
+    constructor() {
+        eval("var x = 20");
+        super();
+        let f = () => this;
+        let xf = f();
+        xf.id = 'test-id';
+    }
+};
+
+var c = new C();
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-supercall-2.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-supercall-2.js
new file mode 100644 (file)
index 0000000..83c8e37
--- /dev/null
@@ -0,0 +1,176 @@
+var testCase = function (actual, expected, message) {
+    if (actual !== expected) {
+        throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+    }
+};
+
+var testValue  = 'test-value';
+
+var A = class A {
+    constructor() {
+        this.idValue = testValue;
+    }
+};
+
+var B = class B extends A {
+    constructor (inArrowFuction, inConstructor, setProtoToNull) {
+        var arrow = () => () => () => {
+            if (inArrowFuction) {
+              super();
+              testCase(this.idValue, testValue, "Error: super() should create this and put value into idValue property");
+            }
+        };
+
+        if (inArrowFuction)
+            arrow()()();
+
+        if (inConstructor)
+            super();
+
+        testCase(this.idValue, testValue, "Error: arrow function should return this to constructor");
+    }
+};
+
+for (var i=0; i < 1000; i++) {
+    new B(true, false);
+    new B(false, true);
+}
+
+var testException = function (index) {
+    var exception;
+    try {
+        new B(false, false);
+    } catch (e) {
+        exception = e;
+        if (!(e instanceof ReferenceError))
+            throw "Exception thrown was not a correct error. Expected ReferenceError but was " + e.name;
+    }
+
+    if (!exception)
+        throw "Exception not thrown for an unitialized this at iteration #" + index;
+}
+
+for (var i = 0; i < 1000; i++) {
+  testException(i, ReferenceError);
+}
+
+var C = class C extends A {
+    constructor () {
+      var arrow = () => {
+          let __proto__ = 'some-text';
+          var arr = () => {
+              testCase(typeof  __proto__, 'string', "Erorr: __proto__ variable has wrong type");
+              super();
+              testCase(this.idValue, testValue, "Error: super() should create this and put value into idValue property");
+           };
+           arr();
+       };
+
+      arrow();
+
+      testCase(this.idValue, testValue, "Error: arrow function should return this to constructor");
+    }
+};
+
+for (var i = 0; i < 1000; i++) {
+    new C();
+}
+
+class D extends A {
+    constructor(doReplaceProto) {
+        var arrow = () => super();
+        if (doReplaceProto)
+            D.__proto__ = function () {};
+        arrow();
+    }
+}
+
+testCase((new D(false)).idValue, testValue, "Error: arrow function bound wrong super");
+testCase(typeof (new D(true)).idValue, "undefined" , "Error: arrow function bound wrong super");
+
+class E extends A {
+    constructor(doReplaceProto) {
+        var arrow = () => {
+            if (doReplaceProto)
+                E.__proto__ = function () {};
+            super();
+        };
+
+        arrow();
+    }
+}
+
+testCase((new E(false)).idValue, testValue, "Error: arrow function bound wrong super #1");
+testCase(typeof (new E(true)).idValue, "undefined" , "Error: arrow function bound wrong super #1");
+
+
+class F extends A {
+    constructor(doReplaceProto) {
+        var arrow = () => {
+            F.__proto__ = null;
+            super();
+        };
+
+        arrow();
+    }
+}
+
+var testTypeErrorException = function (index) {
+    var exception;
+    try {
+        new F();
+    } catch (e) {
+        exception = e;
+        if (!(e instanceof TypeError))
+            throw "Exception thrown was not a correct error. Expected TypeError but was " + e.name;
+    }
+
+    if (!exception)
+        throw "Exception not thrown for an unitialized this at iteration #" + index;
+}
+
+for (var i = 0; i < 1000; i++) {
+  testTypeErrorException(i);
+}
+
+var errorStack;
+
+var ParentClass = class ParentClass {
+    constructor() {
+        try {
+            this.idValue = testValue;
+            throw new Error('Error');
+        } catch (e) {
+            errorStack  = e.stack;
+        }
+    }
+};
+
+var ChildClass = class ChildClass extends ParentClass {
+    constructor () {
+        var arrowInChildConstructor = () => {
+            var nestedArrow = () => {
+                super();
+            }
+
+            nestedArrow();
+        };
+
+        arrowInChildConstructor();
+    }
+};
+
+for (var i = 0; i < 1000; i++) {
+    errorStack = '';
+    let c = new ChildClass();
+
+    let parentClassIndexOf = errorStack.indexOf('ParentClass');
+    let nestedArrowIndexOf = errorStack.indexOf('nestedArrow');
+    let arrowInChildConstructorIndexOf = errorStack.indexOf('arrowInChildConstructor');
+    let childClassIndexOf = errorStack.indexOf('ChildClass');
+
+    testCase(parentClassIndexOf > -1 && errorStack.indexOf('ParentClass', parentClassIndexOf + 1) === -1, true, "Error: stack of error should contain ParentClass text");
+    testCase(nestedArrowIndexOf > -1 && errorStack.indexOf('nestedArrow', nestedArrowIndexOf + 1) === -1, true, "Error: stack of error should contain nestedArrow text");
+    testCase(arrowInChildConstructorIndexOf > -1 && errorStack.indexOf('arrowInChildConstructor', arrowInChildConstructorIndexOf + 1) === -1, true, "Error: stack of error should contain arrowInChildConstructor text");
+    testCase(childClassIndexOf > -1 && errorStack.indexOf('ChildClass', childClassIndexOf + 1) === -1, true, "Error: stack of error should contains ChildClass text");
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-supercall-3.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-supercall-3.js
new file mode 100644 (file)
index 0000000..6fbb6d5
--- /dev/null
@@ -0,0 +1,52 @@
+var testCase = function (actual, expected, message) {
+    if (actual !== expected) {
+        throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+    }
+};
+
+var testValue  = 'test-value';
+
+var A = class A {
+    constructor() {
+        this.idValue = testValue;
+    }
+};
+
+var B = class B extends A {
+    constructor (beforeSuper) {
+        var arrow = () => eval('(() => this.idValue)()');
+
+        if (beforeSuper) {
+            var result = arrow();
+            super();
+            testCase(result, testValue, "Error: has to be TDZ error");
+        } else {
+            super();
+            let result= arrow();
+            testCase(result, testValue, "Error: super() should create this and put value into idValue property");
+        }
+    }
+};
+
+for (var i = 0; i < 1000; i++) {
+    var b = new B(false);
+}
+
+var testException = function (value, index) {
+  var exception;
+  try {
+       new B(value);
+  } 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 #" + index;
+}
+
+
+for (var i = 0; i < 1000; i++) {
+    testException(true, i);
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-supercall-4.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-supercall-4.js
new file mode 100644 (file)
index 0000000..18a6f70
--- /dev/null
@@ -0,0 +1,80 @@
+var testCase = function (actual, expected, message) {
+    if (actual !== expected) {
+        throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+    }
+};
+
+var testValue  = 'test-value';
+
+var A = class A {
+    constructor() {
+        this.idValue = testValue;
+    }
+};
+
+var B = class B extends A {
+  constructor (beforeSuper) {
+
+      var arrow = () => eval('(() => super())()');
+
+      if (beforeSuper) {
+          arrow();
+          testCase(this.idValue, testValue, "Error: super() should create this and put value into idValue property");
+      } else {
+          testCase(this.idValue, testValue, "Error: has to be TDZ error");
+          arrow();
+      }
+  }
+};
+
+var C = class C extends A {
+    constructor () {
+        var arrow = () => eval('(() => super())()');
+        arrow();
+        return {};
+    }
+};
+
+var D = class D extends A {
+    constructor () {
+        var arrow = () => eval('(() => super())()');
+        arrow();
+        eval('this.id="new-value"');
+    }
+};
+
+var E = class E extends A {
+    constructor () {
+        var arrow = () => eval("eval('(() => super())()')");
+        arrow();
+        eval('eval("this.id=\'new-value\'")');
+    }
+};
+
+for (var i=0; i < 1000; i++) {
+    new B(true);
+    var c = new C();
+    testCase(typeof c.id, 'undefined', 'Error during set value in eval #1');
+    var d = new D();
+    testCase(d.id, 'new-value', 'Error during set value in eval #2');
+    var e = new E();
+    testCase(e.id, 'new-value', 'Error during set value in eval #3');
+}
+
+var testException = function (value, index) {
+    var exception;
+    try {
+        new B(value);
+    } 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 #" + index;
+}
+
+for (var i=0; i < 1000; i++) {
+    testException(false, i);
+}
index 4cfab24..69cb8cd 100644 (file)
@@ -8,6 +8,7 @@ function Dog(name) {
   this.name = name;
   this.getName = () => eval("this.name");
   this.getNameHard = () => eval("(() => this.name)()");
+  this.getNameReallyHard = () => eval("eval('(() => this.name)()')");
 }
 
 noInline(Dog)
@@ -16,4 +17,5 @@ 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");
+  testCase(d.getNameReallyHard(), d.name, "Error: this is not lexically binded inside of the arrow function #3");
 }
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-7.js b/Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-this-7.js
new file mode 100644 (file)
index 0000000..2f76c9d
--- /dev/null
@@ -0,0 +1,24 @@
+var testCase = function (actual, expected, message) {
+    if (actual !== expected) {
+        throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+    }
+};
+
+var deepScope = function (x, y) {
+    var _x = x, _y = y;
+    return ()=> _x + _y + this.val;
+};
+
+var a = deepScope.call({val:'A'}, 'D', 'E');
+var b = deepScope.call({val:'B'}, 'D', 'F');
+var c = deepScope.call({val:'C'}, 'D', 'G');
+
+var anotherScope = function (_af) {
+    return _af();
+};
+
+for (var i = 0; i < 1000; i++) {
+    testCase(c(), anotherScope.call({val:'I'}, c), "Error: this is not lexically binded inside of the arrow function #1");
+    testCase(b(), anotherScope.call({val:'J'}, b), "Error: this is not lexically binded inside of the arrow function #2");
+    testCase(a(), anotherScope.call({val:'K'}, a), "Error: this is not lexically binded inside of the arrow function #3");
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-tdz-1.js b/Source/JavaScriptCore/tests/stress/arrowfunction-tdz-1.js
new file mode 100644 (file)
index 0000000..8d4d9d4
--- /dev/null
@@ -0,0 +1,31 @@
+var A = class A { };
+var B = class B extends A {
+    constructor(beforeSuper, returnThis) {
+        var f = () => returnThis ? this : {};
+        if (beforeSuper) {
+            let val = f();
+            super();
+        } else {
+            super();
+            let val = f();
+        }
+    }
+};
+
+var exception = null;
+for (var i=0; i < 10000; i++) {
+    try {
+        new B(true, 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 a = new B(false, true);
+    var b = new B(false, false);
+    var c = new B(true, false);
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-tdz-2.js b/Source/JavaScriptCore/tests/stress/arrowfunction-tdz-2.js
new file mode 100644 (file)
index 0000000..7afccaf
--- /dev/null
@@ -0,0 +1,32 @@
+var A = class A { };
+var B = class B extends A {
+    constructor(beforeSuper, returnThis) {
+        var f = () => returnThis ? (() => this ) : (()=>{});
+        let af = f();
+        if (beforeSuper) {
+            let result = af();
+            super();
+        } else {
+            super();
+            let result = af();
+        }
+    }
+};
+
+var exception = null;
+for (var i = 0; i < 10000; i++) {
+    try {
+        new B(true, 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 a = new B(false, true);
+    var b = new B(false, false);
+    var c = new B(true, false);
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-tdz-3.js b/Source/JavaScriptCore/tests/stress/arrowfunction-tdz-3.js
new file mode 100644 (file)
index 0000000..ab98309
--- /dev/null
@@ -0,0 +1,177 @@
+var testCase = function (actual, expected, message) {
+  if (actual !== expected) {
+    throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+  }
+};
+
+var A = class A {
+   constructor() {
+      this.id = 'A'
+   }
+};
+
+var B = class B extends A {
+  constructor(beforeSuper) {
+    var f = () => {
+      if (this.id === 'A') {
+        return 'ok';
+      }
+      return 'ok';
+    };
+    let val;
+    if (beforeSuper) {
+      val = f();
+      super();
+    } else {
+      super();
+      val = f();
+    }
+    this.res = val;
+  }
+};
+
+var C = class C extends A {
+  constructor(beforeSuper) {
+    var f = () => {
+      if (this > 5) {
+        return 'ok';
+      }
+      return 'ok';
+    };
+    let val;
+    if (beforeSuper) {
+      val = f();
+      super();
+    } else {
+      super();
+      val = f();
+    }
+    this.res = val;
+  }
+};
+
+var D = class D extends A {
+  constructor(beforeSuper) {
+    var f = () => {
+      if (this < 5) {
+        return 'ok';
+      }
+      return 'ok';
+    };
+    let val;
+    if (beforeSuper) {
+      val = f();
+      super();
+    } else {
+      super();
+      val = f();
+    }
+    this.res = val;
+  }
+};
+
+var E = class E extends A {
+  constructor(beforeSuper) {
+    var f = () => {
+      if (this !== 5) {
+        return 'ok';
+      }
+      return 'ok';
+    };
+    let val;
+    if (beforeSuper) {
+      val = f();
+      super();
+    } else {
+      super();
+       val = f();
+    }
+    this.res = val;
+  }
+};
+
+var F = class F extends A {
+  constructor(beforeSuper) {
+    var f = () => {
+      if (this <= 5) {
+        return 'ok';
+      }
+      return 'ok';
+    };
+    let val;
+    if (beforeSuper) {
+      val = f();
+      super();
+    } else {
+      super();
+      val = f();
+    }
+    this.res = val;
+  }
+};
+
+var G = class G extends A {
+  constructor(beforeSuper) {
+    var f = () => {
+      if (this >= 5) {
+        return 'ok';
+      }
+      return 'ok';
+    };
+    let val;
+    if (beforeSuper) {
+      val = f();
+      super();
+    } else {
+      super();
+      val = f();
+    }
+    this.res = val;
+  }
+};
+
+var G = class G extends A {
+  constructor(beforeSuper) {
+    var f = () => {
+      if (this === 5) {
+        return 'ok';
+      }
+      return 'ok';
+    };
+    let val;
+    if (beforeSuper) {
+      val = f();
+      super();
+    } else {
+      super();
+      val = f();
+    }
+    this.res = val;
+  }
+};
+
+var tryToCreate = function (classForCreate) {
+  var result = false;
+  try {
+       new classForCreate(true);
+  } catch (e) {
+      result = e instanceof ReferenceError;
+  }
+
+  return result;
+}
+
+var check = function (classForCheck) {
+  testCase(tryToCreate(classForCheck), true, 'Exception wasn\'t thrown or was not a reference error');
+  var result = new classForCheck(false);
+  testCase(result.res, 'ok', 'Error in setting id ');
+}
+
+for (var i = 0; i < 10000; i++) {
+  check(B);
+  check(C);
+  check(D);
+  check(E);
+  check(F);
+  check(G);
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-tdz-4.js b/Source/JavaScriptCore/tests/stress/arrowfunction-tdz-4.js
new file mode 100644 (file)
index 0000000..87c2927
--- /dev/null
@@ -0,0 +1,46 @@
+var testCase = function (actual, expected, message) {
+    if (actual !== expected) {
+        throw message + ". Expected '" + expected + "', but was '" + actual + "'";
+    }
+};
+
+var testValue  = 'test-value';
+
+var A = class A {
+    constructor() {
+        this.idValue = testValue;
+    }
+};
+
+var B = class B extends A {
+  constructor (doRunSuper) {
+      var arrow = () => {
+          if (doRunSuper) {
+              super();
+              testCase(this.idValue, testValue, "Error: super() should create this and put value into idValue property");
+          }
+      }
+
+      if (doRunSuper) {
+          arrow();
+          testCase(this.idValue, testValue, "Error: arrow function should return this to constructor");
+      } else {
+          var value = this.idValue;//force TDZ error
+          debug(value);
+      }
+  }
+};
+
+for (var i=0; i < 10000; i++) {
+    var exception;
+    try {
+        new B(false);
+    } 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 #" + i;
+}
diff --git a/Source/JavaScriptCore/tests/stress/arrowfunction-tdz.js b/Source/JavaScriptCore/tests/stress/arrowfunction-tdz.js
deleted file mode 100644 (file)
index 6874923..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-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);
-}