Title: [181466] trunk/Source/_javascript_Core
Revision
181466
Author
[email protected]
Date
2015-03-12 18:11:15 -0700 (Thu, 12 Mar 2015)

Log Message

"this" should be in TDZ until super is called in the constructor of a derived class
https://bugs.webkit.org/show_bug.cgi?id=142527

Reviewed by Mark Hahnenberg.

DFG and FTL implementations co-authored by Filip Pizlo.

In ES6 class syntax, "this" register must be in the "temporal dead zone" (TDZ) and throw ReferenceError until
super() is called inside the constructor of a derived class.

Added op_check_tdz, a new OP code, which throws a reference error when the first operand is an empty value
to all tiers of JIT and LLint. The op code throws in the slow path on the basis that a TDZ error should be
a programming error and not a part of the programs' normal control flow. In DFG, this op code is represented
by a no-op must-generate node CheckNotEmpty modeled after CheckCell.

Also made the constructor of a derived class assign the empty value to "this" register rather than undefined
so that ThisNode can emit the op_check_tdz to check the initialized-ness of "this" in such a constructor.

* bytecode/BytecodeList.json: Added op_check_tdz.
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset): Ditto.
(JSC::computeDefsForBytecodeOffset): Ditto.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode): Ditto.
* bytecode/ExitKind.cpp:
(JSC::exitKindToString): Added TDZFailure.
* bytecode/ExitKind.h: Ditto.
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator): Assign the empty value to "this" register to indicate it's in TDZ.
(JSC::BytecodeGenerator::emitTDZCheck): Added.
(JSC::BytecodeGenerator::emitReturn): Emit the TDZ check since "this" can still be in TDZ if super() was never
called. e.g. class B extends A { constructor() { } }
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::ThisNode::emitBytecode): Always emit the TDZ check if we're inside the constructor of a derived class.
We can't omit this check even if the result was ignored per spec.
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): Previously, empty value could never appear
in a local variable. This is no longer true so generalize this code. Also added the support for CheckNotEmpty.
Like CheckCell, we phantomize this DFG node in the constant folding phase if the type of the operand is already
found to be not empty. Otherwise filter out SpecEmpty.
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock): Added op_check_tdz.
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel): op_check_tdz can be compiled and inlined.
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize): CheckNotEmpty doesn't read or write values.
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants): Convert CheckNotEmpty to a phantom if non-emptiness had already
been proven for the operand prior to this node.
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC): CheckNotEmpty does not trigger GC.
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode): CheckNotEmpty is a no-op in the fixup phase.
* dfg/DFGNodeType.h: CheckNotEmpty cannot be removed even if the result was ignored. See ThisNode::emitBytecode.
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate): CheckNotEmpty doesn't return any value.
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute): CheckNotEmpty doesn't load from heap so it's safe.
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile): Speculative the operand to be not empty. OSR exit if the speculation fails.
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile): Ditto.
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile): CheckNotEmpty can be compiled in FTL.
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode): Calls compileCheckNotEmpty for CheckNotEmpty.
(JSC::FTL::LowerDFGToLLVM::compileCheckNotEmpty): OSR exit with "TDZFailure" if the operand is not empty.
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass): Added op_check_tdz.
(JSC::JIT::privateCompileSlowCases): Ditto.
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_check_tdz): Implements op_check_tdz in Baseline JIT.
(JSC::JIT::emitSlow_op_check_tdz): Ditto.
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_check_tdz): Ditto.
(JSC::JIT::emitSlow_op_check_tdz): Ditto.
* llint/LowLevelInterpreter32_64.asm: Implements op_check_tdz in LLint.
* llint/LowLevelInterpreter64.asm: Ditto.
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL): Throws a reference error for op_check_tdz. Shared by LLint and Baseline JIT.
* runtime/CommonSlowPaths.h:
* tests/stress/class-syntax-no-loop-tdz.js: Added.
* tests/stress/class-syntax-no-tdz-in-catch.js: Added.
* tests/stress/class-syntax-no-tdz-in-conditional.js: Added.
* tests/stress/class-syntax-no-tdz-in-loop-no-inline-super.js: Added.
* tests/stress/class-syntax-no-tdz-in-loop.js: Added.
* tests/stress/class-syntax-no-tdz.js: Added.
* tests/stress/class-syntax-tdz-in-catch.js: Added.
* tests/stress/class-syntax-tdz-in-conditional.js: Added.
* tests/stress/class-syntax-tdz-in-loop.js: Added.
* tests/stress/class-syntax-tdz.js: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (181465 => 181466)


