[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, 8 Dec 2015 20:24:04 +0000 (20:24 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 8 Dec 2015 20:24:04 +0000 (20:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=149338

Source/JavaScriptCore:

Patch by Aleksandr Skachkov <gskachkov@gmail.com> on 2015-12-05
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::isArrowFunction):
(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::emitNewArrowFunctionExpression):
(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-08
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@193766 268f45cc-cd09-0410-ab3c-d52691b4dbfc

76 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/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 536841a..7660de8 100644 (file)
@@ -1,3 +1,16 @@
+2015-12-08  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-08  Brady Eidson  <beidson@apple.com>
 
         Modern IDB: storage/indexeddb/index-cursor.html fails.
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 7b50d0b..c025c2d 100644 (file)
@@ -1,3 +1,147 @@
+2015-12-05 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::isArrowFunction):
+        (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::emitNewArrowFunctionExpression):
+        (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-08  Csaba Osztrogon√°c  <ossy@webkit.org>
 
         Fix the !ENABLE(DFG_JIT) build after r193649
index a9e69be..b800f51 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, GeneratorThisMode::NonEmpty, dummyTDZVariables, WTF::move(sourceOverride));
+    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, kind, constructAbility, GeneratorThisMode::NonEmpty, dummyTDZVariables, false, WTF::move(sourceOverride));
     functionExecutable->setNameValue(vm, jsString(&vm, name.string()));
     return functionExecutable;
 }
