DirectArguments should protect itself using dynamic poisoning and precise index masking
https://bugs.webkit.org/show_bug.cgi?id=182086

Reviewed by Saam Barati.
        
Source/JavaScriptCore:

This implements dynamic poisoning and precise index masking in DirectArguments, using the
helpers from <wtf/MathExtras.h> and helpers in AssemblyHelpers and FTL::LowerDFGToB3.
        
We use dynamic poisoning for DirectArguments since this object did not have any additional
indirection inside it that could have been poisoned. So, we use the xor of the expected type
and the actual type as an additional input into the pointer.
        
We use precise index masking for bounds checks, because it's not worth doing index masking
unless we know that precise index masking is too slow.

* assembler/MacroAssembler.h:
(JSC::MacroAssembler::lshiftPtr):
(JSC::MacroAssembler::rshiftPtr):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileGetByValOnDirectArguments):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileGetByVal):
(JSC::FTL::DFG::LowerDFGToB3::compileGetMyArgumentByVal):
(JSC::FTL::DFG::LowerDFGToB3::preciseIndexMask64):
(JSC::FTL::DFG::LowerDFGToB3::preciseIndexMask32):
(JSC::FTL::DFG::LowerDFGToB3::dynamicPoison):
(JSC::FTL::DFG::LowerDFGToB3::dynamicPoisonOnLoadedType):
(JSC::FTL::DFG::LowerDFGToB3::dynamicPoisonOnType):
* jit/AssemblyHelpers.cpp:
(JSC::AssemblyHelpers::emitPreciseIndexMask32):
(JSC::AssemblyHelpers::emitDynamicPoison):
(JSC::AssemblyHelpers::emitDynamicPoisonOnLoadedType):
(JSC::AssemblyHelpers::emitDynamicPoisonOnType):
* jit/AssemblyHelpers.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emitDirectArgumentsGetByVal):
* runtime/DirectArguments.h:
(JSC::DirectArguments::getIndexQuickly const):
(JSC::DirectArguments::setIndexQuickly):
(JSC::DirectArguments::argument):
* runtime/GenericArgumentsInlines.h:

Source/WTF:

Add helpers for:
        
Dynamic poisoning: this means arranging to have the pointer you will dereference become an
invalid pointer if the type check you were relying on would have failed.
        
Precise index masking: a variant of index masking that does not depend on distancing. I figured
I'd just try this first for DirectArguments, since I didn't think that arguments[i] was ever
hot enough to warrant anything better. Turns out that in all of the benchmarks that care about
arguments performance, we optimize things to the point that the index masking isn't on a hot
path anymore. Turns out, it's neutral!

* wtf/MathExtras.h:
(WTF::preciseIndexMask):
(WTF::dynamicPoison):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@227643 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/runtime/DirectArguments.h b/Source/JavaScriptCore/runtime/DirectArguments.h
index 8a14d30..1606f1a 100644
--- a/Source/JavaScriptCore/runtime/DirectArguments.h
+++ b/Source/JavaScriptCore/runtime/DirectArguments.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -98,13 +98,15 @@
     JSValue getIndexQuickly(uint32_t i) const
     {
         ASSERT_WITH_SECURITY_IMPLICATION(isMappedArgument(i));
-        return const_cast<DirectArguments*>(this)->storage()[i].get();
+        auto* ptr = &const_cast<DirectArguments*>(this)->storage()[i];
+        return preciseIndexMaskPtr(i, m_length, dynamicPoison(type(), DirectArgumentsType, ptr))->get();
     }
     
     void setIndexQuickly(VM& vm, uint32_t i, JSValue value)
     {
         ASSERT_WITH_SECURITY_IMPLICATION(isMappedArgument(i));
-        storage()[i].set(vm, this, value);
+        auto* ptr = &storage()[i];
+        preciseIndexMaskPtr(i, m_length, dynamicPoison(type(), DirectArgumentsType, ptr))->set(vm, this, value);
     }
     
     WriteBarrier<JSFunction>& callee()
@@ -116,7 +118,8 @@
     {
         ASSERT(offset);
         ASSERT_WITH_SECURITY_IMPLICATION(offset.offset() < std::max(m_length, m_minCapacity));
-        return storage()[offset.offset()];
+        auto* ptr = &storage()[offset.offset()];
+        return *preciseIndexMaskPtr(offset.offset(), std::max(m_length, m_minCapacity), dynamicPoison(type(), DirectArgumentsType, ptr));
     }
     
     // Methods intended for use by the GenericArguments mixin.