--- trunk/Source/_javascript_Core/ChangeLog	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-03-13 01:11:15 UTC (rev 181466)
@@ -1,3 +1,99 @@
+2015-03-12  Ryosuke Niwa  <[email protected]>
+
+        "this" should be in TDZ until super is called in the constructor of a derived class
+        https://bugs.webkit.org/show_bug.cgi?id=142527
+
+        Reviewed by Mark Hahnenberg.
+
+        DFG and FTL implementations co-authored by Filip Pizlo.
+
+        In ES6 class syntax, "this" register must be in the "temporal dead zone" (TDZ) and throw ReferenceError until
+        super() is called inside the constructor of a derived class.
+
+        Added op_check_tdz, a new OP code, which throws a reference error when the first operand is an empty value
+        to all tiers of JIT and LLint. The op code throws in the slow path on the basis that a TDZ error should be
+        a programming error and not a part of the programs' normal control flow. In DFG, this op code is represented
+        by a no-op must-generate node CheckNotEmpty modeled after CheckCell.
+
+        Also made the constructor of a derived class assign the empty value to "this" register rather than undefined
+        so that ThisNode can emit the op_check_tdz to check the initialized-ness of "this" in such a constructor.
+
+        * bytecode/BytecodeList.json: Added op_check_tdz.
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset): Ditto.
+        (JSC::computeDefsForBytecodeOffset): Ditto.
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode): Ditto.
+        * bytecode/ExitKind.cpp:
+        (JSC::exitKindToString): Added TDZFailure.
+        * bytecode/ExitKind.h: Ditto.
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator): Assign the empty value to "this" register to indicate it's in TDZ.
+        (JSC::BytecodeGenerator::emitTDZCheck): Added.
+        (JSC::BytecodeGenerator::emitReturn): Emit the TDZ check since "this" can still be in TDZ if super() was never
+        called. e.g. class B extends A { constructor() { } }
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ThisNode::emitBytecode): Always emit the TDZ check if we're inside the constructor of a derived class.
+        We can't omit this check even if the result was ignored per spec.
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): Previously, empty value could never appear
+        in a local variable. This is no longer true so generalize this code. Also added the support for CheckNotEmpty.
+        Like CheckCell, we phantomize this DFG node in the constant folding phase if the type of the operand is already
+        found to be not empty. Otherwise filter out SpecEmpty.
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock): Added op_check_tdz.
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel): op_check_tdz can be compiled and inlined.
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize): CheckNotEmpty doesn't read or write values.
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants): Convert CheckNotEmpty to a phantom if non-emptiness had already
+        been proven for the operand prior to this node.
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC): CheckNotEmpty does not trigger GC.
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode): CheckNotEmpty is a no-op in the fixup phase.
+        * dfg/DFGNodeType.h: CheckNotEmpty cannot be removed even if the result was ignored. See ThisNode::emitBytecode.
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate): CheckNotEmpty doesn't return any value.
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute): CheckNotEmpty doesn't load from heap so it's safe.
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile): Speculative the operand to be not empty. OSR exit if the speculation fails.
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile): Ditto.
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile): CheckNotEmpty can be compiled in FTL.
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileNode): Calls compileCheckNotEmpty for CheckNotEmpty.
+        (JSC::FTL::LowerDFGToLLVM::compileCheckNotEmpty): OSR exit with "TDZFailure" if the operand is not empty.
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass): Added op_check_tdz.
+        (JSC::JIT::privateCompileSlowCases): Ditto.
+        * jit/JIT.h:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_check_tdz): Implements op_check_tdz in Baseline JIT.
+        (JSC::JIT::emitSlow_op_check_tdz): Ditto.
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_check_tdz): Ditto.
+        (JSC::JIT::emitSlow_op_check_tdz): Ditto.
+        * llint/LowLevelInterpreter32_64.asm: Implements op_check_tdz in LLint.
+        * llint/LowLevelInterpreter64.asm: Ditto.
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL): Throws a reference error for op_check_tdz. Shared by LLint and Baseline JIT.
+        * runtime/CommonSlowPaths.h:
+        * tests/stress/class-syntax-no-loop-tdz.js: Added.
+        * tests/stress/class-syntax-no-tdz-in-catch.js: Added.
+        * tests/stress/class-syntax-no-tdz-in-conditional.js: Added.
+        * tests/stress/class-syntax-no-tdz-in-loop-no-inline-super.js: Added.
+        * tests/stress/class-syntax-no-tdz-in-loop.js: Added.
+        * tests/stress/class-syntax-no-tdz.js: Added.
+        * tests/stress/class-syntax-tdz-in-catch.js: Added.
+        * tests/stress/class-syntax-tdz-in-conditional.js: Added.
+        * tests/stress/class-syntax-tdz-in-loop.js: Added.
+        * tests/stress/class-syntax-tdz.js: Added.
+
 2015-03-12  Yusuke Suzuki  <[email protected]>
 
         Integrate MapData into JSMap and JSSet

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeList.json (181465 => 181466)


