Title: [217840] trunk
Revision
217840
Author
[email protected]
Date
2017-06-06 11:08:17 -0700 (Tue, 06 Jun 2017)

Log Message

index out of bound in bytecodebasicblock
https://bugs.webkit.org/show_bug.cgi?id=172963

Reviewed by Saam Barati and Mark Lam.
JSTests:


* stress/dfg-call-class-constructor.js: Added.
(Foo):
(i.catch):

Source/_javascript_Core:

        
We were leaving an unterminated basic block when generating CodeForCall for a class
constructor. This was mostly benign since that unterminated block was not reachable, but it
does cause an ASSERT.
        
This fixes the issue by appending op_unreachable to that block. I added op_unreachable because
this really is the cleanest and most idiomatic way to solve this problem, so even though it
makes the change bigger it's probabably worth it.

* bytecode/BytecodeDumper.cpp:
(JSC::BytecodeDumper<Block>::dumpBytecode):
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/Opcode.h:
(JSC::isTerminal):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::emitUnreachable):
* bytecompiler/BytecodeGenerator.h:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileUnreachable):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_unreachable):
* llint/LowLevelInterpreter.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:

Source/WTF:


* wtf/Assertions.h:
(UNREACHABLE_FOR_PLATFORM):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (217839 => 217840)


--- trunk/JSTests/ChangeLog	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/JSTests/ChangeLog	2017-06-06 18:08:17 UTC (rev 217840)
@@ -1,3 +1,14 @@
+2017-06-06  Filip Pizlo  <[email protected]>
+
+        index out of bound in bytecodebasicblock
+        https://bugs.webkit.org/show_bug.cgi?id=172963
+
+        Reviewed by Saam Barati and Mark Lam.
+
+        * stress/dfg-call-class-constructor.js: Added.
+        (Foo):
+        (i.catch):
+
 2017-06-05  Joseph Pecoraro  <[email protected]>
 
         Web Inspector: Improve ES6 Class instances in Heap Snapshot instances view

Added: trunk/JSTests/stress/dfg-call-class-constructor.js (0 => 217840)


--- trunk/JSTests/stress/dfg-call-class-constructor.js	                        (rev 0)
+++ trunk/JSTests/stress/dfg-call-class-constructor.js	2017-06-06 18:08:17 UTC (rev 217840)
@@ -0,0 +1,14 @@
+class Foo extends Promise { }
+
+noInline(Foo);
+
+for (var i = 0; i < 10000; ++i) {
+    var completed = false;
+    try {
+        Foo();
+        completed = true;
+    } catch (e) {
+    }
+    if (completed)
+        throw "Error: completed without throwing";
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (217839 => 217840)


--- trunk/Source/_javascript_Core/ChangeLog	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-06-06 18:08:17 UTC (rev 217840)
@@ -1,3 +1,46 @@
+2017-06-06  Filip Pizlo  <[email protected]>
+
+        index out of bound in bytecodebasicblock
+        https://bugs.webkit.org/show_bug.cgi?id=172963
+
+        Reviewed by Saam Barati and Mark Lam.
+        
+        We were leaving an unterminated basic block when generating CodeForCall for a class
+        constructor. This was mostly benign since that unterminated block was not reachable, but it
+        does cause an ASSERT.
+        
+        This fixes the issue by appending op_unreachable to that block. I added op_unreachable because
+        this really is the cleanest and most idiomatic way to solve this problem, so even though it
+        makes the change bigger it's probabably worth it.
+
+        * bytecode/BytecodeDumper.cpp:
+        (JSC::BytecodeDumper<Block>::dumpBytecode):
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/Opcode.h:
+        (JSC::isTerminal):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::generate):
+        (JSC::BytecodeGenerator::emitUnreachable):
+        * bytecompiler/BytecodeGenerator.h:
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileUnreachable):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * jit/JIT.h:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_unreachable):
+        * llint/LowLevelInterpreter.asm:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/CommonSlowPaths.h:
+
 2017-06-06  Ryan Haddad  <[email protected]>
 
         Unreviewed, rolling out r217812.

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeDumper.cpp (217839 => 217840)


--- trunk/Source/_javascript_Core/bytecode/BytecodeDumper.cpp	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeDumper.cpp	2017-06-06 18:08:17 UTC (rev 217840)
@@ -1568,6 +1568,10 @@
         out.printf("%s, %d", registerName(condition).data(), line);
         break;
     }
