Changeset 181466 in webkit


Ignore:
Timestamp:
Mar 12, 2015, 6:11:15 PM (10 years ago)
Author:
rniwa@webkit.org
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.
Location:
trunk/Source/JavaScriptCore
Files:
10 added
31 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r181458 r181466  
     12015-03-12  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        "this" should be in TDZ until super is called in the constructor of a derived class
     4        https://bugs.webkit.org/show_bug.cgi?id=142527
     5
     6        Reviewed by Mark Hahnenberg.
     7
     8        DFG and FTL implementations co-authored by Filip Pizlo.
     9
     10        In ES6 class syntax, "this" register must be in the "temporal dead zone" (TDZ) and throw ReferenceError until
     11        super() is called inside the constructor of a derived class.
     12
     13        Added op_check_tdz, a new OP code, which throws a reference error when the first operand is an empty value
     14        to all tiers of JIT and LLint. The op code throws in the slow path on the basis that a TDZ error should be
     15        a programming error and not a part of the programs' normal control flow. In DFG, this op code is represented
     16        by a no-op must-generate node CheckNotEmpty modeled after CheckCell.
     17
     18        Also made the constructor of a derived class assign the empty value to "this" register rather than undefined
     19        so that ThisNode can emit the op_check_tdz to check the initialized-ness of "this" in such a constructor.
     20
     21        * bytecode/BytecodeList.json: Added op_check_tdz.
     22        * bytecode/BytecodeUseDef.h:
     23        (JSC::computeUsesForBytecodeOffset): Ditto.
     24        (JSC::computeDefsForBytecodeOffset): Ditto.
     25        * bytecode/CodeBlock.cpp:
     26        (JSC::CodeBlock::dumpBytecode): Ditto.
     27        * bytecode/ExitKind.cpp:
     28        (JSC::exitKindToString): Added TDZFailure.
     29        * bytecode/ExitKind.h: Ditto.
     30        * bytecompiler/BytecodeGenerator.cpp:
     31        (JSC::BytecodeGenerator::BytecodeGenerator): Assign the empty value to "this" register to indicate it's in TDZ.
     32        (JSC::BytecodeGenerator::emitTDZCheck): Added.
     33        (JSC::BytecodeGenerator::emitReturn): Emit the TDZ check since "this" can still be in TDZ if super() was never
     34        called. e.g. class B extends A { constructor() { } }
     35        * bytecompiler/BytecodeGenerator.h:
     36        * bytecompiler/NodesCodegen.cpp:
     37        (JSC::ThisNode::emitBytecode): Always emit the TDZ check if we're inside the constructor of a derived class.
     38        We can't omit this check even if the result was ignored per spec.
     39        * dfg/DFGAbstractInterpreterInlines.h:
     40        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): Previously, empty value could never appear
     41        in a local variable. This is no longer true so generalize this code. Also added the support for CheckNotEmpty.
     42        Like CheckCell, we phantomize this DFG node in the constant folding phase if the type of the operand is already
     43        found to be not empty. Otherwise filter out SpecEmpty.
     44        * dfg/DFGByteCodeParser.cpp:
     45        (JSC::DFG::ByteCodeParser::parseBlock): Added op_check_tdz.
     46        * dfg/DFGCapabilities.cpp:
     47        (JSC::DFG::capabilityLevel): op_check_tdz can be compiled and inlined.
     48        * dfg/DFGClobberize.h:
     49        (JSC::DFG::clobberize): CheckNotEmpty doesn't read or write values.
     50        * dfg/DFGConstantFoldingPhase.cpp:
     51        (JSC::DFG::ConstantFoldingPhase::foldConstants): Convert CheckNotEmpty to a phantom if non-emptiness had already
     52        been proven for the operand prior to this node.
     53        * dfg/DFGDoesGC.cpp:
     54        (JSC::DFG::doesGC): CheckNotEmpty does not trigger GC.
     55        * dfg/DFGFixupPhase.cpp:
     56        (JSC::DFG::FixupPhase::fixupNode): CheckNotEmpty is a no-op in the fixup phase.
     57        * dfg/DFGNodeType.h: CheckNotEmpty cannot be removed even if the result was ignored. See ThisNode::emitBytecode.
     58        * dfg/DFGPredictionPropagationPhase.cpp:
     59        (JSC::DFG::PredictionPropagationPhase::propagate): CheckNotEmpty doesn't return any value.
     60        * dfg/DFGSafeToExecute.h:
     61        (JSC::DFG::safeToExecute): CheckNotEmpty doesn't load from heap so it's safe.
     62        * dfg/DFGSpeculativeJIT32_64.cpp:
     63        (JSC::DFG::SpeculativeJIT::compile): Speculative the operand to be not empty. OSR exit if the speculation fails.
     64        * dfg/DFGSpeculativeJIT64.cpp:
     65        (JSC::DFG::SpeculativeJIT::compile): Ditto.
     66        * ftl/FTLCapabilities.cpp:
     67        (JSC::FTL::canCompile): CheckNotEmpty can be compiled in FTL.
     68        * ftl/FTLLowerDFGToLLVM.cpp:
     69        (JSC::FTL::LowerDFGToLLVM::compileNode): Calls compileCheckNotEmpty for CheckNotEmpty.
     70        (JSC::FTL::LowerDFGToLLVM::compileCheckNotEmpty): OSR exit with "TDZFailure" if the operand is not empty.
     71        * jit/JIT.cpp:
     72        (JSC::JIT::privateCompileMainPass): Added op_check_tdz.
     73        (JSC::JIT::privateCompileSlowCases): Ditto.
     74        * jit/JIT.h:
     75        * jit/JITOpcodes.cpp:
     76        (JSC::JIT::emit_op_check_tdz): Implements op_check_tdz in Baseline JIT.
     77        (JSC::JIT::emitSlow_op_check_tdz): Ditto.
     78        * jit/JITOpcodes32_64.cpp:
     79        (JSC::JIT::emit_op_check_tdz): Ditto.
     80        (JSC::JIT::emitSlow_op_check_tdz): Ditto.
     81        * llint/LowLevelInterpreter32_64.asm: Implements op_check_tdz in LLint.
     82        * llint/LowLevelInterpreter64.asm: Ditto.
     83        * runtime/CommonSlowPaths.cpp:
     84        (JSC::SLOW_PATH_DECL): Throws a reference error for op_check_tdz. Shared by LLint and Baseline JIT.
     85        * runtime/CommonSlowPaths.h:
     86        * tests/stress/class-syntax-no-loop-tdz.js: Added.
     87        * tests/stress/class-syntax-no-tdz-in-catch.js: Added.
     88        * tests/stress/class-syntax-no-tdz-in-conditional.js: Added.
     89        * tests/stress/class-syntax-no-tdz-in-loop-no-inline-super.js: Added.
     90        * tests/stress/class-syntax-no-tdz-in-loop.js: Added.
     91        * tests/stress/class-syntax-no-tdz.js: Added.
     92        * tests/stress/class-syntax-tdz-in-catch.js: Added.
     93        * tests/stress/class-syntax-tdz-in-conditional.js: Added.
     94        * tests/stress/class-syntax-tdz-in-loop.js: Added.
     95        * tests/stress/class-syntax-tdz.js: Added.
     96
    1972015-03-12  Yusuke Suzuki  <utatane.tea@gmail.com>
    298
  • trunk/Source/JavaScriptCore/bytecode/BytecodeList.json

    r180917 r181466  
    1212            { "name" : "op_create_this", "length" : 4 },
    1313            { "name" : "op_to_this", "length" : 4 },
     14            { "name" : "op_check_tdz", "length" : 2 },
    1415            { "name" : "op_new_object", "length" : 4 },
    1516            { "name" : "op_new_array", "length" : 5 },
  • trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h

    r180917 r181466  
    5757    case op_get_scope:
    5858    case op_to_this:
     59    case op_check_tdz:
    5960    case op_pop_scope:
    6061    case op_profile_will_call:
     
    365366    case op_new_object:
    366367    case op_to_this:
     368    case op_check_tdz:
    367369    case op_init_lazy_reg:
    368370    case op_get_scope:
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r181456 r181466  
    788788                out.print(" cache(struct = ", RawPointer(structure), ")");
    789789            out.print(" ", (++it)->u.toThisStatus);
     790            break;
     791        }
     792        case op_check_tdz: {
     793            int r0 = (++it)->u.operand;
     794            printLocationOpAndRegisterOperand(out, exec, location, it, "op_check_tdz", r0);
    790795            break;
    791796        }
  • trunk/Source/JavaScriptCore/bytecode/ExitKind.cpp

    r180703 r181466  
    7171    case VarargsOverflow:
    7272        return "VarargsOverflow";
     73    case TDZFailure:
     74        return "TDZFailure";
    7375    case Uncountable:
    7476        return "Uncountable";
  • trunk/Source/JavaScriptCore/bytecode/ExitKind.h

    r180703 r181466  
    4848    NotStringObject, // We exited because we shouldn't have attempted to optimize string object access.
    4949    VarargsOverflow, // We exited because a varargs call passed more arguments than we expected.
     50    TDZFailure, // We exited because we were in the TDZ and accessed the variable.
    5051    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.
    5152    UncountableInvalidation, // We exited because the code block was invalidated; this means that we've already counted the reasons why the code block was invalidated.
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r181353 r181466  
    405405            m_newTargetRegister = addVar();
    406406            emitMove(m_newTargetRegister, &m_thisRegister);
    407             emitLoad(&m_thisRegister, jsNull());
     407            emitMove(&m_thisRegister, addConstantEmptyValue());
    408408        } else
    409409            emitCreateThis(&m_thisRegister);
     
    15571557}
    15581558
     1559void BytecodeGenerator::emitTDZCheck(RegisterID* target)
     1560{
     1561    emitOpcode(op_check_tdz);
     1562    instructions().append(target->index());
     1563}
     1564
    15591565RegisterID* BytecodeGenerator::emitNewObject(RegisterID* dst)
    15601566{
     
    19081914
    19091915    bool thisMightBeUninitialized = constructorKindIsDerived();
    1910     if (isConstructor() && (src->index() != m_thisRegister.index() || thisMightBeUninitialized)) {
     1916    bool srcIsThis = src->index() == m_thisRegister.index();
     1917    if (isConstructor() && (!srcIsThis || thisMightBeUninitialized)) {
    19111918        RefPtr<Label> isObjectOrUndefinedLabel = newLabel();
    19121919
     1920        if (srcIsThis && thisMightBeUninitialized)
     1921            emitTDZCheck(src);
     1922
    19131923        emitJumpIfTrue(emitIsObject(newTemporary(), src), isObjectOrUndefinedLabel.get());
    19141924
    1915         if (constructorKindIsDerived()) {
     1925        if (thisMightBeUninitialized) {
    19161926            emitJumpIfTrue(emitIsUndefined(newTemporary(), src), isObjectOrUndefinedLabel.get());
    19171927            emitThrowTypeError("Cannot return a non-object type in the constructor of a derived class.");
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r181293 r181466  
    459459
    460460        RegisterID* emitCreateThis(RegisterID* dst);
     461        void emitTDZCheck(RegisterID* target);
    461462        RegisterID* emitNewObject(RegisterID* dst);
    462463        RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r181293 r181466  
    145145RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    146146{
     147    if (generator.constructorKindIsDerived())
     148        generator.emitTDZCheck(generator.thisRegister());
     149
    147150    if (dst == generator.ignoredResult())
    148151        return 0;
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r181035 r181466  
    144144       
    145145    case ExtractOSREntryLocal: {
    146         if (!(node->unlinkedLocal().isArgument())
    147             && m_graph.m_lazyVars.get(node->unlinkedLocal().toLocal())) {
    148             // This is kind of pessimistic - we could know in some cases that the
    149             // DFG code at the point of the OSR had already initialized the lazy
    150             // variable. But maybe this is fine, since we're inserting OSR
    151             // entrypoints very early in the pipeline - so any lazy initializations
    152             // ought to be hoisted out anyway.
    153             forNode(node).makeBytecodeTop();
    154         } else
    155             forNode(node).makeHeapTop();
     146        forNode(node).makeBytecodeTop();
    156147        break;
    157148    }
     
    18661857            break;
    18671858        }
    1868        
    18691859        filterByValue(node->child1(), *node->cellOperand());
    18701860        break;
    18711861    }
    1872        
     1862
     1863    case CheckNotEmpty: {
     1864        AbstractValue& value = forNode(node->child1());
     1865        if (!(value.m_type & SpecEmpty)) {
     1866            m_state.setFoundConstants(true);
     1867            break;
     1868        }
     1869       
     1870        filter(value, ~SpecEmpty);
     1871        break;
     1872    }
     1873
    18731874    case CheckInBounds: {
    18741875        JSValue left = forNode(node->child1()).value();
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r181035 r181466  
    28212821            set(VirtualRegister(currentInstruction[1].u.operand), op);
    28222822            NEXT_OPCODE(op_mov);
     2823        }
     2824
     2825        case op_check_tdz: {
     2826            Node* op = get(VirtualRegister(currentInstruction[1].u.operand));
     2827            addToGraph(CheckNotEmpty, op);
     2828            NEXT_OPCODE(op_check_tdz);
    28232829        }
    28242830
  • trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp

    r180993 r181466  
    100100    case op_touch_entry:
    101101    case op_to_this:
     102    case op_check_tdz:
    102103    case op_create_this:
    103104    case op_bitand:
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r181035 r181466  
    255255        def(PureValue(CheckCell, AdjacencyList(AdjacencyList::Fixed, node->child1()), node->cellOperand()));
    256256        return;
    257        
     257
     258    case CheckNotEmpty:
     259        def(PureValue(CheckNotEmpty, AdjacencyList(AdjacencyList::Fixed, node->child1())));
     260        return;
     261
    258262    case ConstantStoragePointer:
    259263        def(PureValue(node, node->storagePointer()));
  • trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp

    r180691 r181466  
    186186                break;
    187187            }
    188                
     188
     189            case CheckNotEmpty: {
     190                if (m_state.forNode(node->child1()).m_type & SpecEmpty)
     191                    break;
     192                node->convertToPhantom();
     193                eliminated = true;
     194                break;
     195            }
     196
    189197            case CheckInBounds: {
    190198                JSValue left = m_state.forNode(node->child1()).value();
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r181035 r181466  
    106106    case VarInjectionWatchpoint:
    107107    case CheckCell:
     108    case CheckNotEmpty:
    108109    case AllocationProfileWatchpoint:
    109110    case RegExpExec:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r181035 r181466  
    12701270        case ForceOSRExit:
    12711271        case CheckBadCell:
     1272        case CheckNotEmpty:
    12721273        case CheckWatchdogTimer:
    12731274        case Unreachable:
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r181035 r181466  
    192192    macro(VarInjectionWatchpoint, NodeMustGenerate) \
    193193    macro(CheckCell, NodeMustGenerate) \
     194    macro(CheckNotEmpty, NodeMustGenerate) \
    194195    macro(CheckBadCell, NodeMustGenerate) \
    195196    macro(AllocationProfileWatchpoint, NodeMustGenerate) \
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r181035 r181466  
    627627        case CheckStructure:
    628628        case CheckCell:
     629        case CheckNotEmpty:
    629630        case CheckBadCell:
    630631        case PutStructure:
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r181035 r181466  
    179179    case CheckCell:
    180180    case CheckBadCell:
     181    case CheckNotEmpty:
    181182    case AllocationProfileWatchpoint:
    182183    case RegExpExec:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r181334 r181466  
    37593759    }
    37603760
     3761    case CheckNotEmpty: {
     3762        JSValueOperand operand(this, node->child1());
     3763        GPRReg tagGPR = operand.tagGPR();
     3764        speculationCheck(TDZFailure, JSValueSource(), nullptr, m_jit.branch32(JITCompiler::Equal, tagGPR, TrustedImm32(JSValue::EmptyValueTag)));
     3765        noResult(node);
     3766        break;
     3767    }
     3768
    37613769    case GetExecutable: {
    37623770        SpeculateCellOperand function(this, node->child1());
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r181035 r181466  
    38433843        break;
    38443844    }
    3845        
     3845
     3846    case CheckNotEmpty: {
     3847        JSValueOperand operand(this, node->child1());
     3848        GPRReg gpr = operand.gpr();
     3849        speculationCheck(TDZFailure, JSValueSource(), nullptr, m_jit.branchTest64(JITCompiler::Zero, gpr));
     3850        noResult(node);
     3851        break;
     3852    }
     3853
    38463854    case GetExecutable: {
    38473855        SpeculateCellOperand function(this, node->child1());
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r181035 r181466  
    111111    case CheckCell:
    112112    case CheckBadCell:
     113    case CheckNotEmpty:
    113114    case StringCharCodeAt:
    114115    case AllocatePropertyStorage:
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp

    r181035 r181466  
    547547            compileCheckCell();
    548548            break;
     549        case CheckNotEmpty:
     550            compileCheckNotEmpty();
     551            break;
    549552        case CheckBadCell:
    550553            compileCheckBadCell();
     
    18631866        terminate(BadCell);
    18641867    }
    1865    
     1868
     1869    void compileCheckNotEmpty()
     1870    {
     1871        speculate(TDZFailure, noValue(), nullptr, m_out.isZero64(lowJSValue(m_node->child1())));
     1872    }
     1873
    18661874    void compileGetExecutable()
    18671875    {
  • trunk/Source/JavaScriptCore/jit/JIT.cpp

    r181343 r181466  
    202202        DEFINE_OP(op_create_this)
    203203        DEFINE_OP(op_to_this)
     204        DEFINE_OP(op_check_tdz)
    204205        DEFINE_OP(op_init_lazy_reg)
    205206        DEFINE_OP(op_create_arguments)
     
    376377        DEFINE_SLOWCASE_OP(op_construct)
    377378        DEFINE_SLOWCASE_OP(op_to_this)
     379        DEFINE_SLOWCASE_OP(op_check_tdz)
    378380        DEFINE_SLOWCASE_OP(op_create_this)
    379381        DEFINE_SLOWCASE_OP(op_div)
  • trunk/Source/JavaScriptCore/jit/JIT.h

    r180917 r181466  
    469469        void emit_op_create_this(Instruction*);
    470470        void emit_op_to_this(Instruction*);
     471        void emit_op_check_tdz(Instruction*);
    471472        void emit_op_create_arguments(Instruction*);
    472473        void emit_op_debug(Instruction*);
     
    573574        void emitSlow_op_to_this(Instruction*, Vector<SlowCaseEntry>::iterator&);
    574575        void emitSlow_op_create_this(Instruction*, Vector<SlowCaseEntry>::iterator&);
     576        void emitSlow_op_check_tdz(Instruction*, Vector<SlowCaseEntry>::iterator&);
    575577        void emitSlow_op_div(Instruction*, Vector<SlowCaseEntry>::iterator&);
    576578        void emitSlow_op_eq(Instruction*, Vector<SlowCaseEntry>::iterator&);
  • trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp

    r180917 r181466  
    757757}
    758758
     759void JIT::emit_op_check_tdz(Instruction* currentInstruction)
     760{
     761    emitGetVirtualRegister(currentInstruction[1].u.operand, regT0);
     762    addSlowCase(branchTest64(Zero, regT0));
     763}
     764
     765void JIT::emitSlow_op_check_tdz(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     766{
     767    linkSlowCase(iter);
     768    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_throw_tdz_error);
     769    slowPathCall.call();
     770}
     771
    759772void JIT::emit_op_profile_will_call(Instruction* currentInstruction)
    760773{
  • trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp

    r180917 r181466  
    998998}
    999999
     1000void JIT::emit_op_check_tdz(Instruction* currentInstruction)
     1001{
     1002    emitLoadTag(currentInstruction[1].u.operand, regT0);
     1003    addSlowCase(branch32(Equal, regT0, TrustedImm32(JSValue::EmptyValueTag)));
     1004}
     1005
     1006void JIT::emitSlow_op_check_tdz(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     1007{
     1008    linkSlowCase(iter);
     1009    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_throw_tdz_error);
     1010    slowPathCall.call();
     1011}
     1012
    10001013void JIT::emit_op_profile_will_call(Instruction* currentInstruction)
    10011014{
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm

    r180917 r181466  
    802802    callSlowPath(_llint_slow_path_new_object)
    803803    dispatch(4)
     804
     805
     806_llint_op_check_tdz:
     807    traceExecution()
     808    loadpFromInstruction(1, t0)
     809    bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opNotTDZ
     810    callSlowPath(_slow_path_throw_tdz_error)
     811
     812.opNotTDZ:
     813    dispatch(2)
    804814
    805815
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r180917 r181466  
    686686    callSlowPath(_llint_slow_path_new_object)
    687687    dispatch(4)
     688
     689
     690_llint_op_check_tdz:
     691    traceExecution()
     692    loadpFromInstruction(1, t0)
     693    loadq [cfr, t0, 8], t0
     694    bqneq t0, ValueEmpty, .opNotTDZ
     695    callSlowPath(_slow_path_throw_tdz_error)
     696
     697.opNotTDZ:
     698    dispatch(2)
    688699
    689700
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

    r180917 r181466  
    258258}
    259259
     260SLOW_PATH_DECL(slow_path_throw_tdz_error)
     261{
     262    BEGIN();
     263    THROW(createReferenceError(exec, "Cannot access uninitialized variable."));
     264}
     265
    260266SLOW_PATH_DECL(slow_path_not)
    261267{
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.h

    r180587 r181466  
    188188SLOW_PATH_HIDDEN_DECL(slow_path_get_callee);
    189189SLOW_PATH_HIDDEN_DECL(slow_path_to_this);
     190SLOW_PATH_HIDDEN_DECL(slow_path_throw_tdz_error);
    190191SLOW_PATH_HIDDEN_DECL(slow_path_not);
    191192SLOW_PATH_HIDDEN_DECL(slow_path_eq);
Note: See TracChangeset for help on using the changeset viewer.