index 03f46a9..bccab04 100644 (file)
@@ -92,7 +92,7 @@
             { "name" : "op_new_func_exp", "length" : 4 },
             { "name" : "op_new_generator_func", "length" : 4 },
             { "name" : "op_new_generator_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 c6e9dfa..d8ccc67 100644 (file)
@@ -58,7 +58,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:
@@ -395,7 +394,6 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, BytecodeBasicBlock* bloc
     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 b453c7f..a2f326b 100644 (file)
@@ -769,11 +769,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");
@@ -1331,9 +1326,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 83703cf..8691316 100644 (file)
@@ -55,11 +55,12 @@ namespace JSC {
             return nullptr;
         }
         
-        EvalExecutable* getSlow(ExecState* exec, JSCell* owner, bool inStrictContext, ThisTDZMode thisTDZMode, const SourceCode& evalSource, JSScope* scope)
+        EvalExecutable* getSlow(ExecState* exec, JSCell* owner, bool inStrictContext, ThisTDZMode thisTDZMode, bool isDerivedConstructorContext, bool isArrowFunctionContext, const SourceCode& evalSource, JSScope* scope)
         {
             VariableEnvironment variablesUnderTDZ;
             JSScope::collectVariablesUnderTDZ(scope, variablesUnderTDZ);
-            EvalExecutable* evalExecutable = EvalExecutable::create(exec, evalSource, inStrictContext, thisTDZMode, &variablesUnderTDZ);
+            EvalExecutable* evalExecutable = EvalExecutable::create(exec, evalSource, inStrictContext, thisTDZMode, isDerivedConstructorContext, isArrowFunctionContext, &variablesUnderTDZ);
+
             if (!evalExecutable)
                 return nullptr;
 
index 2602be7..aac3904 100644 (file)
@@ -34,7 +34,7 @@ namespace JSC {
 // FIXME: These flags, ParserModes and propagation to XXXCodeBlocks should be reorganized.
 // https://bugs.webkit.org/show_bug.cgi?id=151547
 struct ExecutableInfo {
-    ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind, GeneratorThisMode generatorThisMode, SuperBinding superBinding, SourceParseMode parseMode)
+    ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind, GeneratorThisMode generatorThisMode, SuperBinding superBinding, SourceParseMode parseMode, bool isDerivedConstructorContext, bool isArrowFunctionContext)
         : m_needsActivation(needsActivation)
         , m_usesEval(usesEval)
         , m_isStrictMode(isStrictMode)
@@ -44,6 +44,8 @@ struct ExecutableInfo {
         , m_constructorKind(static_cast<unsigned>(constructorKind))
         , m_superBinding(static_cast<unsigned>(superBinding))
         , m_parseMode(parseMode)
+        , m_isDerivedConstructorContext(isDerivedConstructorContext)
+        , m_isArrowFunctionContext(isArrowFunctionContext)
     {
         ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind));
         ASSERT(m_superBinding == static_cast<unsigned>(superBinding));
@@ -59,6 +61,8 @@ struct ExecutableInfo {
     ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
     SuperBinding superBinding() const { return static_cast<SuperBinding>(m_superBinding); }
     SourceParseMode parseMode() const { return m_parseMode; }
+    bool isDerivedConstructorContext() const { return m_isDerivedConstructorContext; }
+    bool isArrowFunctionContext() const { return m_isArrowFunctionContext; }
 
 private:
     unsigned m_needsActivation : 1;
@@ -70,6 +74,8 @@ private:
     unsigned m_constructorKind : 2;
     unsigned m_superBinding : 1;
     SourceParseMode m_parseMode;
+    unsigned m_isDerivedConstructorContext : 1;
+    unsigned m_isArrowFunctionContext : 1;
 };
 
 } // namespace JSC
index 87e8233..8a7d026 100644 (file)
@@ -67,6 +67,8 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType code
     , m_constructorKind(static_cast<unsigned>(info.constructorKind()))
     , m_generatorThisMode(static_cast<unsigned>(info.generatorThisMode()))
     , m_superBinding(static_cast<unsigned>(info.superBinding()))
+    , m_isDerivedConstructorContext(info.isDerivedConstructorContext())
+    , m_isArrowFunctionContext(info.isArrowFunctionContext())
     , m_firstLine(0)
     , m_lineCount(0)
     , m_endColumn(UINT_MAX)
index bca2c04..bec6e08 100644 (file)
@@ -119,6 +119,9 @@ public:
     bool isStrictMode() const { return m_isStrictMode; }
     bool usesEval() const { return m_usesEval; }
     SourceParseMode parseMode() const { return m_parseMode; }
+    bool isArrowFunction() const { return m_parseMode == SourceParseMode::ArrowFunctionMode; }
+    bool isDerivedConstructorContext() const { return m_isDerivedConstructorContext; }
+    bool isArrowFunctionContext() const { return m_isArrowFunctionContext; }
 
     bool needsFullScopeChain() const { return m_needsFullScopeChain; }
 
@@ -393,6 +396,8 @@ private:
     unsigned m_constructorKind : 2;
     unsigned m_generatorThisMode : 1;
     unsigned m_superBinding : 1;
+    unsigned m_isDerivedConstructorContext : 1;
+    unsigned m_isArrowFunctionContext : 1;
 
     unsigned m_firstLine;
     unsigned m_lineCount;
index 3f49488..0c7f452 100644 (file)
@@ -67,7 +67,8 @@ 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(), executable->generatorThisMode(), executable->superBinding(), parseMode));
+        ExecutableInfo(function->needsActivation(), function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind(), executable->generatorThisMode(), executable->superBinding(), parseMode,  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 +76,7 @@ static UnlinkedFunctionCodeBlock* generateUnlinkedFunctionCodeBlock(
     return result;
 }
 
-UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, GeneratorThisMode generatorThisMode, VariableEnvironment& parentScopeTDZVariables)
+UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, GeneratorThisMode generatorThisMode, VariableEnvironment& parentScopeTDZVariables, bool isDerivedConstructorContext)
     : Base(*vm, structure)
     , m_name(node->ident())
     , m_inferredName(node->inferredName())
@@ -101,6 +102,7 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct
     , m_functionMode(node->functionMode())
     , m_generatorThisMode(static_cast<unsigned>(generatorThisMode))
     , m_superBinding(static_cast<unsigned>(node->superBinding()))