--- trunk/Source/_javascript_Core/bytecode/BytecodeList.json	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeList.json	2015-03-13 01:11:15 UTC (rev 181466)
@@ -11,6 +11,7 @@
             { "name" : "op_create_arguments", "length" : 3 },
             { "name" : "op_create_this", "length" : 4 },
             { "name" : "op_to_this", "length" : 4 },
+            { "name" : "op_check_tdz", "length" : 2 },
             { "name" : "op_new_object", "length" : 4 },
             { "name" : "op_new_array", "length" : 5 },
             { "name" : "op_new_array_with_size", "length" : 4 },

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h (181465 => 181466)


--- trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h	2015-03-13 01:11:15 UTC (rev 181466)
@@ -56,6 +56,7 @@
         return;
     case op_get_scope:
     case op_to_this:
+    case op_check_tdz:
     case op_pop_scope:
     case op_profile_will_call:
     case op_profile_did_call:
@@ -364,6 +365,7 @@
     case op_mov:
     case op_new_object:
     case op_to_this:
+    case op_check_tdz:
     case op_init_lazy_reg:
     case op_get_scope:
     case op_create_arguments:

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -789,6 +789,11 @@
             out.print(" ", (++it)->u.toThisStatus);
             break;
         }
+        case op_check_tdz: {
+            int r0 = (++it)->u.operand;
+            printLocationOpAndRegisterOperand(out, exec, location, it, "op_check_tdz", r0);
+            break;
+        }
         case op_new_object: {
             int r0 = (++it)->u.operand;
             unsigned inferredInlineCapacity = (++it)->u.operand;

Modified: trunk/Source/_javascript_Core/bytecode/ExitKind.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/bytecode/ExitKind.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/bytecode/ExitKind.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -70,6 +70,8 @@
         return "NotStringObject";
     case VarargsOverflow:
         return "VarargsOverflow";
+    case TDZFailure:
+        return "TDZFailure";
     case Uncountable:
         return "Uncountable";
     case UncountableInvalidation:

Modified: trunk/Source/_javascript_Core/bytecode/ExitKind.h (181465 => 181466)


--- trunk/Source/_javascript_Core/bytecode/ExitKind.h	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/bytecode/ExitKind.h	2015-03-13 01:11:15 UTC (rev 181466)
@@ -47,6 +47,7 @@
     ExoticObjectMode, // We exited because some exotic object that we were accessing was in an exotic mode (like Arguments with slow arguments).
     NotStringObject, // We exited because we shouldn't have attempted to optimize string object access.
     VarargsOverflow, // We exited because a varargs call passed more arguments than we expected.
+    TDZFailure, // We exited because we were in the TDZ and accessed the variable.
     Uncountable, // We exited for none of the above reasons, and we should not count it. Most uses of this should be viewed as a FIXME.
     UncountableInvalidation, // We exited because the code block was invalidated; this means that we've already counted the reasons why the code block was invalidated.
     WatchdogTimerFired, // We exited because we need to service the watchdog timer.

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -404,7 +404,7 @@
         if (constructorKindIsDerived()) {
             m_newTargetRegister = addVar();
             emitMove(m_newTargetRegister, &m_thisRegister);
-            emitLoad(&m_thisRegister, jsNull());
+            emitMove(&m_thisRegister, addConstantEmptyValue());
         } else
             emitCreateThis(&m_thisRegister);
     } else if (functionNode->usesThis() || codeBlock->usesEval()) {
@@ -1556,6 +1556,12 @@
     return dst;
 }
 
