# HG changeset patch # User Tooru Fujisawa # Date 1467687983 -32400 # Tue Jul 05 12:06:23 2016 +0900 # Node ID 7cc17480d08daaee802a26a75da613cd25759e40 # Parent 7b3db06d27815e4f0684916da2b23a252185325b Bug 1016936 - Part 3: Support JSOP_CHECKISOBJ in Ion. diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -11565,16 +11565,38 @@ CodeGenerator::visitCheckReturn(LCheckRe Label bail, noChecks; masm.branchTestObject(Assembler::Equal, returnValue, &noChecks); masm.branchTestUndefined(Assembler::NotEqual, returnValue, &bail); masm.branchTestMagicValue(Assembler::Equal, thisValue, JS_UNINITIALIZED_LEXICAL, &bail); bailoutFrom(&bail, ins->snapshot()); masm.bind(&noChecks); } +typedef bool (*ThrowCheckIsObjectFn)(JSContext*, CheckIsObjectKind); +static const VMFunction ThrowCheckIsObjectInfo = + FunctionInfo(ThrowCheckIsObject, "ThrowCheckIsObject"); + +void +CodeGenerator::visitCheckIsObjV(LCheckIsObjV* ins) +{ + ValueOperand checkValue = ToValue(ins, LCheckIsObjV::CheckValue); + Label done; + masm.branchTestObject(Assembler::Equal, checkValue, &done); + pushArg(Imm32(ins->mir()->checkKind())); + callVM(ThrowCheckIsObjectInfo, ins); + masm.bind(&done); +} + +void +CodeGenerator::visitCheckIsObjT(LCheckIsObjT* ins) +{ + pushArg(Imm32(ins->mir()->checkKind())); + callVM(ThrowCheckIsObjectInfo, ins); +} + typedef bool (*ThrowObjCoercibleFn)(JSContext*, HandleValue); static const VMFunction ThrowObjectCoercibleInfo = FunctionInfo(ThrowObjectCoercible, "ThrowObjectCoercible"); void CodeGenerator::visitCheckObjCoercible(LCheckObjCoercible* ins) { ValueOperand checkValue = ToValue(ins, LCheckObjCoercible::CheckValue); diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -364,16 +364,18 @@ class CodeGenerator final : public CodeG void visitAsmJSVoidReturn(LAsmJSVoidReturn* ret); void visitLexicalCheck(LLexicalCheck* ins); void visitThrowRuntimeLexicalError(LThrowRuntimeLexicalError* ins); void visitGlobalNameConflictsCheck(LGlobalNameConflictsCheck* ins); void visitDebugger(LDebugger* ins); void visitNewTarget(LNewTarget* ins); void visitArrowNewTarget(LArrowNewTarget* ins); void visitCheckReturn(LCheckReturn* ins); + void visitCheckIsObjV(LCheckIsObjV* ins); + void visitCheckIsObjT(LCheckIsObjT* ins); void visitCheckObjCoercible(LCheckObjCoercible* ins); void visitDebugCheckSelfHosted(LDebugCheckSelfHosted* ins); void visitCheckOverRecursed(LCheckOverRecursed* lir); void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool); void visitUnboxFloatingPoint(LUnboxFloatingPoint* lir); void visitOutOfLineUnboxFloatingPoint(OutOfLineUnboxFloatingPoint* ool); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -2140,16 +2140,19 @@ IonBuilder::inspectOpcode(JSOp op) } // Just fall through to the unsupported bytecode case. break; case JSOP_NEWTARGET: return jsop_newtarget(); + case JSOP_CHECKISOBJ: + return jsop_checkisobj(GET_UINT8(pc)); + case JSOP_CHECKOBJCOERCIBLE: return jsop_checkobjcoercible(); case JSOP_DEBUGCHECKSELFHOSTED: { #ifdef DEBUG MDebugCheckSelfHosted* check = MDebugCheckSelfHosted::New(alloc(), current->pop()); current->add(check); @@ -10778,16 +10781,32 @@ IonBuilder::jsop_rest() // elements added. MSetInitializedLength* initLength = MSetInitializedLength::New(alloc(), elements, index); current->add(initLength); return true; } bool +IonBuilder::jsop_checkisobj(uint8_t kind) +{ + MDefinition* toCheck = current->peek(-1); + + if (toCheck->type() == MIRType::Object) { + toCheck->setImplicitlyUsedUnchecked(); + return true; + } + + MCheckIsObj* check = MCheckIsObj::New(alloc(), current->pop(), kind); + current->add(check); + current->push(check); + return resumeAfter(check); +} + +bool IonBuilder::jsop_checkobjcoercible() { MDefinition* toCheck = current->peek(-1); if (!toCheck->mightBeType(MIRType::Undefined) && !toCheck->mightBeType(MIRType::Null)) { toCheck->setImplicitlyUsedUnchecked(); diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -775,16 +775,17 @@ class IonBuilder MOZ_MUST_USE bool jsop_isnoiter(); MOZ_MUST_USE bool jsop_iterend(); MOZ_MUST_USE bool jsop_in(); MOZ_MUST_USE bool jsop_instanceof(); MOZ_MUST_USE bool jsop_getaliasedvar(ScopeCoordinate sc); MOZ_MUST_USE bool jsop_setaliasedvar(ScopeCoordinate sc); MOZ_MUST_USE bool jsop_debugger(); MOZ_MUST_USE bool jsop_newtarget(); + MOZ_MUST_USE bool jsop_checkisobj(uint8_t kind); MOZ_MUST_USE bool jsop_checkobjcoercible(); /* Inlining. */ enum InliningStatus { InliningStatus_Error, InliningStatus_NotInlined, diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -4506,16 +4506,36 @@ LIRGenerator::visitCheckReturn(MCheckRet LCheckReturn* lir = new(alloc()) LCheckReturn(useBoxAtStart(retVal), useBoxAtStart(thisVal)); assignSnapshot(lir, Bailout_BadDerivedConstructorReturn); add(lir, ins); redefine(ins, retVal); } void +LIRGenerator::visitCheckIsObj(MCheckIsObj* ins) +{ + MDefinition* checkVal = ins->checkValue(); + MOZ_ASSERT(checkVal->type() == MIRType::Value); + + if (checkVal->type() == MIRType::Value) { + LCheckIsObjV* lir = new(alloc()) LCheckIsObjV(useBoxAtStart(checkVal)); + redefine(ins, checkVal); + add(lir, ins); + assignSafepoint(lir, ins); + } else { + // Other case just throws regardless of the value. + LCheckIsObjT* lir = new(alloc()) LCheckIsObjT(); + redefine(ins, checkVal); + add(lir, ins); + assignSafepoint(lir, ins); + } +} + +void LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible* ins) { MDefinition* checkVal = ins->checkValue(); MOZ_ASSERT(checkVal->type() == MIRType::Value); LCheckObjCoercible* lir = new(alloc()) LCheckObjCoercible(useBoxAtStart(checkVal)); redefine(ins, checkVal); add(lir, ins); diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -312,16 +312,17 @@ class LIRGenerator : public LIRGenerator void visitThrowRuntimeLexicalError(MThrowRuntimeLexicalError* ins); void visitGlobalNameConflictsCheck(MGlobalNameConflictsCheck* ins); void visitDebugger(MDebugger* ins); void visitNewTarget(MNewTarget* ins); void visitArrowNewTarget(MArrowNewTarget* ins); void visitAtomicIsLockFree(MAtomicIsLockFree* ins); void visitGuardSharedTypedArray(MGuardSharedTypedArray* ins); void visitCheckReturn(MCheckReturn* ins); + void visitCheckIsObj(MCheckIsObj* ins); void visitCheckObjCoercible(MCheckObjCoercible* ins); void visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins); }; } // namespace jit } // namespace js #endif /* jit_Lowering_h */ diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -12851,16 +12851,38 @@ class MAtomicTypedArrayElementBinop class MDebugger : public MNullaryInstruction { public: INSTRUCTION_HEADER(Debugger) TRIVIAL_NEW_WRAPPERS }; +class MCheckIsObj + : public MUnaryInstruction, + public BoxInputsPolicy::Data +{ + uint8_t checkKind_; + + explicit MCheckIsObj(MDefinition* toCheck, uint8_t checkKind) + : MUnaryInstruction(toCheck), checkKind_(checkKind) + { + setResultType(MIRType::Value); + setResultTypeSet(toCheck->resultTypeSet()); + setGuard(); + } + + public: + INSTRUCTION_HEADER(CheckIsObj) + TRIVIAL_NEW_WRAPPERS + NAMED_OPERANDS((0, checkValue)) + + uint8_t checkKind() const { return checkKind_; } +}; + class MCheckObjCoercible : public MUnaryInstruction, public BoxInputsPolicy::Data { explicit MCheckObjCoercible(MDefinition* toCheck) : MUnaryInstruction(toCheck) { setGuard(); diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -294,16 +294,17 @@ namespace jit { _(UnknownValue) \ _(LexicalCheck) \ _(ThrowRuntimeLexicalError) \ _(GlobalNameConflictsCheck) \ _(Debugger) \ _(NewTarget) \ _(ArrowNewTarget) \ _(CheckReturn) \ + _(CheckIsObj) \ _(CheckObjCoercible) \ _(DebugCheckSelfHosted) // Forward declarations of MIR types. #define FORWARD_DECLARE(op) class M##op; MIR_OPCODE_LIST(FORWARD_DECLARE) #undef FORWARD_DECLARE diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -8370,16 +8370,42 @@ class LCheckReturn : public LCallInstruc setBoxOperand(ReturnValue, retVal); setBoxOperand(ThisValue, thisVal); } static const size_t ReturnValue = 0; static const size_t ThisValue = BOX_PIECES; }; +class LCheckIsObjV : public LCallInstructionHelper +{ + public: + LIR_HEADER(CheckIsObjV) + + static const size_t CheckValue = 0; + + explicit LCheckIsObjV(const LBoxAllocation& value) { + setBoxOperand(CheckValue, value); + } + + MCheckIsObj* mir() const { + return mir_->toCheckIsObj(); + } +}; + +class LCheckIsObjT : public LCallInstructionHelper<0, 0, 0> +{ + public: + LIR_HEADER(CheckIsObjT) + + MCheckIsObj* mir() const { + return mir_->toCheckIsObj(); + } +}; + class LCheckObjCoercible : public LCallInstructionHelper { public: LIR_HEADER(CheckObjCoercible) static const size_t CheckValue = 0; explicit LCheckObjCoercible(const LBoxAllocation& value) { diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -411,12 +411,14 @@ _(AssertResultT) \ _(LexicalCheck) \ _(ThrowRuntimeLexicalError) \ _(GlobalNameConflictsCheck) \ _(Debugger) \ _(NewTarget) \ _(ArrowNewTarget) \ _(CheckReturn) \ + _(CheckIsObjV) \ + _(CheckIsObjT) \ _(CheckObjCoercible) \ _(DebugCheckSelfHosted) #endif /* jit_shared_LOpcodes_shared_h */