Reviewed by Geoff Garen.
Inline code generation of eq_null/neq_null for CTI. Uses vptr checking for
StringObjectsThatAreMasqueradingAsBeingUndefined. In the long run, the
masquerading may be handled differently (through the StructureIDs - see bug
#20823).
>1% on v8-tests.
* VM/CTI.cpp:
(JSC::CTI::emitJumpSlowCaseIfIsJSCell):
(JSC::CTI::privateCompileMainPass):
(JSC::CTI::privateCompileSlowCases):
* VM/CTI.h:
* VM/Machine.cpp:
(JSC::Machine::Machine):
(JSC::Machine::cti_op_eq_null):
(JSC::Machine::cti_op_neq_null):
* VM/Machine.h:
(JSC::Machine::doesMasqueradesAsUndefined):
* kjs/JSWrapperObject.h:
(JSC::JSWrapperObject::):
(JSC::JSWrapperObject::JSWrapperObject):
* kjs/StringObject.h:
(JSC::StringObject::StringObject):
* kjs/StringObjectThatMasqueradesAsUndefined.h:
(JSC::StringObjectThatMasqueradesAsUndefined::StringObjectThatMasqueradesAsUndefined):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@36462
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2008-09-15 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ Inline code generation of eq_null/neq_null for CTI. Uses vptr checking for
+ StringObjectsThatAreMasqueradingAsBeingUndefined. In the long run, the
+ masquerading may be handled differently (through the StructureIDs - see bug
+ #20823).
+
+ >1% on v8-tests.
+
+ * VM/CTI.cpp:
+ (JSC::CTI::emitJumpSlowCaseIfIsJSCell):
+ (JSC::CTI::privateCompileMainPass):
+ (JSC::CTI::privateCompileSlowCases):
+ * VM/CTI.h:
+ * VM/Machine.cpp:
+ (JSC::Machine::Machine):
+ (JSC::Machine::cti_op_eq_null):
+ (JSC::Machine::cti_op_neq_null):
+ * VM/Machine.h:
+ (JSC::Machine::doesMasqueradesAsUndefined):
+ * kjs/JSWrapperObject.h:
+ (JSC::JSWrapperObject::):
+ (JSC::JSWrapperObject::JSWrapperObject):
+ * kjs/StringObject.h:
+ (JSC::StringObject::StringObject):
+ * kjs/StringObjectThatMasqueradesAsUndefined.h:
+ (JSC::StringObjectThatMasqueradesAsUndefined::StringObjectThatMasqueradesAsUndefined):
+
2008-09-15 Cameron Zwarich <cwzwarich@uwaterloo.ca>
Rubber-stamped by Oliver Hunt.
return call;
}
+ALWAYS_INLINE void CTI::emitJumpSlowCaseIfIsJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex)
+{
+ m_jit.testl_i32r(JSImmediate::TagMask, reg);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJe(), opcodeIndex));
+}
+
ALWAYS_INLINE void CTI::emitJumpSlowCaseIfNotJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex)
{
m_jit.testl_i32r(JSImmediate::TagMask, reg);
break;
}
case op_eq_null: {
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
- emitCall(i, Machine::cti_op_eq_null);
+ emitGetArg(instruction[i + 2].u.operand, X86::edx);
+
+ // go to a slow case either if this is not an immediate, or if the immediate is not undefined/null.
+ emitJumpSlowCaseIfIsJSCell(X86::edx, i);
+ m_jit.andl_i32r(~JSImmediate::ExtendedTagBitUndefined, X86::edx);
+ m_jit.cmpl_i32r(JSImmediate::FullTagTypeNull, X86::edx);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
+
+ m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::trueImmediate()), X86::eax);
emitPutResult(instruction[i + 1].u.operand);
+
i += 3;
break;
}
case op_neq_null: {
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
- emitCall(i, Machine::cti_op_neq_null);
+ emitGetArg(instruction[i + 2].u.operand, X86::edx);
+
+ // go to a slow case either if this is not an immediate, or if the immediate is not undefined/null.
+ emitJumpSlowCaseIfIsJSCell(X86::edx, i);
+ m_jit.andl_i32r(~JSImmediate::ExtendedTagBitUndefined, X86::edx);
+ m_jit.cmpl_i32r(JSImmediate::FullTagTypeNull, X86::edx);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
+
+ m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::falseImmediate()), X86::eax);
emitPutResult(instruction[i + 1].u.operand);
+
i += 3;
break;
}
break;
}
CTI_COMPILE_BINARY_OP_SLOW_CASE(op_mul);
+ case op_eq_null: {
+ m_jit.link(iter->from, m_jit.label());
+
+ // Value is a JSCell - speculate false, check for StringObjectThatMasqueradesAsUndefined.
+ m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::falseImmediate()), X86::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+ m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsStringObjectThatMasqueradesAsUndefinedVptr), X86::edx);
+ m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3]);
+
+ // Value is a StringObjectThatMasqueradesAsUndefined
+ m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::trueImmediate()), X86::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+ m_jit.link(m_jit.emitUnlinkedJmp(), m_labels[i + 3]);
+
+ // Value is an immediate other than undefined/null
+ m_jit.link((++iter)->from, m_jit.label());
+ m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::falseImmediate()), X86::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+
+ i += 3;
+ break;
+ }
+ case op_neq_null: {
+ m_jit.link(iter->from, m_jit.label());
+
+ // Value is a JSCell - speculate false, check for StringObjectThatMasqueradesAsUndefined.
+ m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::trueImmediate()), X86::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+ m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsStringObjectThatMasqueradesAsUndefinedVptr), X86::edx);
+ m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3]);
+
+ // Value is a StringObjectThatMasqueradesAsUndefined
+ m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::falseImmediate()), X86::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+ m_jit.link(m_jit.emitUnlinkedJmp(), m_labels[i + 3]);
+
+ // Value is an immediate other than undefined/null
+ m_jit.link((++iter)->from, m_jit.label());
+ m_jit.movl_i32r(reinterpret_cast<uint32_t>(JSImmediate::trueImmediate()), X86::eax);
+ emitPutResult(instruction[i + 1].u.operand);
+
+ i += 3;
+ break;
+ }
default:
ASSERT_NOT_REACHED();
break;
static const int repatchOffsetGetByIdStructureID = 19;
static const int repatchOffsetGetByIdBranchToSlowCase = 25;
static const int repatchOffsetGetByIdPropertyMapOffset = 34;
+#if ENABLE(SAMPLING_TOOL)
+ static const int repatchOffsetGetByIdSlowCaseCall = 27;
+#else
static const int repatchOffsetGetByIdSlowCaseCall = 17;
+#endif
public:
static void compile(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
JSValue* getConstantImmediateNumericArg(unsigned src);
unsigned getDeTaggedConstantImmediate(JSValue* imm);
+ void CTI::emitJumpSlowCaseIfIsJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex);
void CTI::emitJumpSlowCaseIfNotJSCell(X86Assembler::RegisterID reg, unsigned opcodeIndex);
void emitJumpSlowCaseIfNotImm(X86Assembler::RegisterID, unsigned opcodeIndex);
void emitJumpSlowCaseIfNotImms(X86Assembler::RegisterID, X86Assembler::RegisterID, unsigned opcodeIndex);
#include "debugger.h"
#include "operations.h"
#include "SamplingTool.h"
+#include "StringObjectThatMasqueradesAsUndefined.h"
#include <stdio.h>
#if PLATFORM(DARWIN)
m_jsArrayVptr = jsArray->vptr();
static_cast<JSCell*>(jsArray)->~JSCell();
+ StringObjectThatMasqueradesAsUndefined* jsStringObjectThatMasqueradesAsUndefined = new (storage) StringObjectThatMasqueradesAsUndefined(StringObjectThatMasqueradesAsUndefined::VPtrStealingHack);
+ m_jsStringObjectThatMasqueradesAsUndefinedVptr = jsStringObjectThatMasqueradesAsUndefined->vptr();
+ static_cast<JSCell*>(jsStringObjectThatMasqueradesAsUndefined)->~JSCell();
+
JSString* jsString = new (storage) JSString(JSString::VPtrStealingHack);
m_jsStringVptr = jsString->vptr();
static_cast<JSCell*>(jsString)->~JSCell();
JSValue* Machine::cti_op_eq_null(CTI_ARGS)
{
JSValue* src = ARG_src1;
+
if (src->isUndefinedOrNull())
return jsBoolean(true);
- return jsBoolean(!JSImmediate::isImmediate(src) && static_cast<JSCell*>(src)->masqueradeAsUndefined());
+ return jsBoolean(ARG_exec->machine()->doesMasqueradesAsUndefined(src));
}
JSValue* Machine::cti_op_neq_null(CTI_ARGS)
if (src->isUndefinedOrNull())
return jsBoolean(false);
- return jsBoolean(JSImmediate::isImmediate(src) || !static_cast<JSCell*>(src)->masqueradeAsUndefined());
+ return jsBoolean(!ARG_exec->machine()->doesMasqueradesAsUndefined(src));
}
void* Machine::cti_vm_throw(CTI_ARGS)
bool isJSArray(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsArrayVptr; }
bool isJSString(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsStringVptr; }
+ bool doesMasqueradesAsUndefined(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsStringObjectThatMasqueradesAsUndefinedVptr; }
void tryCacheGetByID(ExecState*, CodeBlock*, Instruction* vPC, JSValue* baseValue, const Identifier& propertyName, const PropertySlot&);
void uncacheGetByID(CodeBlock*, Instruction* vPC);
void* m_jsArrayVptr;
void* m_jsStringVptr;
+ void* m_jsStringObjectThatMasqueradesAsUndefinedVptr;
void* m_jsFunctionVptr;
#if HAVE(COMPUTED_GOTO)
virtual JSObject* toObject(ExecState*) const = 0;
// WebCore uses this to make document.all and style.filter undetectable
+ //
+ // This in checked in CTI using a vptr check, so currently only StringObjectThatMasqueradesAsUndefined
+ // overloading ths is supported. If this behaviour is required in other classes, then we will need
+ // update the code generated.
virtual bool masqueradeAsUndefined() const { return false; }
// Garbage collection.
*/
class JSWrapperObject : public JSObject {
public:
+
+ enum VPtrStealingHackType { VPtrStealingHack };
+ JSWrapperObject(VPtrStealingHackType)
+ : JSObject(StructureID::create(jsNull()))
+ {
+ }
+
JSWrapperObject(JSObject* prototype);
JSValue* internalValue() const;
class StringObject : public JSWrapperObject {
public:
+ StringObject(VPtrStealingHackType type)
+ : JSWrapperObject(type)
+ {
+ }
StringObject(ExecState*, JSObject* prototype);
StringObject(ExecState*, JSObject* prototype, const UString&);
// WebCore uses this to make style.filter undetectable
class StringObjectThatMasqueradesAsUndefined : public StringObject {
public:
+ StringObjectThatMasqueradesAsUndefined(VPtrStealingHackType type)
+ : StringObject(type)
+ {
+ }
StringObjectThatMasqueradesAsUndefined(ExecState* exec, JSObject* prototype, const UString& string)
: StringObject(exec, prototype, string)
{