+void BytecodeGenerator::emitTDZCheck(RegisterID* target)
+{
+    emitOpcode(op_check_tdz);
+    instructions().append(target->index());
+}
+
 RegisterID* BytecodeGenerator::emitNewObject(RegisterID* dst)
 {
     size_t begin = instructions().size();
@@ -1907,12 +1913,16 @@
     }
 
     bool thisMightBeUninitialized = constructorKindIsDerived();
-    if (isConstructor() && (src->index() != m_thisRegister.index() || thisMightBeUninitialized)) {
+    bool srcIsThis = src->index() == m_thisRegister.index();
+    if (isConstructor() && (!srcIsThis || thisMightBeUninitialized)) {
         RefPtr<Label> isObjectOrUndefinedLabel = newLabel();
 
+        if (srcIsThis && thisMightBeUninitialized)
+            emitTDZCheck(src);
+
         emitJumpIfTrue(emitIsObject(newTemporary(), src), isObjectOrUndefinedLabel.get());
 
-        if (constructorKindIsDerived()) {
+        if (thisMightBeUninitialized) {
             emitJumpIfTrue(emitIsUndefined(newTemporary(), src), isObjectOrUndefinedLabel.get());
             emitThrowTypeError("Cannot return a non-object type in the constructor of a derived class.");
         } else

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (181465 => 181466)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2015-03-13 01:11:15 UTC (rev 181466)
@@ -458,6 +458,7 @@
         RegisterID* emitUnaryNoDstOp(OpcodeID, RegisterID* src);
 
         RegisterID* emitCreateThis(RegisterID* dst);
+        void emitTDZCheck(RegisterID* target);
         RegisterID* emitNewObject(RegisterID* dst);
         RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision
 

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -144,6 +144,9 @@
 
 RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
+    if (generator.constructorKindIsDerived())
+        generator.emitTDZCheck(generator.thisRegister());
+
     if (dst == generator.ignoredResult())
         return 0;
 

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (181465 => 181466)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2015-03-13 01:11:15 UTC (rev 181466)
@@ -143,16 +143,7 @@
     }
         
     case ExtractOSREntryLocal: {
-        if (!(node->unlinkedLocal().isArgument())
-            && m_graph.m_lazyVars.get(node->unlinkedLocal().toLocal())) {
-            // This is kind of pessimistic - we could know in some cases that the
-            // DFG code at the point of the OSR had already initialized the lazy
-            // variable. But maybe this is fine, since we're inserting OSR
-            // entrypoints very early in the pipeline - so any lazy initializations
-            // ought to be hoisted out anyway.
-            forNode(node).makeBytecodeTop();
-        } else
-            forNode(node).makeHeapTop();
+        forNode(node).makeBytecodeTop();
         break;
     }
             
@@ -1865,11 +1856,21 @@
             ASSERT(value);
             break;
         }
-        
         filterByValue(node->child1(), *node->cellOperand());
         break;
     }
+
+    case CheckNotEmpty: {
+        AbstractValue& value = forNode(node->child1());
+        if (!(value.m_type & SpecEmpty)) {
+            m_state.setFoundConstants(true);
+            break;
+        }
         
+        filter(value, ~SpecEmpty);
+        break;
+    }
+
     case CheckInBounds: {
         JSValue left = forNode(node->child1()).value();
         JSValue right = forNode(node->child2()).value();

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -2822,6 +2822,12 @@
             NEXT_OPCODE(op_mov);
         }
 
+        case op_check_tdz: {
+            Node* op = get(VirtualRegister(currentInstruction[1].u.operand));
+            addToGraph(CheckNotEmpty, op);
+            NEXT_OPCODE(op_check_tdz);
+        }
+
         case op_check_has_instance:
             addToGraph(CheckHasInstance, get(VirtualRegister(currentInstruction[3].u.operand)));
             NEXT_OPCODE(op_check_has_instance);

Modified: trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -99,6 +99,7 @@
     case op_enter:
     case op_touch_entry:
     case op_to_this:
+    case op_check_tdz:
     case op_create_this:
     case op_bitand:
     case op_bitor:

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (181465 => 181466)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2015-03-13 01:11:15 UTC (rev 181466)
@@ -254,7 +254,11 @@
     case CheckCell:
         def(PureValue(CheckCell, AdjacencyList(AdjacencyList::Fixed, node->child1()), node->cellOperand()));
         return;
