DFG::LazyJSValue::tryGetStringImpl() crashes for empty values
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGLazyJSValue.cpp
index c7b05ed..468053e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2014, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #if ENABLE(DFG_JIT)
 
-#include "Operations.h"
+#include "CCallHelpers.h"
+#include "DFGGraph.h"
+#include "JSCInlines.h"
+#include "LinkBuffer.h"
 
 namespace JSC { namespace DFG {
 
+LazyJSValue LazyJSValue::newString(Graph& graph, const String& string)
+{
+    LazyJSValue result;
+    result.m_kind = NewStringImpl;
+    result.u.stringImpl = graph.m_localStrings.add(string).iterator->impl();
+    return result;
+}
+
 JSValue LazyJSValue::getValue(VM& vm) const
 {
     switch (m_kind) {
     case KnownValue:
-        return value();
+        return value()->value();
     case SingleCharacterString:
         return jsSingleCharacterString(&vm, u.character);
     case KnownStringImpl:
+    case NewStringImpl:
         return jsString(&vm, u.stringImpl);
     }
     RELEASE_ASSERT_NOT_REACHED();
+    return JSValue();
 }
 
 static TriState equalToSingleCharacter(JSValue value, UChar character)
@@ -74,17 +87,60 @@ static TriState equalToStringImpl(JSValue value, StringImpl* stringImpl)
     return triState(WTF::equal(stringImpl, string));
 }
 
+const StringImpl* LazyJSValue::tryGetStringImpl() const
+{
+    switch (m_kind) {
+    case KnownStringImpl:
+    case NewStringImpl:
+        return u.stringImpl;
+
+    case KnownValue:
+        if (JSString* string = value()->dynamicCast<JSString*>())
+            return string->tryGetValueImpl();
+        return nullptr;
+
+    default:
+        return nullptr;
+    }
+}
+
+String LazyJSValue::tryGetString(Graph& graph) const
+{
+    switch (m_kind) {
+    case NewStringImpl:
+        return u.stringImpl;
+
+    case SingleCharacterString:
+        return String(&u.character, 1);
+
+    default:
+        if (const StringImpl* string = tryGetStringImpl()) {
+            unsigned ginormousStringLength = 10000;
+            if (string->length() > ginormousStringLength)
+                return String();
+            
+            auto result = graph.m_copiedStrings.add(string, String());
+            if (result.isNewEntry)
+                result.iterator->value = string->isolatedCopy();
+            return result.iterator->value;
+        }
+        
+        return String();
+    }
+}
+
 TriState LazyJSValue::strictEqual(const LazyJSValue& other) const
 {
     switch (m_kind) {
     case KnownValue:
         switch (other.m_kind) {
         case KnownValue:
-            return JSValue::pureStrictEqual(value(), other.value());
+            return JSValue::pureStrictEqual(value()->value(), other.value()->value());
         case SingleCharacterString:
-            return equalToSingleCharacter(value(), other.character());
+            return equalToSingleCharacter(value()->value(), other.character());
         case KnownStringImpl:
-            return equalToStringImpl(value(), other.stringImpl());
+        case NewStringImpl:
+            return equalToStringImpl(value()->value(), other.stringImpl());
         }
         break;
     case SingleCharacterString:
@@ -92,6 +148,7 @@ TriState LazyJSValue::strictEqual(const LazyJSValue& other) const
         case SingleCharacterString:
             return triState(character() == other.character());
         case KnownStringImpl:
+        case NewStringImpl:
             if (other.stringImpl()->length() != 1)
                 return FalseTriState;
             return triState(other.stringImpl()->at(0) == character());
@@ -100,8 +157,10 @@ TriState LazyJSValue::strictEqual(const LazyJSValue& other) const
         }
         break;
     case KnownStringImpl:
+    case NewStringImpl:
         switch (other.m_kind) {
         case KnownStringImpl:
+        case NewStringImpl:
             return triState(WTF::equal(stringImpl(), other.stringImpl()));
         default:
             return other.strictEqual(*this);
@@ -109,13 +168,83 @@ TriState LazyJSValue::strictEqual(const LazyJSValue& other) const
         break;
     }
     RELEASE_ASSERT_NOT_REACHED();
+    return FalseTriState;
 }
 
-void LazyJSValue::dump(PrintStream& out) const
+uintptr_t LazyJSValue::switchLookupValue(SwitchKind kind) const
+{
+    // NB. Not every kind of JSValue will be able to give you a switch lookup
+    // value, and this method will assert, or do bad things, if you use it
+    // for a kind of value that can't.
+    switch (m_kind) {
+    case KnownValue:
+        switch (kind) {
+        case SwitchImm:
+            return value()->value().asInt32();
+        case SwitchCell:
+            return bitwise_cast<uintptr_t>(value()->value().asCell());
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            return 0;
+        }
+    case SingleCharacterString:
+        switch (kind) {
+        case SwitchChar:
+            return character();
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            return 0;
+        }
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        return 0;
+    }
+}
+
+void LazyJSValue::emit(CCallHelpers& jit, JSValueRegs result) const
+{
+    if (m_kind == KnownValue) {
+        jit.moveValue(value()->value(), result);
+        return;
+    }
+
+    // It must be some kind of cell.
+#if USE(JSVALUE32_64)
+    jit.move(CCallHelpers::TrustedImm32(JSValue::CellTag), result.tagGPR());
+#endif
+    CCallHelpers::DataLabelPtr label = jit.moveWithPatch(
+        CCallHelpers::TrustedImmPtr(static_cast<size_t>(0xd1e7beeflu)),
+        result.payloadGPR());
+
+    LazyJSValue thisValue = *this;
+
+    // Once we do this, we're committed. Otherwise we leak memory. Note that we call ref/deref
+    // manually to ensure that there is no concurrency shadiness. We are doing something here
+    // that might be rather brutal: transfering ownership of this string.
+    if (m_kind == NewStringImpl)
+        thisValue.u.stringImpl->ref();
+
+    CodeBlock* codeBlock = jit.codeBlock();
+    
+    jit.addLinkTask(
+        [codeBlock, label, thisValue] (LinkBuffer& linkBuffer) {
+            JSValue realValue = thisValue.getValue(linkBuffer.vm());
+            RELEASE_ASSERT(realValue.isCell());
+
+            codeBlock->addConstant(realValue);
+            
+            if (thisValue.m_kind == NewStringImpl)
+                thisValue.u.stringImpl->deref();
+
+            linkBuffer.patch(label, realValue.asCell());
+        });
+}
+
+void LazyJSValue::dumpInContext(PrintStream& out, DumpContext* context) const
 {
     switch (m_kind) {
     case KnownValue:
-        value().dump(out);
+        value()->dumpInContext(out, context);
         return;
     case SingleCharacterString:
         out.print("Lazy:SingleCharacterString(");
@@ -123,12 +252,20 @@ void LazyJSValue::dump(PrintStream& out) const
         out.print(" / ", StringImpl::utf8ForCharacters(&u.character, 1), ")");
         return;
     case KnownStringImpl:
-        out.print("Lazy:String(", stringImpl(), ")");
+        out.print("Lazy:KnownString(", stringImpl(), ")");
+        return;
+    case NewStringImpl:
+        out.print("Lazy:NewString(", stringImpl(), ")");
         return;
     }
     RELEASE_ASSERT_NOT_REACHED();
 }
 
+void LazyJSValue::dump(PrintStream& out) const
+{
+    dumpInContext(out, 0);
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)