Commit ad4425f8 authored by Tom Schuster's avatar Tom Schuster
Browse files

Bug 1350263 - Ion/MacroAssembler typeof object improvements. r=jandem

parent 204d59df
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
function test() {
    var funs = [function() {}, new Proxy(function() {}, {}), wrapWithProto(function() {}, null)];
    var objects = [{}, new Proxy({}, {}), wrapWithProto({}, null), new Proxy(objectEmulatingUndefined(), {})];
    var undefs = [objectEmulatingUndefined(), wrapWithProto(objectEmulatingUndefined(), null)];

    for (var fun of funs) {
        assertEq(typeof fun, "function")
    }

    for (var obj of objects) {
        assertEq(typeof obj, "object");
    }

    for (var undef of undefs) {
        assertEq(typeof undef, "undefined");
    }
}

test();
+3 −3
Original line number Diff line number Diff line
@@ -669,18 +669,18 @@ ICToBool_Object::Compiler::generateStubCode(MacroAssembler& masm)
{
    MOZ_ASSERT(engine_ == Engine::Baseline);

    Label failure, ifFalse, slowPath;
    Label failure, emulatesUndefined, slowPath;
    masm.branchTestObject(Assembler::NotEqual, R0, &failure);

    Register objReg = masm.extractObject(R0, ExtractTemp0);
    Register scratch = R1.scratchReg();
    masm.branchTestObjectTruthy(false, objReg, scratch, &slowPath, &ifFalse);
    masm.branchIfObjectEmulatesUndefined(objReg, scratch, &slowPath, &emulatesUndefined);

    // If object doesn't emulate undefined, it evaulates to true.
    masm.moveValue(BooleanValue(true), R0);
    EmitReturnFromIC(masm);

    masm.bind(&ifFalse);
    masm.bind(&emulatesUndefined);
    masm.moveValue(BooleanValue(false), R0);
    EmitReturnFromIC(masm);

+20 −2
Original line number Diff line number Diff line
@@ -592,7 +592,7 @@ CodeGenerator::testObjectEmulatesUndefinedKernel(Register objreg,
    // Perform a fast-path check of the object's class flags if the object's
    // not a proxy.  Let out-of-line code handle the slow cases that require
    // saving registers, making a function call, and restoring registers.
    masm.branchTestObjectTruthy(false, objreg, scratch, ool->entry(), ifEmulatesUndefined);
    masm.branchIfObjectEmulatesUndefined(objreg, scratch, ool->entry(), ifEmulatesUndefined);
}

void
@@ -10657,6 +10657,7 @@ void
CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool)
{
    LTypeOfV* ins = ool->ins();
    const JSAtomState& names = GetJitContext()->runtime->names();

    ValueOperand input = ToValue(ins, LTypeOfV::Input);
    Register temp = ToTempUnboxRegister(ins->tempToUnbox());
@@ -10664,12 +10665,29 @@ CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool)

    Register obj = masm.extractObject(input, temp);

    Label slowCheck, isObject, isCallable, isUndefined, done;
    masm.typeOfObject(obj, output, &slowCheck, &isObject, &isCallable, &isUndefined);

    masm.bind(&isCallable);
    masm.movePtr(ImmGCPtr(names.function), output);
    masm.jump(ool->rejoin());

    masm.bind(&isUndefined);
    masm.movePtr(ImmGCPtr(names.undefined), output);
    masm.jump(ool->rejoin());

    masm.bind(&isObject);
    masm.movePtr(ImmGCPtr(names.object), output);
    masm.jump(ool->rejoin());

    masm.bind(&slowCheck);

    saveVolatile(output);
    masm.setupUnalignedABICall(output);
    masm.passABIArg(obj);
    masm.movePtr(ImmPtr(GetJitContext()->runtime), output);
    masm.passABIArg(output);
    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::TypeOfObjectOperation));
    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, TypeOfObject));
    masm.storeCallWordResult(output);
    restoreVolatile(output);

+14 −16
Original line number Diff line number Diff line
@@ -464,6 +464,20 @@ MacroAssembler::branchIfInterpreted(Register fun, Label* label)
    branchTest32(Assembler::NonZero, address, Imm32(bit), label);
}

void
MacroAssembler::branchIfObjectEmulatesUndefined(Register objReg, Register scratch,
                                                Label* slowCheck, Label* label)
{
    // The branches to out-of-line code here implement a conservative version
    // of the JSObject::isWrapper test performed in EmulatesUndefined.
    loadObjClass(objReg, scratch);

    branchTestClassIsProxy(true, scratch, slowCheck);

    Address flags(scratch, Class::offsetOfFlags());
    branchTest32(Assembler::NonZero, flags, Imm32(JSCLASS_EMULATES_UNDEFINED), label);
}

void
MacroAssembler::branchFunctionKind(Condition cond, JSFunction::FunctionKind kind, Register fun,
                                   Register scratch, Label* label)
@@ -512,22 +526,6 @@ MacroAssembler::branchTestObjGroup(Condition cond, Register obj, Register group,
    branchPtr(cond, Address(obj, JSObject::offsetOfGroup()), group, label);
}

void
MacroAssembler::branchTestObjectTruthy(bool truthy, Register objReg, Register scratch,
                                       Label* slowCheck, Label* checked)
{
    // The branches to out-of-line code here implement a conservative version
    // of the JSObject::isWrapper test performed in EmulatesUndefined.  If none
    // of the branches are taken, we can check class flags directly.
    loadObjClass(objReg, scratch);
    Address flags(scratch, Class::offsetOfFlags());

    branchTestClassIsProxy(true, scratch, slowCheck);

    Condition cond = truthy ? Assembler::Zero : Assembler::NonZero;
    branchTest32(cond, flags, Imm32(JSCLASS_EMULATES_UNDEFINED), checked);
}

void
MacroAssembler::branchTestClassIsProxy(bool proxy, Register clasp, Label* label)
{
+27 −0
Original line number Diff line number Diff line
@@ -1436,6 +1436,33 @@ MacroAssembler::loadStringIndexValue(Register str, Register dest, Label* fail)
    rshift32(Imm32(JSString::INDEX_VALUE_SHIFT), dest);
}

void
MacroAssembler::typeOfObject(Register obj, Register scratch, Label* slow,
                             Label* isObject, Label* isCallable, Label* isUndefined)
{
    loadObjClass(obj, scratch);

    // Proxies can emulate undefined and have complex isCallable behavior.
    branchTestClassIsProxy(true, scratch, slow);

    // JSFunctions are always callable.
    branchPtr(Assembler::Equal, scratch, ImmPtr(&JSFunction::class_), isCallable);

    // Objects that emulate undefined.
    Address flags(scratch, Class::offsetOfFlags());
    branchTest32(Assembler::NonZero, flags, Imm32(JSCLASS_EMULATES_UNDEFINED), isUndefined);

    // Handle classes with a call hook.
    branchPtr(Assembler::Equal, Address(scratch, offsetof(js::Class, cOps)), ImmPtr(nullptr),
              isObject);

    loadPtr(Address(scratch, offsetof(js::Class, cOps)), scratch);
    branchPtr(Assembler::Equal, Address(scratch, offsetof(js::ClassOps, call)), ImmPtr(nullptr),
              isObject);

    jump(isCallable);
}

void
MacroAssembler::loadJSContext(Register dest)
{
Loading