-        
+
+    case CheckNotEmpty:
+        def(PureValue(CheckNotEmpty, AdjacencyList(AdjacencyList::Fixed, node->child1())));
+        return;
+
     case ConstantStoragePointer:
         def(PureValue(node, node->storagePointer()));
         return;

Modified: trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -185,7 +185,15 @@
                 eliminated = true;
                 break;
             }
-                
+
+            case CheckNotEmpty: {
+                if (m_state.forNode(node->child1()).m_type & SpecEmpty)
+                    break;
+                node->convertToPhantom();
+                eliminated = true;
+                break;
+            }
+
             case CheckInBounds: {
                 JSValue left = m_state.forNode(node->child1()).value();
                 JSValue right = m_state.forNode(node->child2()).value();

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -105,6 +105,7 @@
     case PutGlobalVar:
     case VarInjectionWatchpoint:
     case CheckCell:
+    case CheckNotEmpty:
     case AllocationProfileWatchpoint:
     case RegExpExec:
     case RegExpTest:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -1269,6 +1269,7 @@
         case CountExecution:
         case ForceOSRExit:
         case CheckBadCell:
+        case CheckNotEmpty:
         case CheckWatchdogTimer:
         case Unreachable:
         case ExtractOSREntryLocal:

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (181465 => 181466)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2015-03-13 01:11:15 UTC (rev 181466)
@@ -191,6 +191,7 @@
     macro(NotifyWrite, NodeMustGenerate) \
     macro(VarInjectionWatchpoint, NodeMustGenerate) \
     macro(CheckCell, NodeMustGenerate) \
+    macro(CheckNotEmpty, NodeMustGenerate) \
     macro(CheckBadCell, NodeMustGenerate) \
     macro(AllocationProfileWatchpoint, NodeMustGenerate) \
     macro(CheckInBounds, NodeMustGenerate) \

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -626,6 +626,7 @@
         case SetArgument:
         case CheckStructure:
         case CheckCell:
+        case CheckNotEmpty:
         case CheckBadCell:
         case PutStructure:
         case TearOffArguments:

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (181465 => 181466)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2015-03-13 01:11:15 UTC (rev 181466)
@@ -178,6 +178,7 @@
     case VarInjectionWatchpoint:
     case CheckCell:
     case CheckBadCell:
+    case CheckNotEmpty:
     case AllocationProfileWatchpoint:
     case RegExpExec:
     case RegExpTest:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -3758,6 +3758,14 @@
         break;
     }
 
+    case CheckNotEmpty: {
+        JSValueOperand operand(this, node->child1());
+        GPRReg tagGPR = operand.tagGPR();
+        speculationCheck(TDZFailure, JSValueSource(), nullptr, m_jit.branch32(JITCompiler::Equal, tagGPR, TrustedImm32(JSValue::EmptyValueTag)));
+        noResult(node);
+        break;
+    }
+
     case GetExecutable: {
         SpeculateCellOperand function(this, node->child1());
         GPRTemporary result(this, Reuse, function);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -3842,7 +3842,15 @@
         noResult(node);
         break;
     }
