blob: 442948536e731ebe06a8ae70f83643eb2362f402 [file] [log] [blame]
/*
* Copyright (C) 2009-2021 Apple Inc. All rights reserved.
* Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#if ENABLE(JIT)
#if USE(JSVALUE32_64)
#include "JIT.h"
#include "BasicBlockLocation.h"
#include "BytecodeGenerator.h"
#include "BytecodeStructs.h"
#include "InterpreterInlines.h"
#include "JITInlines.h"
#include "JSFunction.h"
#include "SlowPathCall.h"
#include "TypeProfilerLog.h"
#include "VirtualRegister.h"
namespace JSC {
void JIT::compileOpEqCommon(VirtualRegister src1, VirtualRegister src2)
{
emitGetVirtualRegister(src1, jsRegT10);
emitGetVirtualRegister(src2, jsRegT32);
addSlowCase(branch32(NotEqual, jsRegT10.tagGPR(), jsRegT32.tagGPR()));
addSlowCase(branchIfCell(jsRegT10));
addSlowCase(branch32(Below, jsRegT10.tagGPR(), TrustedImm32(JSValue::LowestTag)));
}
void JIT::compileOpEqSlowCommon(Vector<SlowCaseEntry>::iterator& iter)
{
JumpList genericCase;
genericCase.append(getSlowCase(iter)); // tags not equal
linkSlowCase(iter); // tags equal and JSCell
genericCase.append(branchIfNotString(jsRegT10.payloadGPR()));
genericCase.append(branchIfNotString(jsRegT32.payloadGPR()));
// String case.
loadGlobalObject(regT4);
callOperation(operationCompareStringEq, regT4, jsRegT10.payloadGPR(), jsRegT32.payloadGPR());
Jump done = jump();
// Generic case.
genericCase.append(getSlowCase(iter)); // doubles
genericCase.link(this);
loadGlobalObject(regT4);
callOperation(operationCompareEq, regT4, jsRegT10, jsRegT32);
done.link(this);
}
void JIT::emit_op_eq(const Instruction* currentInstruction)
{
auto bytecode = currentInstruction->as<OpEq>();
compileOpEqCommon(bytecode.m_lhs, bytecode.m_rhs);
compare32(Equal, jsRegT10.payloadGPR(), jsRegT32.payloadGPR(), regT0);
boxBoolean(regT0, jsRegT10);
emitPutVirtualRegister(bytecode.m_dst, jsRegT10);
}
void JIT::emit_op_neq(const Instruction* currentInstruction)
{
auto bytecode = currentInstruction->as<OpNeq>();
compileOpEqCommon(bytecode.m_lhs, bytecode.m_rhs);
compare32(NotEqual, jsRegT10.payloadGPR(), jsRegT32.payloadGPR(), regT0);
boxBoolean(regT0, jsRegT10);
emitPutVirtualRegister(bytecode.m_dst, jsRegT10);
}
void JIT::emit_op_jeq(const Instruction* currentInstruction)
{
auto bytecode = currentInstruction->as<OpJeq>();
unsigned target = jumpTarget(currentInstruction, bytecode.m_targetLabel);
compileOpEqCommon(bytecode.m_lhs, bytecode.m_rhs);
addJump(branch32(Equal, jsRegT10.payloadGPR(), jsRegT32.payloadGPR()), target);
}
void JIT::emit_op_jneq(const Instruction* currentInstruction)
{
auto bytecode = currentInstruction->as<OpJneq>();
unsigned target = jumpTarget(currentInstruction, bytecode.m_targetLabel);
compileOpEqCommon(bytecode.m_lhs, bytecode.m_rhs);
addJump(branch32(NotEqual, jsRegT10.payloadGPR(), jsRegT32.payloadGPR()), target);
}
void JIT::emitSlow_op_eq(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
auto bytecode = currentInstruction->as<OpEq>();
compileOpEqSlowCommon(iter);
boxBoolean(returnValueGPR, returnValueJSR);
emitPutVirtualRegister(bytecode.m_dst, returnValueJSR);
}
void JIT::emitSlow_op_neq(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
auto bytecode = currentInstruction->as<OpNeq>();
compileOpEqSlowCommon(iter);
xor32(TrustedImm32(1), returnValueGPR);
boxBoolean(returnValueGPR, returnValueJSR);
emitPutVirtualRegister(bytecode.m_dst, returnValueJSR);
}
void JIT::emitSlow_op_jeq(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
auto bytecode = currentInstruction->as<OpJeq>();
unsigned target = jumpTarget(currentInstruction, bytecode.m_targetLabel);
compileOpEqSlowCommon(iter);
emitJumpSlowToHot(branchTest32(NonZero, returnValueGPR), target);
}
void JIT::emitSlow_op_jneq(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
auto bytecode = currentInstruction->as<OpJneq>();
unsigned target = jumpTarget(currentInstruction, bytecode.m_targetLabel);
compileOpEqSlowCommon(iter);
emitJumpSlowToHot(branchTest32(Zero, returnValueGPR), target);
}
void JIT::compileOpStrictEqCommon(VirtualRegister src1, VirtualRegister src2)
{
emitGetVirtualRegister(src1, jsRegT10);
emitGetVirtualRegister(src2, jsRegT32);
// Bail if the tags differ, or are double.
addSlowCase(branch32(NotEqual, jsRegT10.tagGPR(), jsRegT32.tagGPR()));
addSlowCase(branch32(Below, jsRegT10.tagGPR(), TrustedImm32(JSValue::LowestTag)));
// Jump to a slow case if both are strings or symbols (non object).
Jump notCell = branchIfNotCell(jsRegT10);
Jump firstIsObject = branchIfObject(jsRegT10.payloadGPR());
addSlowCase(branchIfNotObject(jsRegT32.payloadGPR()));
notCell.link(this);
firstIsObject.link(this);
}
void JIT::emit_op_stricteq(const Instruction* currentInstruction)
{
auto bytecode = currentInstruction->as<OpStricteq>();
compileOpStrictEqCommon(bytecode.m_lhs, bytecode.m_rhs);
compare32(Equal, jsRegT10.payloadGPR(), jsRegT32.payloadGPR(), regT0);
boxBoolean(regT0, jsRegT10);
emitPutVirtualRegister(bytecode.m_dst, jsRegT10);
}
void JIT::emit_op_nstricteq(const Instruction* currentInstruction)
{
auto bytecode = currentInstruction->as<OpNstricteq>();
compileOpStrictEqCommon(bytecode.m_lhs, bytecode.m_rhs);
compare32(NotEqual, jsRegT10.payloadGPR(), jsRegT32.payloadGPR(), regT0);
boxBoolean(regT0, jsRegT10);
emitPutVirtualRegister(bytecode.m_dst, jsRegT10);
}
void JIT::emit_op_jstricteq(const Instruction* currentInstruction)
{
auto bytecode = currentInstruction->as<OpJstricteq>();
int target = jumpTarget(currentInstruction, bytecode.m_targetLabel);
compileOpStrictEqCommon(bytecode.m_lhs, bytecode.m_rhs);
addJump(branch32(Equal, jsRegT10.payloadGPR(), jsRegT32.payloadGPR()), target);
}
void JIT::emit_op_jnstricteq(const Instruction* currentInstruction)
{
auto bytecode = currentInstruction->as<OpJnstricteq>();
int target = jumpTarget(currentInstruction, bytecode.m_targetLabel);
compileOpStrictEqCommon(bytecode.m_lhs, bytecode.m_rhs);
addJump(branch32(NotEqual, jsRegT10.payloadGPR(), jsRegT32.payloadGPR()), target);
}
void JIT::emitSlow_op_jstricteq(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
linkAllSlowCases(iter);
auto bytecode = currentInstruction->as<OpJstricteq>();
unsigned target = jumpTarget(currentInstruction, bytecode.m_targetLabel);
loadGlobalObject(regT4);
callOperation(operationCompareStrictEq, regT4, jsRegT10, jsRegT32);
emitJumpSlowToHot(branchTest32(NonZero, returnValueGPR), target);
}
void JIT::emitSlow_op_jnstricteq(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
linkAllSlowCases(iter);
auto bytecode = currentInstruction->as<OpJnstricteq>();
unsigned target = jumpTarget(currentInstruction, bytecode.m_targetLabel);
loadGlobalObject(regT4);
callOperation(operationCompareStrictEq, regT4, jsRegT10, jsRegT32);
emitJumpSlowToHot(branchTest32(Zero, returnValueGPR), target);
}
} // namespace JSC
#endif // USE(JSVALUE32_64)
#endif // ENABLE(JIT)