/*
- * 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)
return triState(string->at(0) == character);
}
+static TriState equalToStringImpl(JSValue value, StringImpl* stringImpl)
+{
+ if (!value.isString())
+ return FalseTriState;
+
+ JSString* jsString = asString(value);
+ const StringImpl* string = jsString->tryGetValueImpl();
+ if (!string)
+ return MixedTriState;
+
+ 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:
+ case NewStringImpl:
+ return equalToStringImpl(value()->value(), other.stringImpl());
}
break;
case SingleCharacterString:
switch (other.m_kind) {
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());
+ default:
+ return other.strictEqual(*this);
+ }
+ 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);
}
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:
- value().dump(out);
+ 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()->dumpInContext(out, context);
return;
case SingleCharacterString:
out.print("Lazy:SingleCharacterString(");
out.printf("%04X", static_cast<unsigned>(character()));
out.print(" / ", StringImpl::utf8ForCharacters(&u.character, 1), ")");
return;
+ case KnownStringImpl:
+ 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)