+    case op_unreachable: {
+        printLocationAndOp(out, location, it, "unreachable");
+        break;
+    }
     case op_end: {
         int r0 = (++it)->u.operand;
         printLocationOpAndRegisterOperand(out, location, it, "end", r0);

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeList.json (217839 => 217840)


--- trunk/Source/_javascript_Core/bytecode/BytecodeList.json	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeList.json	2017-06-06 18:08:17 UTC (rev 217840)
@@ -147,6 +147,7 @@
             { "name" : "op_enumerator_generic_pname", "length" : 4 },
             { "name" : "op_to_index_string", "length" : 3 },
             { "name" : "op_assert", "length" : 3 },
+            { "name" : "op_unreachable", "length" : 1 },
             { "name" : "op_create_rest", "length": 4 },
             { "name" : "op_get_rest_length", "length": 3 },
             { "name" : "op_yield", "length" : 4 },

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h (217839 => 217840)


--- trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeUseDef.h	2017-06-06 18:08:17 UTC (rev 217840)
@@ -55,6 +55,7 @@
     case op_check_traps:
     case op_get_argument:
     case op_nop:
+    case op_unreachable:
         return;
     case op_assert:
     case op_get_scope:
@@ -366,6 +367,7 @@
     case op_log_shadow_chicken_tail:
     case op_yield:
     case op_nop:
+    case op_unreachable:
 #define LLINT_HELPER_OPCODES(opcode, length) case opcode:
         FOR_EACH_LLINT_OPCODE_EXTENSION(LLINT_HELPER_OPCODES);
 #undef LLINT_HELPER_OPCODES

Modified: trunk/Source/_javascript_Core/bytecode/Opcode.h (217839 => 217840)


--- trunk/Source/_javascript_Core/bytecode/Opcode.h	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/bytecode/Opcode.h	2017-06-06 18:08:17 UTC (rev 217840)
@@ -175,6 +175,7 @@
     switch (opcodeID) {
     case op_ret:
     case op_end:
+    case op_unreachable:
         return true;
     default:
         return false;

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (217839 => 217840)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2017-06-06 18:08:17 UTC (rev 217840)
@@ -144,6 +144,13 @@
     bool callingClassConstructor = constructorKind() != ConstructorKind::None && !isConstructor();
     if (!callingClassConstructor)
         m_scopeNode->emitBytecode(*this);
+    else {
+        // At this point we would have emitted an unconditional throw followed by some nonsense that's
+        // just an artifact of how this generator is structured. That code never runs, but it confuses
+        // bytecode analyses because it constitutes an unterminated basic block. So, we terminate the
+        // basic block the strongest way possible.
+        emitUnreachable();
+    }
 
     m_staticPropertyAnalyzer.kill();
 
@@ -2954,6 +2961,11 @@
     return condition;
 }
 
+void BytecodeGenerator::emitUnreachable()
+{
+    emitOpcode(op_unreachable);
+}
+
 RegisterID* BytecodeGenerator::emitGetArgument(RegisterID* dst, int32_t index)
 {
     UnlinkedValueProfile profile = ""

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (217839 => 217840)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2017-06-06 18:08:17 UTC (rev 217840)
@@ -685,6 +685,7 @@
         RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value);
 
         RegisterID* emitAssert(RegisterID* condition, int line);
+        void emitUnreachable();
 
         void emitPutGetterById(RegisterID* base, const Identifier& property, unsigned propertyDescriptorOptions, RegisterID* getter);
         void emitPutSetterById(RegisterID* base, const Identifier& property, unsigned propertyDescriptorOptions, RegisterID* setter);

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (217839 => 217840)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2017-06-06 18:08:17 UTC (rev 217840)
@@ -5803,6 +5803,12 @@
             }
             NEXT_OPCODE(op_log_shadow_chicken_tail);
         }
+            
+        case op_unreachable: {
+            flushForTerminal();
+            addToGraph(Unreachable);
+            LAST_OPCODE(op_unreachable);
+        }
 
         default:
             // Parse failed! This should not happen because the capabilities checker

Modified: trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp (217839 => 217840)


--- trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2017-06-06 18:08:17 UTC (rev 217840)
@@ -250,6 +250,7 @@
     case op_resolve_scope:
     case op_resolve_scope_for_hoisting_func_decl_in_eval:
     case op_new_regexp:
+    case op_unreachable:
         return CanCompileAndInline;
 
     case op_switch_string: // Don't inline because we don't want to copy string tables in the concurrent JIT.

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (217839 => 217840)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2017-06-06 18:08:17 UTC (rev 217840)
@@ -10197,6 +10197,10 @@
         // after that opcode. You don't have to also prove to AI that your opcode does not return.
         // Hence, there is nothing to do here but emit code that will crash, so that we catch
         // cases where you said Unreachable but you lied.
+        //
+        // It's also also worth noting that some clients emit this opcode because they're not 100% sure
+        // if the code is unreachable, but they would really prefer if we crashed rather than kept going
+        // if it did turn out to be reachable. Hence, this needs to deterministically crash.
         
         crash();
     }

Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (217839 => 217840)