-        
+
+    case CheckNotEmpty: {
+        JSValueOperand operand(this, node->child1());
+        GPRReg gpr = operand.gpr();
+        speculationCheck(TDZFailure, JSValueSource(), nullptr, m_jit.branchTest64(JITCompiler::Zero, gpr));
+        noResult(node);
+        break;
+    }
+
     case GetExecutable: {
         SpeculateCellOperand function(this, node->child1());
         GPRTemporary result(this, Reuse, function);

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -110,6 +110,7 @@
     case StringCharAt:
     case CheckCell:
     case CheckBadCell:
+    case CheckNotEmpty:
     case StringCharCodeAt:
     case AllocatePropertyStorage:
     case ReallocatePropertyStorage:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -546,6 +546,9 @@
         case CheckCell:
             compileCheckCell();
             break;
+        case CheckNotEmpty:
+            compileCheckNotEmpty();
+            break;
         case CheckBadCell:
             compileCheckBadCell();
             break;
@@ -1862,7 +1865,12 @@
     {
         terminate(BadCell);
     }
-    
+
+    void compileCheckNotEmpty()
+    {
+        speculate(TDZFailure, noValue(), nullptr, m_out.isZero64(lowJSValue(m_node->child1())));
+    }
+
     void compileGetExecutable()
     {
         LValue cell = lowCell(m_node->child1());

Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/jit/JIT.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -201,6 +201,7 @@
         DEFINE_OP(op_construct)
         DEFINE_OP(op_create_this)
         DEFINE_OP(op_to_this)
+        DEFINE_OP(op_check_tdz)
         DEFINE_OP(op_init_lazy_reg)
         DEFINE_OP(op_create_arguments)
         DEFINE_OP(op_debug)
@@ -375,6 +376,7 @@
         DEFINE_SLOWCASE_OP(op_construct_varargs)
         DEFINE_SLOWCASE_OP(op_construct)
         DEFINE_SLOWCASE_OP(op_to_this)
+        DEFINE_SLOWCASE_OP(op_check_tdz)
         DEFINE_SLOWCASE_OP(op_create_this)
         DEFINE_SLOWCASE_OP(op_div)
         DEFINE_SLOWCASE_OP(op_eq)

Modified: trunk/Source/_javascript_Core/jit/JIT.h (181465 => 181466)


--- trunk/Source/_javascript_Core/jit/JIT.h	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/jit/JIT.h	2015-03-13 01:11:15 UTC (rev 181466)
@@ -468,6 +468,7 @@
         void emit_op_construct(Instruction*);
         void emit_op_create_this(Instruction*);
         void emit_op_to_this(Instruction*);
+        void emit_op_check_tdz(Instruction*);
         void emit_op_create_arguments(Instruction*);
         void emit_op_debug(Instruction*);
         void emit_op_del_by_id(Instruction*);
@@ -572,6 +573,7 @@
         void emitSlow_op_construct(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_to_this(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_create_this(Instruction*, Vector<SlowCaseEntry>::iterator&);
+        void emitSlow_op_check_tdz(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_div(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_eq(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_get_callee(Instruction*, Vector<SlowCaseEntry>::iterator&);

Modified: trunk/Source/_javascript_Core/jit/JITOpcodes.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -756,6 +756,19 @@
     slowPathCall.call();
 }
 
+void JIT::emit_op_check_tdz(Instruction* currentInstruction)
+{
+    emitGetVirtualRegister(currentInstruction[1].u.operand, regT0);
+    addSlowCase(branchTest64(Zero, regT0));
+}
+
+void JIT::emitSlow_op_check_tdz(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    linkSlowCase(iter);
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_throw_tdz_error);
+    slowPathCall.call();
+}
+
 void JIT::emit_op_profile_will_call(Instruction* currentInstruction)
 {
     Jump profilerDone = branchTestPtr(Zero, AbsoluteAddress(m_vm->enabledProfilerAddress()));

Modified: trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -997,6 +997,19 @@
     slowPathCall.call();
 }
 
+void JIT::emit_op_check_tdz(Instruction* currentInstruction)
+{
+    emitLoadTag(currentInstruction[1].u.operand, regT0);
+    addSlowCase(branch32(Equal, regT0, TrustedImm32(JSValue::EmptyValueTag)));
+}
+
+void JIT::emitSlow_op_check_tdz(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+    linkSlowCase(iter);
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_throw_tdz_error);
+    slowPathCall.call();
+}
+
 void JIT::emit_op_profile_will_call(Instruction* currentInstruction)
 {
     load32(m_vm->enabledProfilerAddress(), regT0);

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm (181465 => 181466)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm	2015-03-13 01:11:15 UTC (rev 181466)
@@ -803,6 +803,16 @@
     dispatch(4)
 
 
+_llint_op_check_tdz:
+    traceExecution()
+    loadpFromInstruction(1, t0)
+    bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opNotTDZ
+    callSlowPath(_slow_path_throw_tdz_error)
+
+.opNotTDZ:
+    dispatch(2)
+
+
 _llint_op_mov:
     traceExecution()
     loadi 8[PC], t1

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (181465 => 181466)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2015-03-13 01:11:15 UTC (rev 181466)
@@ -687,6 +687,17 @@
     dispatch(4)
 
 
+_llint_op_check_tdz:
+    traceExecution()
+    loadpFromInstruction(1, t0)
+    loadq [cfr, t0, 8], t0
+    bqneq t0, ValueEmpty, .opNotTDZ
+    callSlowPath(_slow_path_throw_tdz_error)
+
+.opNotTDZ:
+    dispatch(2)
+
+
 _llint_op_mov:
     traceExecution()
     loadisFromInstruction(2, t1)

Modified: trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp (181465 => 181466)


--- trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp	2015-03-13 01:11:15 UTC (rev 181466)
@@ -257,6 +257,12 @@
     RETURN(v1.toThis(exec, exec->codeBlock()->isStrictMode() ? StrictMode : NotStrictMode));
 }
 
+SLOW_PATH_DECL(slow_path_throw_tdz_error)
+{
+    BEGIN();
+    THROW(createReferenceError(exec, "Cannot access uninitialized variable."));
+}
+
 SLOW_PATH_DECL(slow_path_not)
 {
     BEGIN();

Modified: trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h (181465 => 181466)


--- trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h	2015-03-13 00:57:10 UTC (rev 181465)
+++ trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h	2015-03-13 01:11:15 UTC (rev 181466)
@@ -187,6 +187,7 @@
 SLOW_PATH_HIDDEN_DECL(slow_path_enter);
 SLOW_PATH_HIDDEN_DECL(slow_path_get_callee);
 SLOW_PATH_HIDDEN_DECL(slow_path_to_this);
+SLOW_PATH_HIDDEN_DECL(slow_path_throw_tdz_error);
 SLOW_PATH_HIDDEN_DECL(slow_path_not);
 SLOW_PATH_HIDDEN_DECL(slow_path_eq);
 SLOW_PATH_HIDDEN_DECL(slow_path_neq);

Added: trunk/Source/_javascript_Core/tests/stress/class-syntax-no-loop-tdz.js (0 => 181466)


--- trunk/Source/_javascript_Core/tests/stress/class-syntax-no-loop-tdz.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/class-syntax-no-loop-tdz.js	2015-03-13 01:11:15 UTC (rev 181466)
@@ -0,0 +1,21 @@
+//@ skip
+
+class A {
+    constructor() { }
+}
+
+class B extends A {
+    constructor() {
+        for (var j = 0; j < 10; j++) {
+            if (!j)
+                super();
+            else
+                this;
+        }
+    }
+}
+
+noInline(B);
+
+for (var i = 0; i < 100000; ++i)
+    new B();

Added: trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz-in-catch.js (0 => 181466)


--- trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz-in-catch.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz-in-catch.js	2015-03-13 01:11:15 UTC (rev 181466)
@@ -0,0 +1,20 @@
+//@ skip
+
+class A {
+    constructor() { }
+}
+
+class B extends A {
+    constructor() {
+        try {
+            this;
+        } catch (e) {
+            super();
+        }
+    }
+}
+
+noInline(B);
+
+for (var i = 0; i < 100000; ++i)
+    new B();

Added: trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz-in-conditional.js (0 => 181466)


--- trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz-in-conditional.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz-in-conditional.js	2015-03-13 01:11:15 UTC (rev 181466)
@@ -0,0 +1,19 @@
+//@ skip
+
+class A {
+    constructor() { }
+}
+
+class B extends A {
+    constructor(accessThisBeforeSuper) {
+        if (accessThisBeforeSuper)
+            this;
+        else
+            super();
+    }
+}
+
+noInline(B);
+
+for (var i = 0; i < 100000; ++i)
+    new B(false);

Added: trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz-in-loop-no-inline-super.js (0 => 181466)


--- trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz-in-loop-no-inline-super.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz-in-loop-no-inline-super.js	2015-03-13 01:11:15 UTC (rev 181466)
@@ -0,0 +1,26 @@
+//@ skip
+
+class A {
+    constructor() { }
+}
+
+noInline(A);
+
+class B extends A {
+    constructor() {
+        var values = [];
+        for (var j = 0; j < 100; j++) {
+            if (j == 1)
+                super();
+            else if (j > 2)
+                this;
+            else
+                values.push(i);
+        }
+    }
+}
+
+noInline(B);
+
+for (var i = 0; i < 100000; ++i)
+    new B();

Added: trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz-in-loop.js (0 => 181466)


--- trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz-in-loop.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz-in-loop.js	2015-03-13 01:11:15 UTC (rev 181466)
@@ -0,0 +1,24 @@
+//@ skip
+
+class A {
+    constructor() { }
+}
+
+class B extends A {
+    constructor() {
+        var values = [];
+        for (var j = 0; j < 100; j++) {
+            if (j == 1)
+                super();
+            else if (j > 2)
+                this;
+            else
+                values.push(i);
+        }
+    }
+}
+
+noInline(B);
+
+for (var i = 0; i < 100000; ++i)
+    new B();

Added: trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz.js (0 => 181466)


--- trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/class-syntax-no-tdz.js	2015-03-13 01:11:15 UTC (rev 181466)
@@ -0,0 +1,17 @@
+//@ skip
+
+class A {
+    constructor() { }
+}
+
+class B extends A {
+    constructor() {
+        super();
+        this;
+    }
+}
+
+noInline(B);
+
+for (var i = 0; i < 100000; ++i)
+    new B();

Added: trunk/Source/_javascript_Core/tests/stress/class-syntax-tdz-in-catch.js (0 => 181466)


--- trunk/Source/_javascript_Core/tests/stress/class-syntax-tdz-in-catch.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/class-syntax-tdz-in-catch.js	2015-03-13 01:11:15 UTC (rev 181466)
@@ -0,0 +1,31 @@
+//@ skip
+
+class A {
+    constructor() { }
+}
+
+class B extends A {
+    constructor() {
+        try {
+            this;
+        } catch (e) {
+            this;
+            super();
+        }
+    }
+}
+
+noInline(B);
+
+for (var i = 0; i < 100000; ++i) {
+    var exception = null;
+    try {
+         new B(false);
+    } catch (e) {
+        exception = e;
+        if (!(e instanceof ReferenceError))
+            throw "Exception thrown in iteration " + i + " was not a reference error";
+    }
+    if (!exception)
+        throw "Exception not thrown for an unitialized this at iteration " + i;
+}

Added: trunk/Source/_javascript_Core/tests/stress/class-syntax-tdz-in-conditional.js (0 => 181466)


--- trunk/Source/_javascript_Core/tests/stress/class-syntax-tdz-in-conditional.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/class-syntax-tdz-in-conditional.js	2015-03-13 01:11:15 UTC (rev 181466)
@@ -0,0 +1,29 @@
+//@ skip
+
+class A {
+    constructor() { }
+}
+
+class B extends A {
+    constructor(accessThisBeforeSuper) {
+        if (accessThisBeforeSuper)
+            this;
+        else {
+            this;
+            super();
+        }
+    }
+}
+
+noInline(B);
+
+for (var i = 0; i < 100000; ++i) {
+    var exception = null;
+    try {
+         new B(false);
+    } catch (e) {
+        exception = e;
+    }
+    if (!exception)
+        throw "Exception not thrown for an unitialized this at iteration " + i;
+}

Added: trunk/Source/_javascript_Core/tests/stress/class-syntax-tdz-in-loop.js (0 => 181466)


--- trunk/Source/_javascript_Core/tests/stress/class-syntax-tdz-in-loop.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/class-syntax-tdz-in-loop.js	2015-03-13 01:11:15 UTC (rev 181466)
@@ -0,0 +1,31 @@
+//@ skip
+
+class A {
+    constructor() { }
+}
+
+class B extends A {
+    constructor() {
+        for (var j = 0; j < 100; j++) {
+            if (j)
+                super();
+            else
+                this;
+        }
+    }
+}
+
+noInline(B);
+
+for (var i = 0; i < 100000; ++i) {
+    var exception = null;
+    try {
+        new B();
+    } catch (e) {
+        exception = e;
+        if (!(e instanceof ReferenceError))
+            throw "Exception thrown in iteration " + i + " was not a reference error";
+    }
+    if (!exception)
+        throw "Exception not thrown for an unitialized this at iteration " + i;
+}

Added: trunk/Source/_javascript_Core/tests/stress/class-syntax-tdz.js (0 => 181466)


--- trunk/Source/_javascript_Core/tests/stress/class-syntax-tdz.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/class-syntax-tdz.js	2015-03-13 01:11:15 UTC (rev 181466)
@@ -0,0 +1,27 @@
+//@ skip
+
+class A {
+    constructor() { }
+}
+
+class B extends A {
+    constructor() {
+        this;
+        super();
+    }
+}
+
+noInline(B);
+
+for (var i = 0; i < 100000; ++i) {
+    var exception;
+    try {
+        new B();
+    } catch (e) {
+        exception = e;
+        if (!(e instanceof ReferenceError))
+            throw "Exception thrown in iteration " + i + " was not a reference error";
+    }
+    if (!exception)
+        throw "Exception not thrown for an unitialized this at iteration " + i;
+}
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to