+    , m_isDerivedConstructorContext(isDerivedConstructorContext)
 {
     ASSERT(m_constructorKind == static_cast<unsigned>(node->constructorKind()));
     m_parentScopeTDZVariables.swap(parentScopeTDZVariables);
index c8bba0a..fa21e38 100644 (file)
@@ -66,10 +66,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, GeneratorThisMode generatorThisMode, VariableEnvironment& parentScopeTDZVariables, RefPtr<SourceProvider>&& sourceOverride = nullptr)
+    static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, GeneratorThisMode generatorThisMode, 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, generatorThisMode, parentScopeTDZVariables);
+            UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, WTF::move(sourceOverride), node, unlinkedFunctionKind, constructAbility, generatorThisMode, parentScopeTDZVariables, isDerivedConstructorContext);
         instance->finishCreation(*vm);
         return instance;
     }
@@ -128,9 +128,13 @@ public:
     ConstructAbility constructAbility() const { return static_cast<ConstructAbility>(m_constructAbility); }
     bool isClassConstructorFunction() const { return constructorKind() != ConstructorKind::None; }
     const VariableEnvironment* parentScopeTDZVariables() const { return &m_parentScopeTDZVariables; }
+    
+    bool isArrowFunction() const { return m_parseMode == SourceParseMode::ArrowFunctionMode; }
+    bool isDerivedConstructorContext() const {return m_isDerivedConstructorContext; }
 
 private:
-    UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, GeneratorThisMode, VariableEnvironment&);
+    UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, RefPtr<SourceProvider>&& sourceOverride, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, GeneratorThisMode, VariableEnvironment&, bool isDerivedConstructorContext);
+    
     WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForCall;
     WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct;
 
@@ -162,6 +166,7 @@ private:
     unsigned m_functionMode : 1; // FunctionMode
     unsigned m_generatorThisMode : 1;
     unsigned m_superBinding : 1;
+    unsigned m_isDerivedConstructorContext : 1;
 
 protected:
     void finishCreation(VM& vm)
index 372c74c..3996884 100644 (file)
@@ -157,6 +157,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());
 
@@ -187,6 +189,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)
@@ -204,6 +211,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;
@@ -230,7 +239,10 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     }
 
     SourceParseMode parseMode = codeBlock->parseMode();
-    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();
 
@@ -510,8 +522,8 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     m_newTargetRegister = addVar();
     switch (parseMode) {
     case SourceParseMode::ArrowFunctionMode: {
-        if (functionNode->usesThis() || codeBlock->usesEval())
-            emitLoadArrowFunctionThis(&m_thisRegister);
+        if (functionNode->usesThis())
+            emitLoadThisFromArrowFunctionLexicalEnvironment();
         break;
     }
 
@@ -562,6 +574,13 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     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);
 }
 
@@ -574,6 +593,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;
@@ -603,6 +624,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);
 }
 
@@ -615,6 +644,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());
 
@@ -850,6 +881,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());
@@ -1899,9 +1983,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);
     }
@@ -2596,9 +2680,6 @@ void BytecodeGenerator::emitNewFunctionExpressionCommon(RegisterID* dst, BaseFun
     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)
@@ -2609,11 +2690,7 @@ RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* dst, FuncEx
 
 RegisterID* BytecodeGenerator::emitNewArrowFunctionExpression(RegisterID* dst, ArrowFuncExprNode* func)
 {
-    ASSERT(func->metadata()->parseMode() == SourceParseMode::ArrowFunctionMode);
-    bool isClassConstructor = m_codeBlock->isConstructor() && constructorKind() != ConstructorKind::None;
-    if (isClassConstructor || generatorThisMode() == GeneratorThisMode::Empty)
-        emitTDZCheck(thisRegister());
-    
+    ASSERT(func->metadata()->parseMode() == SourceParseMode::ArrowFunctionMode);    
     emitNewFunctionExpressionCommon(dst, func);
     return dst;
 }
@@ -3222,13 +3299,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)
 {
@@ -3915,6 +3985,62 @@ void BytecodeGenerator::popIndexedForInScope(RegisterID* localRegister)
     m_forInContextStack.removeLast();
 }
 