--- trunk/Source/_javascript_Core/jit/JIT.cpp	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp	2017-06-06 18:08:17 UTC (rev 217840)
@@ -289,6 +289,7 @@
         DEFINE_OP(op_get_rest_length)
         DEFINE_OP(op_check_tdz)
         DEFINE_OP(op_assert)
+        DEFINE_OP(op_unreachable)
         DEFINE_OP(op_debug)
         DEFINE_OP(op_del_by_id)
         DEFINE_OP(op_del_by_val)

Modified: trunk/Source/_javascript_Core/jit/JIT.h (217839 => 217840)


--- trunk/Source/_javascript_Core/jit/JIT.h	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/jit/JIT.h	2017-06-06 18:08:17 UTC (rev 217840)
@@ -489,6 +489,7 @@
         void emit_op_get_rest_length(Instruction*);
         void emit_op_check_tdz(Instruction*);
         void emit_op_assert(Instruction*);
+        void emit_op_unreachable(Instruction*);
         void emit_op_debug(Instruction*);
         void emit_op_del_by_id(Instruction*);
         void emit_op_del_by_val(Instruction*);

Modified: trunk/Source/_javascript_Core/jit/JITOpcodes.cpp (217839 => 217840)


--- trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2017-06-06 18:08:17 UTC (rev 217840)
@@ -558,6 +558,12 @@
     slowPathCall.call();
 }
 
+void JIT::emit_op_unreachable(Instruction* currentInstruction)
+{
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_unreachable);
+    slowPathCall.call();
+}
+
 void JIT::emit_op_create_lexical_environment(Instruction* currentInstruction)
 {
     JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_create_lexical_environment);

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (217839 => 217840)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2017-06-06 18:08:17 UTC (rev 217840)
@@ -1721,6 +1721,12 @@
     dispatch(3)
 
 
+_llint_op_unreachable:
+    traceExecution()
+    callOpcodeSlowPath(_slow_path_unreachable)
+    dispatch(1)
+
+
 _llint_op_yield:
     notSupported()
 

Modified: trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp (217839 => 217840)


--- trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/runtime/CommonSlowPaths.cpp	2017-06-06 18:08:17 UTC (rev 217840)
@@ -789,6 +789,13 @@
     END();
 }
 
+SLOW_PATH_DECL(slow_path_unreachable)
+{
+    BEGIN();
+    UNREACHABLE_FOR_PLATFORM();
+    END();
+}
+
 SLOW_PATH_DECL(slow_path_create_lexical_environment)
 {
     BEGIN();

Modified: trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h (217839 => 217840)


--- trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/_javascript_Core/runtime/CommonSlowPaths.h	2017-06-06 18:08:17 UTC (rev 217840)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2013, 2015-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -254,6 +254,7 @@
 SLOW_PATH_HIDDEN_DECL(slow_path_to_index_string);
 SLOW_PATH_HIDDEN_DECL(slow_path_profile_type_clear_log);
 SLOW_PATH_HIDDEN_DECL(slow_path_assert);
+SLOW_PATH_HIDDEN_DECL(slow_path_unreachable);
 SLOW_PATH_HIDDEN_DECL(slow_path_create_lexical_environment);
 SLOW_PATH_HIDDEN_DECL(slow_path_push_with_scope);
 SLOW_PATH_HIDDEN_DECL(slow_path_resolve_scope);

Modified: trunk/Source/WTF/ChangeLog (217839 => 217840)


--- trunk/Source/WTF/ChangeLog	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/WTF/ChangeLog	2017-06-06 18:08:17 UTC (rev 217840)
@@ -1,3 +1,13 @@
+2017-06-06  Filip Pizlo  <[email protected]>
+
+        index out of bound in bytecodebasicblock
+        https://bugs.webkit.org/show_bug.cgi?id=172963
+
+        Reviewed by Saam Barati and Mark Lam.
+
+        * wtf/Assertions.h:
+        (UNREACHABLE_FOR_PLATFORM):
+
 2017-06-05  Jer Noble  <[email protected]>
 
         Allow clients to specify a list of codecs which should require hardware decode support.

Modified: trunk/Source/WTF/wtf/Assertions.h (217839 => 217840)


--- trunk/Source/WTF/wtf/Assertions.h	2017-06-06 17:41:44 UTC (rev 217839)
+++ trunk/Source/WTF/wtf/Assertions.h	2017-06-06 18:08:17 UTC (rev 217840)
@@ -456,6 +456,8 @@
 #pragma clang diagnostic ignored "-Wmissing-noreturn"
 static inline void UNREACHABLE_FOR_PLATFORM()
 {
+    // This *MUST* be a release assert. We use it in places where it's better to crash than to keep
+    // going.
     RELEASE_ASSERT_NOT_REACHED();
 }
 #pragma clang diagnostic pop
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to