+RegisterID* BytecodeGenerator::emitLoadArrowFunctionLexicalEnvironment()
+{
+    ASSERT(m_codeBlock->isArrowFunction() || m_codeBlock->isArrowFunctionContext() || constructorKind() == ConstructorKind::Derived);
+
+    return emitResolveScope(nullptr, variable(propertyNames().thisIdentifier, ThisResolutionType::Scoped));
+}
+
+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);
+            
+        Variable protoScope = variable(propertyNames().derivedConstructorPrivateName);
+        emitPutToScope(m_arrowFunctionContextLexicalEnvironmentRegister, protoScope, &m_calleeRegister, DoNotThrowIfNotFound, Initialization);
+    }
+}
+    
+void BytecodeGenerator::emitPutThisToArrowFunctionContextScope()
+{
+    ASSERT(isDerivedConstructorContext() || m_arrowFunctionContextLexicalEnvironmentRegister != nullptr);
+
+    Variable thisVar = variable(propertyNames().thisIdentifier, ThisResolutionType::Scoped);
+    RegisterID* scope = isDerivedConstructorContext() ? emitLoadArrowFunctionLexicalEnvironment() : m_arrowFunctionContextLexicalEnvironmentRegister;
+    
+    emitPutToScope(scope, thisVar, thisRegister(), DoNotThrowIfNotFound, NotInitialization);
+}
+
 void BytecodeGenerator::pushStructureForInScope(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister)
 {
     if (!localRegister)
index 3e1787d..dc16a38 100644 (file)
@@ -66,6 +66,8 @@ namespace JSC {
         ExpectArrayConstructor
     };
 
+    enum class ThisResolutionType { Local, Scoped };
+    
     class CallArguments {
     public:
         CallArguments(BytecodeGenerator&, ArgumentsNode*, unsigned additionalArguments = 0);
@@ -280,6 +282,11 @@ 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(); }
         GeneratorThisMode generatorThisMode() const { return m_codeBlock->generatorThisMode(); }
         SuperBinding superBinding() const { return m_codeBlock->superBinding(); }
@@ -288,7 +295,7 @@ namespace JSC {
 
         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.
@@ -296,7 +303,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; }
 
@@ -484,6 +495,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&);
@@ -630,6 +645,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);
 
@@ -722,7 +741,6 @@ namespace JSC {
 
         void allocateCalleeSaveSpace();
         void allocateAndEmitScope();
-        RegisterID* emitLoadArrowFunctionThis(RegisterID*);
         void emitComplexPopScopes(RegisterID*, ControlFlowContext* topScope, ControlFlowContext* bottomScope);
 
         typedef HashMap<double, JSValue> NumberMap;
@@ -774,6 +792,8 @@ namespace JSC {
         
         UnlinkedFunctionExecutable* makeFunction(FunctionMetadataNode* metadata)
         {
+            bool newisDerivedConstructorContext = constructorKind() == ConstructorKind::Derived || (m_isDerivedConstructorContext && metadata->parseMode() == SourceParseMode::ArrowFunctionMode);
+
             VariableEnvironment variablesUnderTDZ;
             getVariablesUnderTDZ(variablesUnderTDZ);
 
@@ -792,7 +812,7 @@ namespace JSC {
             if (parseMode == SourceParseMode::GeneratorBodyMode && isConstructor())
                 generatorThisMode = GeneratorThisMode::Empty;
 
-            return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, generatorThisMode, variablesUnderTDZ);
+            return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, generatorThisMode, variablesUnderTDZ, newisDerivedConstructorContext);
         }
 
         void getVariablesUnderTDZ(VariableEnvironment&);
@@ -803,6 +823,7 @@ namespace JSC {
         void initializeParameters(FunctionParameters&);
         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&);
@@ -845,6 +866,7 @@ namespace JSC {
         RegisterID* m_globalObjectRegister { nullptr };
         RegisterID* m_newTargetRegister { nullptr };
         RegisterID* m_linkTimeConstantRegisters[LinkTimeConstantCount];
+        RegisterID* m_arrowFunctionContextLexicalEnvironmentRegister { nullptr };
 
         SegmentedVector<RegisterID*, 16> m_localRegistersForCalleeSaveRegisters;
         SegmentedVector<RegisterID, 32> m_constantPoolRegisters;
@@ -900,6 +922,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 99561bc..add979c 100644 (file)
@@ -146,7 +146,10 @@ RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d
 
 RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived || generator.generatorThisMode() == GeneratorThisMode::Empty)
+    if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext())
+        generator.emitLoadThisFromArrowFunctionLexicalEnvironment();
+
+    if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived || generator.generatorThisMode() == GeneratorThisMode::Empty || generator.isDerivedConstructorContext())
         generator.emitTDZCheck(generator.thisRegister());
 
     if (dst == generator.ignoredResult())
@@ -165,6 +168,9 @@ RegisterID* SuperNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
     if (dst == generator.ignoredResult())
         return 0;
 
+    if (generator.isDerivedConstructorContext())
+        return generator.emitGetById(generator.finalDestination(dst), generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment(), generator.propertyNames().underscoreProto);
+
     RegisterID callee;
     callee.setIndex(JSStack::Callee);
 
@@ -696,6 +702,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);
@@ -723,11 +744,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());
@@ -3052,6 +3078,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 3613178..824655f 100644 (file)
@@ -1810,15 +1810,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 4a0ed11..00e91a4 100644 (file)
@@ -4508,17 +4508,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();
@@ -4568,24 +4557,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 1e0cc08..bb5b1d1 100644 (file)
@@ -203,7 +203,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 417d06f..a5fab83 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 b219452..31b046a 100644 (file)
@@ -1026,11 +1026,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 40cec76..c80e830 100644 (file)
@@ -616,10 +616,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 272734d..c94ad6b 100755 (executable)
@@ -4842,15 +4842,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 45b9543..cc3d4ad 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 387ed6c..b9e7c2f 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 fdfc743..9704ae5 100644 (file)
@@ -832,9 +832,6 @@ private:
         case GetScope:
             compileGetScope();
             break;
-        case LoadArrowFunctionThis:
-            compileLoadArrowFunctionThis();
-            break;
         case SkipScope:
             compileSkipScope();
             break;
@@ -4580,11 +4577,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 637f379..3853045 100644 (file)
@@ -180,7 +180,8 @@ JSValue eval(CallFrame* callFrame)
         // If the literal parser bailed, it should not have thrown exceptions.
         ASSERT(!callFrame->vm().exception());
 
-        eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock, callerCodeBlock->isStrictMode(), thisTDZMode, sourceCode, callerScopeChain);
+        eval = callerCodeBlock->evalCodeCache().getSlow(callFrame, callerCodeBlock, callerCodeBlock->isStrictMode(), thisTDZMode, callerCodeBlock->unlinkedCodeBlock()->isDerivedConstructorContext(), callerCodeBlock->unlinkedCodeBlock()->isArrowFunction(), sourceCode, callerScopeChain);
+
         if (!eval)
             return jsUndefined();
     }
index 5b67a05..f3431c9 100644 (file)
@@ -223,7 +223,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 20f0e9c..da5232a 100755 (executable)
@@ -502,7 +502,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 243be7b..3a97dd8 100755 (executable)
@@ -667,14 +667,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)
 {
@@ -971,23 +963,14 @@ void JIT::emit_op_new_generator_func(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
@@ -995,20 +978,15 @@ 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
+    OpcodeID opcodeID = m_vm->interpreter->getOpcodeID(currentInstruction->u.opcode);
+
+    if (opcodeID == op_new_func_exp || opcodeID == op_new_arrow_func_exp)
+        callOperation(operationNewFunction, dst, regT0, function);
     else {
-        if (opcodeID == op_new_func_exp)
-            callOperation(operationNewFunction, dst, regT0, function);
-        else {
-            ASSERT(opcodeID == op_new_generator_func_exp);
-            callOperation(operationNewGeneratorFunction, dst, regT0, function);
-        }
+        ASSERT(opcodeID == op_new_generator_func_exp);
+        callOperation(operationNewGeneratorFunction, 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 cdb59f4..98fbed8 100644 (file)
@@ -1079,13 +1079,12 @@ LLINT_SLOW_PATH_DECL(slow_path_new_generator_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 76ccc06..f5b0236 100644 (file)
@@ -1478,7 +1478,7 @@ _llint_op_new_generator_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..69f3e0b 100644 (file)
@@ -2291,15 +2291,6 @@ _llint_op_profile_control_flow:
     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 a90dc1c..4331942 100644 (file)
@@ -376,7 +376,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);
@@ -917,6 +917,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 8e9a252..9a9345a 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 c3be82c..49825a6 100644 (file)
@@ -1978,11 +1978,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 486d8fc..8694f77 100644 (file)
@@ -147,17 +147,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 494520d..b10b114 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, GeneratorThisMode::NonEmpty, emptyTDZVariables);
+    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, ConstructAbility::CanConstruct, GeneratorThisMode::NonEmpty, emptyTDZVariables, false);
     functionExecutable->m_nameValue.set(vm, functionExecutable, jsString(&vm, name.string()));
 
     m_sourceCode.addCache(key, SourceCodeValue(vm, functionExecutable, m_sourceCode.age()));
index 9b8c150..2132f0c 100644 (file)
@@ -194,7 +194,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&);
 
@@ -205,7 +205,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 37c54d2..6835a8a 100644 (file)
     macro(Collator) \
     macro(DateTimeFormat) \
     macro(NumberFormat) \
+    macro(newTargetLocal) \
+    macro(derivedConstructor) \
 
 
 namespace JSC {
index 4206006..f5df77d 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 75b3091..86a5777 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,8 @@ public:
         
     DECLARE_INFO;
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, GeneratorThisMode::NonEmpty, SuperBinding::NotNeeded, SourceParseMode::ProgramMode); }
+
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, GeneratorThisMode::NonEmpty, SuperBinding::NotNeeded, SourceParseMode::ProgramMode, isDerivedConstructorContext(), isArrowFunctionContext()); }
 
     unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }
     unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }
@@ -456,7 +461,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 +506,7 @@ public:
         
     DECLARE_INFO;
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, GeneratorThisMode::NonEmpty, SuperBinding::NotNeeded, SourceParseMode::ProgramMode); }
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, GeneratorThisMode::NonEmpty, SuperBinding::NotNeeded, SourceParseMode::ProgramMode, isDerivedConstructorContext(), false); }
 
 private:
     friend class ExecutableBase;
@@ -542,7 +547,8 @@ public:
 
     DECLARE_INFO;
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, GeneratorThisMode::NonEmpty, SuperBinding::NotNeeded, SourceParseMode::ModuleEvaluateMode); }
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, GeneratorThisMode::NonEmpty, SuperBinding::NotNeeded, SourceParseMode::ModuleEvaluateMode, isDerivedConstructorContext(), false); }
+
     UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCodeBlock() { return m_unlinkedModuleProgramCodeBlock.get(); }
 
     SymbolTable* moduleEnvironmentSymbolTable() { return m_moduleEnvironmentSymbolTable.get(); }
@@ -650,13 +656,14 @@ public:
     FunctionMode functionMode() { return m_unlinkedExecutable->functionMode(); }
     bool isBuiltinFunction() const { return m_unlinkedExecutable->isBuiltinFunction(); }
     ConstructAbility constructAbility() const { return m_unlinkedExecutable->constructAbility(); }
+    bool isArrowFunction() const { return parseMode() == SourceParseMode::ArrowFunctionMode; }
+    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(); }
     JSString* nameValue() const { return m_unlinkedExecutable->nameValue(); }
     size_t parameterCount() const { return m_unlinkedExecutable->parameterCount(); } // Excluding 'this'!
     SourceParseMode parseMode() const { return m_unlinkedExecutable->parseMode(); }
-    bool isArrowFunction() const { return parseMode() == SourceParseMode::ArrowFunctionMode; }
 
     static void visitChildren(JSCell*, SlotVisitor&);
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
index 7d99680..ecc82ba 100644 (file)
@@ -972,14 +972,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 0325324..62d1495 100644 (file)
@@ -669,7 +669,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 c952d32..7e63abd 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);
-}