void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID) { int callee = instruction[1].u.operand; int argCount = instruction[2].u.operand; int registerOffset = instruction[3].u.operand; linkSlowCase(iter); linkSlowCase(iter); // Fast check for JS function. Jump callLinkFailNotObject = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)); Jump callLinkFailNotJSFunction = emitJumpIfNotType(regT0, regT1, JSFunctionType); // Speculatively roll the callframe, assuming argCount will match the arity. store32(TrustedImm32(JSValue::CellTag), tagFor(RegisterFile::CallerFrame + registerOffset, callFrameRegister)); storePtr(callFrameRegister, payloadFor(RegisterFile::CallerFrame + registerOffset, callFrameRegister)); addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister); move(Imm32(argCount), regT1); m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs->ctiVirtualConstructLink() : m_globalData->jitStubs->ctiVirtualCallLink()); // Done! - return back to the hot path. ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval)); ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct)); emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call)); // This handles host functions callLinkFailNotJSFunction.link(this); move(TrustedImm32(JSValue::CellTag), regT1); // Restore cell tag since it was clobbered. callLinkFailNotObject.link(this); JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction); stubCall.addArgument(callee); stubCall.addArgument(JIT::Imm32(registerOffset)); stubCall.addArgument(JIT::Imm32(argCount)); stubCall.call(); sampleCodeBlock(m_codeBlock); }
AssemblyHelpers::Jump AssemblyHelpers::emitExceptionCheck(ExceptionCheckKind kind, ExceptionJumpWidth width) { callExceptionFuzz(); if (width == FarJumpWidth) kind = (kind == NormalExceptionCheck ? InvertedExceptionCheck : NormalExceptionCheck); Jump result; #if USE(JSVALUE64) result = branchTest64(kind == NormalExceptionCheck ? NonZero : Zero, AbsoluteAddress(vm()->addressOfException())); #elif USE(JSVALUE32_64) result = branch32(kind == NormalExceptionCheck ? NotEqual : Equal, AbsoluteAddress(vm()->addressOfException()), TrustedImm32(0)); #endif if (width == NormalJumpWidth) return result; PatchableJump realJump = patchableJump(); result.link(this); return realJump.m_jump; }
void JIT::emit_op_ret(Instruction* currentInstruction) { unsigned dst = currentInstruction[1].u.operand; // We could JIT generate the deref, only calling out to C when the refcount hits zero. if (m_codeBlock->needsFullScopeChain()) { Jump activationNotCreated = branch32(Equal, tagFor(m_codeBlock->activationRegister()), Imm32(JSValue::EmptyValueTag)); JITStubCall(this, cti_op_ret_scopeChain).call(); activationNotCreated.link(this); } emitLoad(dst, regT1, regT0); #ifdef OPT_SCHED emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regLink); emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); #else emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2); emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); restoreReturnAddressBeforeReturn(regT2); #endif ret(); }
void SampleCustomGravityCameraController::onDigitalInputEvent(const SampleFramework::InputEvent& ie, bool val) { if(val) { if(ie.m_Id == CAMERA_MOVE_FORWARD) mFwd = true; else if(ie.m_Id == CAMERA_MOVE_BACKWARD) mBwd = true; else if(ie.m_Id == CAMERA_MOVE_LEFT) mLeft = true; else if(ie.m_Id == CAMERA_MOVE_RIGHT) mRight = true; else if(ie.m_Id == CAMERA_SHIFT_SPEED) mKeyShiftDown = true; else if(ie.m_Id == CAMERA_JUMP) gJump.startJump(gJumpForce); } else { if(ie.m_Id == CAMERA_MOVE_FORWARD) mFwd = false; else if(ie.m_Id == CAMERA_MOVE_BACKWARD) mBwd = false; else if(ie.m_Id == CAMERA_MOVE_LEFT) mLeft = false; else if(ie.m_Id == CAMERA_MOVE_RIGHT) mRight = false; else if(ie.m_Id == CAMERA_SHIFT_SPEED) mKeyShiftDown = false; } }
void Generator::generateBackreference(JumpList& failures, unsigned subpatternId) { push(index); push(repeatCount); // get the start pos of the backref into repeatCount (multipurpose!) load32(Address(output, (2 * subpatternId) * sizeof(int)), repeatCount); Jump skipIncrement = jump(); Label topOfLoop(this); add32(Imm32(1), index); add32(Imm32(1), repeatCount); skipIncrement.link(this); // check if we're at the end of backref (if we are, success!) Jump endOfBackRef = je32(Address(output, ((2 * subpatternId) + 1) * sizeof(int)), repeatCount); load16(BaseIndex(input, repeatCount, MacroAssembler::TimesTwo), character); // check if we've run out of input (this would be a can o'fail) Jump endOfInput = je32(length, index); je16(character, BaseIndex(input, index, TimesTwo), topOfLoop); endOfInput.link(this); // Failure pop(repeatCount); pop(index); failures.append(jump()); // Success endOfBackRef.link(this); pop(repeatCount); pop(); }
AssemblyHelpers::JumpList AssemblyHelpers::branchIfNotType( JSValueRegs regs, GPRReg tempGPR, const InferredType::Descriptor& descriptor, TagRegistersMode mode) { AssemblyHelpers::JumpList result; switch (descriptor.kind()) { case InferredType::Bottom: result.append(jump()); break; case InferredType::Boolean: result.append(branchIfNotBoolean(regs, tempGPR)); break; case InferredType::Other: result.append(branchIfNotOther(regs, tempGPR)); break; case InferredType::Int32: result.append(branchIfNotInt32(regs, mode)); break; case InferredType::Number: result.append(branchIfNotNumber(regs, tempGPR, mode)); break; case InferredType::String: result.append(branchIfNotCell(regs, mode)); result.append(branchIfNotString(regs.payloadGPR())); break; case InferredType::ObjectWithStructure: result.append(branchIfNotCell(regs, mode)); result.append( branchStructure( NotEqual, Address(regs.payloadGPR(), JSCell::structureIDOffset()), descriptor.structure())); break; case InferredType::ObjectWithStructureOrOther: { Jump ok = branchIfOther(regs, tempGPR); result.append(branchIfNotCell(regs, mode)); result.append( branchStructure( NotEqual, Address(regs.payloadGPR(), JSCell::structureIDOffset()), descriptor.structure())); ok.link(this); break; } case InferredType::Object: result.append(branchIfNotCell(regs, mode)); result.append(branchIfNotObject(regs.payloadGPR())); break; case InferredType::ObjectOrOther: { Jump ok = branchIfOther(regs, tempGPR); result.append(branchIfNotCell(regs, mode)); result.append(branchIfNotObject(regs.payloadGPR())); ok.link(this); break; } case InferredType::Top: break; } return result; }
void AssemblyHelpers::jitAssertIsNull(GPRReg gpr) { Jump checkNull = branchTestPtr(Zero, gpr); abortWithReason(AHIsNotNull); checkNull.link(this); }
void AssemblyHelpers::jitAssertIsCell(GPRReg gpr) { Jump checkCell = branch32(Equal, gpr, TrustedImm32(JSValue::CellTag)); abortWithReason(AHIsNotCell); checkCell.link(this); }
void AssemblyHelpers::jitAssertIsCell(GPRReg gpr) { Jump checkCell = branchTest64(MacroAssembler::Zero, gpr, GPRInfo::tagMaskRegister); abortWithReason(AHIsNotCell); checkCell.link(this); }
void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex) { int callee = instruction[2].u.operand; /* Caller always: - Updates callFrameRegister to callee callFrame. - Initializes ArgumentCount; CallerFrame; Callee. For a JS call: - Caller initializes ScopeChain. - Callee initializes ReturnPC; CodeBlock. - Callee restores callFrameRegister before return. For a non-JS call: - Caller initializes ScopeChain; ReturnPC; CodeBlock. - Caller restores callFrameRegister after return. */ if (opcodeID == op_call_varargs) compileLoadVarargs(instruction); else { int argCount = instruction[3].u.operand; int registerOffset = -instruction[4].u.operand; if (opcodeID == op_call && shouldEmitProfiling()) { emitLoad(registerOffset + CallFrame::argumentOffsetIncludingThis(0), regT0, regT1); Jump done = branch32(NotEqual, regT0, TrustedImm32(JSValue::CellTag)); loadPtr(Address(regT1, JSCell::structureOffset()), regT1); storePtr(regT1, instruction[6].u.arrayProfile->addressOfLastSeenStructure()); done.link(this); } addPtr(TrustedImm32(registerOffset * sizeof(Register)), callFrameRegister, regT3); store32(TrustedImm32(argCount), payloadFor(JSStack::ArgumentCount, regT3)); } // regT3 holds newCallFrame with ArgumentCount initialized. uint32_t locationBits = CallFrame::Location::encodeAsBytecodeInstruction(instruction); store32(TrustedImm32(locationBits), tagFor(JSStack::ArgumentCount, callFrameRegister)); emitLoad(callee, regT1, regT0); // regT1, regT0 holds callee. storePtr(callFrameRegister, Address(regT3, JSStack::CallerFrame * static_cast<int>(sizeof(Register)))); emitStore(JSStack::Callee, regT1, regT0, regT3); move(regT3, callFrameRegister); if (opcodeID == op_call_eval) { compileCallEval(instruction); return; } DataLabelPtr addressOfLinkedFunctionCheck; Jump slowCase = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0)); addSlowCase(slowCase); addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag))); ASSERT(m_callStructureStubCompilationInfo.size() == callLinkInfoIndex); m_callStructureStubCompilationInfo.append(StructureStubCompilationInfo()); m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck; m_callStructureStubCompilationInfo[callLinkInfoIndex].callType = CallLinkInfo::callTypeFor(opcodeID); m_callStructureStubCompilationInfo[callLinkInfoIndex].bytecodeIndex = m_bytecodeOffset; loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scope)), regT1); emitPutCellToCallFrameHeader(regT1, JSStack::ScopeChain); m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall(); sampleCodeBlock(m_codeBlock); emitPutCallResult(instruction); }
void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex) { CallLinkInfo* info = m_codeBlock->addCallLinkInfo(); int callee = instruction[2].u.operand; /* Caller always: - Updates callFrameRegister to callee callFrame. - Initializes ArgumentCount; CallerFrame; Callee. For a JS call: - Callee initializes ReturnPC; CodeBlock. - Callee restores callFrameRegister before return. For a non-JS call: - Caller initializes ReturnPC; CodeBlock. - Caller restores callFrameRegister after return. */ if (opcodeID == op_call_varargs || opcodeID == op_construct_varargs) compileSetupVarargsFrame(instruction, info); else { int argCount = instruction[3].u.operand; int registerOffset = -instruction[4].u.operand; if (opcodeID == op_call && shouldEmitProfiling()) { emitLoad(registerOffset + CallFrame::argumentOffsetIncludingThis(0), regT0, regT1); Jump done = branch32(NotEqual, regT0, TrustedImm32(JSValue::CellTag)); loadPtr(Address(regT1, JSCell::structureIDOffset()), regT1); storePtr(regT1, instruction[OPCODE_LENGTH(op_call) - 2].u.arrayProfile->addressOfLastSeenStructureID()); done.link(this); } addPtr(TrustedImm32(registerOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), callFrameRegister, stackPointerRegister); store32(TrustedImm32(argCount), Address(stackPointerRegister, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC))); } // SP holds newCallFrame + sizeof(CallerFrameAndPC), with ArgumentCount initialized. uint32_t locationBits = CallFrame::Location::encodeAsBytecodeInstruction(instruction); store32(TrustedImm32(locationBits), tagFor(JSStack::ArgumentCount, callFrameRegister)); emitLoad(callee, regT1, regT0); // regT1, regT0 holds callee. store32(regT0, Address(stackPointerRegister, JSStack::Callee * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC))); store32(regT1, Address(stackPointerRegister, JSStack::Callee * static_cast<int>(sizeof(Register)) + TagOffset - sizeof(CallerFrameAndPC))); if (opcodeID == op_call_eval) { compileCallEval(instruction); return; } addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag))); DataLabelPtr addressOfLinkedFunctionCheck; Jump slowCase = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0)); addSlowCase(slowCase); ASSERT(m_callCompilationInfo.size() == callLinkInfoIndex); info->setUpCall(CallLinkInfo::callTypeFor(opcodeID), CodeOrigin(m_bytecodeOffset), regT0); m_callCompilationInfo.append(CallCompilationInfo()); m_callCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck; m_callCompilationInfo[callLinkInfoIndex].callLinkInfo = info; checkStackPointerAlignment(); m_callCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall(); addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister); checkStackPointerAlignment(); sampleCodeBlock(m_codeBlock); emitPutCallResult(instruction); }
void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex) { int dst = instruction[1].u.operand; int callee = instruction[2].u.operand; int argCount = instruction[3].u.operand; int registerOffset = instruction[4].u.operand; // Handle eval Jump wasEval; if (opcodeID == op_call_eval) { emitGetVirtualRegister(callee, X86::ecx); compileOpCallEvalSetupArgs(instruction); emitCTICall(Interpreter::cti_op_call_eval); wasEval = jnePtr(X86::eax, ImmPtr(JSValuePtr::encode(JSImmediate::impossibleValue()))); } // This plants a check for a cached JSFunction value, so we can plant a fast link to the callee. // This deliberately leaves the callee in ecx, used when setting up the stack frame below emitGetVirtualRegister(callee, X86::ecx); DataLabelPtr addressOfLinkedFunctionCheck; Jump jumpToSlow = jnePtrWithPatch(X86::ecx, addressOfLinkedFunctionCheck, ImmPtr(JSValuePtr::encode(JSImmediate::impossibleValue()))); addSlowCase(jumpToSlow); ASSERT(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow) == patchOffsetOpCallCompareToJump); m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck; // The following is the fast case, only used whan a callee can be linked. // In the case of OpConstruct, call out to a cti_ function to create the new object. if (opcodeID == op_construct) { int proto = instruction[5].u.operand; int thisRegister = instruction[6].u.operand; emitPutJITStubArg(X86::ecx, 1); emitPutJITStubArgFromVirtualRegister(proto, 4, X86::eax); emitCTICall(Interpreter::cti_op_construct_JSConstruct); emitPutVirtualRegister(thisRegister); emitGetVirtualRegister(callee, X86::ecx); } // Fast version of stack frame initialization, directly relative to edi. // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee storePtr(ImmPtr(JSValuePtr::encode(noValue())), Address(callFrameRegister, (registerOffset + RegisterFile::OptionalCalleeArguments) * static_cast<int>(sizeof(Register)))); storePtr(X86::ecx, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register)))); loadPtr(Address(X86::ecx, FIELD_OFFSET(JSFunction, m_scopeChain) + FIELD_OFFSET(ScopeChain, m_node)), X86::edx); // newScopeChain store32(Imm32(argCount), Address(callFrameRegister, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register)))); storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register)))); storePtr(X86::edx, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register)))); addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister); // Call to the callee m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall(reinterpret_cast<void*>(unreachable)); if (opcodeID == op_call_eval) wasEval.link(this); // Put the return value in dst. In the interpreter, op_ret does this. emitPutVirtualRegister(dst); #if ENABLE(CODEBLOCK_SAMPLING) storePtr(ImmPtr(m_codeBlock), m_interpreter->sampler()->codeBlockSlot()); #endif }
bool JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck) { SamplingRegion samplingRegion("DFG Backend"); setStartOfCode(); compileEntry(); // === Function header code generation === // This is the main entry point, without performing an arity check. // If we needed to perform an arity check we will already have moved the return address, // so enter after this. Label fromArityCheck(this); // Plant a check that sufficient space is available in the JSStack. // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56291 addPtr(TrustedImm32(m_codeBlock->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1); Jump stackCheck = branchPtr(Below, AbsoluteAddress(m_vm->interpreter->stack().addressOfEnd()), GPRInfo::regT1); // Return here after stack check. Label fromStackCheck = label(); // === Function body code generation === SpeculativeJIT speculative(*this); compileBody(speculative); setEndOfMainPath(); // === Function footer code generation === // // Generate code to perform the slow stack check (if the fast one in // the function header fails), and generate the entry point with arity check. // // Generate the stack check; if the fast check in the function head fails, // we need to call out to a helper function to check whether more space is available. // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions). stackCheck.link(this); move(stackPointerRegister, GPRInfo::argumentGPR0); poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); CallBeginToken token; beginCall(CodeOrigin(0), token); Call callStackCheck = call(); notifyCall(callStackCheck, CodeOrigin(0), token); jump(fromStackCheck); // The fast entry point into a function does not check the correct number of arguments // have been passed to the call (we only use the fast entry point where we can statically // determine the correct number of arguments have been passed, or have already checked). // In cases where an arity check is necessary, we enter here. // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions). Label arityCheck = label(); compileEntry(); load32(AssemblyHelpers::payloadFor((VirtualRegister)JSStack::ArgumentCount), GPRInfo::regT1); branch32(AboveOrEqual, GPRInfo::regT1, TrustedImm32(m_codeBlock->numParameters())).linkTo(fromArityCheck, this); move(stackPointerRegister, GPRInfo::argumentGPR0); poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); beginCall(CodeOrigin(0), token); Call callArityCheck = call(); notifyCall(callArityCheck, CodeOrigin(0), token); move(GPRInfo::regT0, GPRInfo::callFrameRegister); jump(fromArityCheck); // Generate slow path code. speculative.runSlowPathGenerators(); compileExceptionHandlers(); linkOSRExits(); // Create OSR entry trampolines if necessary. speculative.createOSREntries(); setEndOfCode(); // === Link === LinkBuffer linkBuffer(*m_vm, this, m_codeBlock, JITCompilationCanFail); if (linkBuffer.didFailToAllocate()) return false; link(linkBuffer); speculative.linkOSREntries(linkBuffer); // FIXME: switch the stack check & arity check over to DFGOpertaion style calls, not JIT stubs. linkBuffer.link(callStackCheck, cti_stack_check); linkBuffer.link(callArityCheck, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck); if (shouldShowDisassembly()) m_disassembler->dump(linkBuffer); if (m_graph.m_compilation) m_disassembler->reportToProfiler(m_graph.m_compilation.get(), linkBuffer); entryWithArityCheck = linkBuffer.locationOf(arityCheck); entry = JITCode( linkBuffer.finalizeCodeWithoutDisassembly(), JITCode::DFGJIT); return true; }
Palette* MuseScore::newRepeatsPalette() { Palette* sp = new Palette; sp->setName(tr("Repeats")); sp->setMag(0.65); sp->setGrid(84, 28); sp->setDrawGrid(true); RepeatMeasure* rm = new RepeatMeasure(gscore); sp->append(rm, tr("Repeat measure sign")); Marker* mk = new Marker(gscore); mk->setMarkerType(MARKER_SEGNO); sp->append(mk, tr("Segno")); mk = new Marker(gscore); mk->setMarkerType(MARKER_VARSEGNO); PaletteCell* cell = sp->append(mk, tr("Segno Variation"), "", 0.6); cell->yoffset = -2; mk = new Marker(gscore); mk->setMarkerType(MARKER_CODA); sp->append(mk, tr("Coda")); mk = new Marker(gscore); mk->setMarkerType(MARKER_VARCODA); sp->append(mk, tr("Varied coda")); mk = new Marker(gscore); mk->setMarkerType(MARKER_CODETTA); sp->append(mk, tr("Codetta")); mk = new Marker(gscore); mk->setMarkerType(MARKER_FINE); sp->append(mk, tr("Fine")); Jump* jp = new Jump(gscore); jp->setJumpType(JUMP_DC); sp->append(jp, tr("Da Capo")); jp = new Jump(gscore); jp->setJumpType(JUMP_DC_AL_FINE); sp->append(jp, tr("Da Capo al Fine")); jp = new Jump(gscore); jp->setJumpType(JUMP_DC_AL_CODA); sp->append(jp, tr("Da Capo al Coda")); jp = new Jump(gscore); jp->setJumpType(JUMP_DS_AL_CODA); sp->append(jp, tr("D.S al Coda")); jp = new Jump(gscore); jp->setJumpType(JUMP_DS_AL_FINE); sp->append(jp, tr("D.S al Fine")); jp = new Jump(gscore); jp->setJumpType(JUMP_DS); sp->append(jp, tr("D.S")); mk = new Marker(gscore); mk->setMarkerType(MARKER_TOCODA); sp->append(mk, tr("To Coda")); return sp; }
void SampleCustomGravityCameraController::update(Camera& camera, PxReal dtime) { const PxExtendedVec3& currentPos = mCCT.getPosition(); const PxVec3 curPos = toVec3(currentPos); // Compute up vector for current CCT position PxVec3 upVector; mBase.mPlanet.getUpVector(upVector, curPos); PX_ASSERT(upVector.isFinite()); // Update CCT if(!mBase.isPaused()) { if(1) { bool recordPos = true; const PxU32 currentSize = mNbRecords; if(currentSize) { const PxVec3 lastPos = mHistory[currentSize-1]; // const float limit = 0.1f; const float limit = 0.5f; if((curPos - lastPos).magnitude()<limit) recordPos = false; } if(recordPos) { if(mNbRecords==POS_HISTORY_LIMIT) { for(PxU32 i=1;i<mNbRecords;i++) mHistory[i-1] = mHistory[i]; mNbRecords--; } mHistory[mNbRecords++] = curPos; } } // Subtract off the 'up' component of the view direction to get our forward motion vector. PxVec3 viewDir = camera.getViewDir(); PxVec3 forward = (viewDir - upVector * upVector.dot(viewDir)).getNormalized(); // PxVec3 forward = mForward; // Compute "right" vector PxVec3 right = forward.cross(upVector); right.normalize(); // PxVec3 right = mRightV; PxVec3 targetKeyDisplacement(0); if(mFwd) targetKeyDisplacement += forward; if(mBwd) targetKeyDisplacement -= forward; if(mRight) targetKeyDisplacement += right; if(mLeft) targetKeyDisplacement -= right; targetKeyDisplacement *= mKeyShiftDown ? mRunningSpeed : mWalkingSpeed; // targetKeyDisplacement += PxVec3(0,-9.81,0); targetKeyDisplacement *= dtime; PxVec3 targetPadDisplacement(0); targetPadDisplacement += forward * mGamepadForwardInc * mRunningSpeed; targetPadDisplacement += right * mGamepadLateralInc * mRunningSpeed; // targetPadDisplacement += PxVec3(0,-9.81,0); targetPadDisplacement *= dtime; const PxF32 heightDelta = gJump.getHeight(dtime); // printf("%f\n", heightDelta); PxVec3 upDisp = upVector; if(heightDelta!=0.0f) upDisp *= heightDelta; else upDisp *= -9.81f * dtime; const PxVec3 disp = targetKeyDisplacement + targetPadDisplacement + upDisp; //upDisp.normalize(); //printf("%f | %f | %f\n", upDisp.x, upDisp.y, upDisp.z); // printf("%f | %f | %f\n", targetKeyDisplacement.x, targetKeyDisplacement.y, targetKeyDisplacement.z); // printf("%f | %f | %f\n\n", targetPadDisplacement.x, targetPadDisplacement.y, targetPadDisplacement.z); mCCT.setUpDirection(upVector); const PxU32 flags = mCCT.move(disp, 0.001f, dtime, PxControllerFilters()); if(flags & PxControllerFlag::eCOLLISION_DOWN) { gJump.stopJump(); // printf("Stop jump\n"); } } // Update camera if(1) { mTargetYaw += mGamepadYawInc * dtime; mTargetPitch += mGamepadPitchInc * dtime; // Clamp pitch // if(mTargetPitch<mPitchMin) mTargetPitch = mPitchMin; // if(mTargetPitch>mPitchMax) mTargetPitch = mPitchMax; } if(1) { PxVec3 up = upVector; PxQuat localPitchQ(mTargetPitch, PxVec3(1.0f, 0.0f, 0.0f)); PX_ASSERT(localPitchQ.isSane()); PxMat33 localPitchM(localPitchQ); const PxVec3 upRef(0.0f, 1.0f, 0.0f); PxQuat localYawQ(mTargetYaw, upRef); PX_ASSERT(localYawQ.isSane()); PxMat33 localYawM(localYawQ); bool res; PxQuat localToWorldQ = rotationArc(upRef, up, res); static PxQuat memory(0,0,0,1); if(!res) { localToWorldQ = memory; } else { memory = localToWorldQ; } PX_ASSERT(localToWorldQ.isSane()); PxMat33 localToWorld(localToWorldQ); static PxVec3 previousUp(0.0f, 1.0f, 0.0f); static PxQuat incLocalToWorldQ(0.0f, 0.0f, 0.0f, 1.0f); PxQuat incQ = rotationArc(previousUp, up, res); PX_ASSERT(incQ.isSane()); // incLocalToWorldQ = incLocalToWorldQ * incQ; incLocalToWorldQ = incQ * incLocalToWorldQ; PX_ASSERT(incLocalToWorldQ.isSane()); incLocalToWorldQ.normalize(); PxMat33 incLocalToWorldM(incLocalToWorldQ); localToWorld = incLocalToWorldM; previousUp = up; mTest = localToWorld; //mTest = localToWorld * localYawM; // PxMat33 rot = localYawM * localToWorld; PxMat33 rot = localToWorld * localYawM * localPitchM; // PxMat33 rot = localToWorld * localYawM; PX_ASSERT(rot.column0.isFinite()); PX_ASSERT(rot.column1.isFinite()); PX_ASSERT(rot.column2.isFinite()); //// PxMat44 view(rot.column0, rot.column1, rot.column2, PxVec3(0)); mForward = -rot.column2; mRightV = rot.column0; camera.setView(PxTransform(view)); PxVec3 viewDir = camera.getViewDir(); PX_ASSERT(viewDir.isFinite()); //// PxRigidActor* characterActor = mCCT.getActor(); PxShape* shape; characterActor->getShapes(&shape,1); PxCapsuleGeometry geom; shape->getCapsuleGeometry(geom); up *= geom.halfHeight+geom.radius; const PxVec3 headPos = curPos + up; const float distanceToTarget = 10.0f; // const float distanceToTarget = 20.0f; // const float distanceToTarget = 5.0f; // const PxVec3 camPos = headPos - viewDir*distanceToTarget; const PxVec3 camPos = headPos - mForward*distanceToTarget;// + up * 20.0f; // view.t = camPos; view.column3 = PxVec4(camPos,0); // camera.setView(view); camera.setView(PxTransform(view)); mTarget = headPos; } if(0) { PxControllerState cctState; mCCT.getState(cctState); printf("\nCCT state:\n"); printf("delta: %.02f | %.02f | %.02f\n", cctState.deltaXP.x, cctState.deltaXP.y, cctState.deltaXP.z); printf("touchedShape: %p\n", cctState.touchedShape); printf("touchedObstacle: %p\n", cctState.touchedObstacle); printf("standOnAnotherCCT: %d\n", cctState.standOnAnotherCCT); printf("standOnObstacle: %d\n", cctState.standOnObstacle); printf("isMovingUp: %d\n", cctState.isMovingUp); printf("collisionFlags: %d\n", cctState.collisionFlags); } }
void JITCompiler::compileFunction(JITCode& entry, MacroAssemblerCodePtr& entryWithArityCheck) { // === Stage 1 - Function header code generation === // // This code currently matches the old JIT. In the function header we need to // pop the return address (since we do not allow any recursion on the machine // stack), and perform a fast register file check. // This is the main entry point, without performing an arity check. // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56292 // We'll need to convert the remaining cti_ style calls (specifically the register file // check) which will be dependent on stack layout. (We'd need to account for this in // both normal return code and when jumping to an exception handler). preserveReturnAddressAfterCall(GPRInfo::regT2); emitPutToCallFrameHeader(GPRInfo::regT2, RegisterFile::ReturnPC); // If we needed to perform an arity check we will already have moved the return address, // so enter after this. Label fromArityCheck(this); // Setup a pointer to the codeblock in the CallFrameHeader. emitPutImmediateToCallFrameHeader(m_codeBlock, RegisterFile::CodeBlock); // Plant a check that sufficient space is available in the RegisterFile. // FIXME: https://bugs.webkit.org/show_bug.cgi?id=56291 addPtr(Imm32(m_codeBlock->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister, GPRInfo::regT1); Jump registerFileCheck = branchPtr(Below, AbsoluteAddress(m_globalData->interpreter->registerFile().addressOfEnd()), GPRInfo::regT1); // Return here after register file check. Label fromRegisterFileCheck = label(); // === Stage 2 - Function body code generation === // // We generate the speculative code path, followed by the non-speculative // code for the function. Next we need to link the two together, making // bail-outs from the speculative path jump to the corresponding point on // the non-speculative one (and generating any code necessary to juggle // register values around, rebox values, and ensure spilled, to match the // non-speculative path's requirements). #if DFG_JIT_BREAK_ON_EVERY_FUNCTION // Handy debug tool! breakpoint(); #endif // First generate the speculative path. Label speculativePathBegin = label(); SpeculativeJIT speculative(*this); #if !DFG_DEBUG_LOCAL_DISBALE_SPECULATIVE bool compiledSpeculative = speculative.compile(); #else bool compiledSpeculative = false; #endif // Next, generate the non-speculative path. We pass this a SpeculationCheckIndexIterator // to allow it to check which nodes in the graph may bail out, and may need to reenter the // non-speculative path. if (compiledSpeculative) { SpeculationCheckIndexIterator checkIterator(speculative.speculationChecks()); NonSpeculativeJIT nonSpeculative(*this); nonSpeculative.compile(checkIterator); // Link the bail-outs from the speculative path to the corresponding entry points into the non-speculative one. linkSpeculationChecks(speculative, nonSpeculative); } else { // If compilation through the SpeculativeJIT failed, throw away the code we generated. m_calls.clear(); rewindToLabel(speculativePathBegin); SpeculationCheckVector noChecks; SpeculationCheckIndexIterator checkIterator(noChecks); NonSpeculativeJIT nonSpeculative(*this); nonSpeculative.compile(checkIterator); } // === Stage 3 - Function footer code generation === // // Generate code to lookup and jump to exception handlers, to perform the slow // register file check (if the fast one in the function header fails), and // generate the entry point with arity check. // Iterate over the m_calls vector, checking for exception checks, // and linking them to here. unsigned exceptionCheckCount = 0; for (unsigned i = 0; i < m_calls.size(); ++i) { Jump& exceptionCheck = m_calls[i].m_exceptionCheck; if (exceptionCheck.isSet()) { exceptionCheck.link(this); ++exceptionCheckCount; } } // If any exception checks were linked, generate code to lookup a handler. if (exceptionCheckCount) { // lookupExceptionHandler is passed two arguments, exec (the CallFrame*), and // an identifier for the operation that threw the exception, which we can use // to look up handler information. The identifier we use is the return address // of the call out from JIT code that threw the exception; this is still // available on the stack, just below the stack pointer! move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); peek(GPRInfo::argumentGPR1, -1); m_calls.append(CallRecord(call(), lookupExceptionHandler)); // lookupExceptionHandler leaves the handler CallFrame* in the returnValueGPR, // and the address of the handler in returnValueGPR2. jump(GPRInfo::returnValueGPR2); } // Generate the register file check; if the fast check in the function head fails, // we need to call out to a helper function to check whether more space is available. // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions). registerFileCheck.link(this); move(stackPointerRegister, GPRInfo::argumentGPR0); poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); Call callRegisterFileCheck = call(); jump(fromRegisterFileCheck); // The fast entry point into a function does not check the correct number of arguments // have been passed to the call (we only use the fast entry point where we can statically // determine the correct number of arguments have been passed, or have already checked). // In cases where an arity check is necessary, we enter here. // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions). Label arityCheck = label(); preserveReturnAddressAfterCall(GPRInfo::regT2); emitPutToCallFrameHeader(GPRInfo::regT2, RegisterFile::ReturnPC); branch32(Equal, GPRInfo::regT1, Imm32(m_codeBlock->m_numParameters)).linkTo(fromArityCheck, this); move(stackPointerRegister, GPRInfo::argumentGPR0); poke(GPRInfo::callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*)); Call callArityCheck = call(); move(GPRInfo::regT0, GPRInfo::callFrameRegister); jump(fromArityCheck); // === Stage 4 - Link === // // Link the code, populate data in CodeBlock data structures. LinkBuffer linkBuffer(*m_globalData, this, m_globalData->executableAllocator); #if DFG_DEBUG_VERBOSE fprintf(stderr, "JIT code start at %p\n", linkBuffer.debugAddress()); #endif // Link all calls out from the JIT code to their respective functions. for (unsigned i = 0; i < m_calls.size(); ++i) linkBuffer.link(m_calls[i].m_call, m_calls[i].m_function); if (m_codeBlock->needsCallReturnIndices()) { m_codeBlock->callReturnIndexVector().reserveCapacity(exceptionCheckCount); for (unsigned i = 0; i < m_calls.size(); ++i) { if (m_calls[i].m_exceptionCheck.isSet()) { unsigned returnAddressOffset = linkBuffer.returnAddressOffset(m_calls[i].m_call); unsigned exceptionInfo = m_calls[i].m_exceptionInfo; m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeOffset(returnAddressOffset, exceptionInfo)); } } } // FIXME: switch the register file check & arity check over to DFGOpertaion style calls, not JIT stubs. linkBuffer.link(callRegisterFileCheck, cti_register_file_check); linkBuffer.link(callArityCheck, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck); entryWithArityCheck = linkBuffer.locationOf(arityCheck); entry = linkBuffer.finalizeCode(); }
void JITCompiler::jitAssertIsJSNumber(GPRReg gpr) { Jump checkTINumber = branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagTypeNumberRegister); breakpoint(); checkTINumber.link(this); }
void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID) { int dst = instruction[1].u.operand; int callee = instruction[2].u.operand; int argCount = instruction[3].u.operand; int registerOffset = instruction[4].u.operand; linkSlowCase(iter); // The arguments have been set up on the hot path for op_call_eval if (opcodeID == op_call) compileOpCallSetupArgs(instruction); else if (opcodeID == op_construct) compileOpConstructSetupArgs(instruction); // Fast check for JS function. Jump callLinkFailNotObject = emitJumpIfNotJSCell(X86::ecx); Jump callLinkFailNotJSFunction = jnePtr(Address(X86::ecx), ImmPtr(m_interpreter->m_jsFunctionVptr)); // First, in the case of a construct, allocate the new object. if (opcodeID == op_construct) { emitCTICall(Interpreter::cti_op_construct_JSConstruct); emitPutVirtualRegister(registerOffset - RegisterFile::CallFrameHeaderSize - argCount); emitGetVirtualRegister(callee, X86::ecx); } move(Imm32(argCount), X86::edx); // Speculatively roll the callframe, assuming argCount will match the arity. storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)))); addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister); m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_interpreter->m_ctiVirtualCallPreLink); Jump storeResultForFirstRun = jump(); // FIXME: this label can be removed, since it is a fixed offset from 'callReturnLocation'. // This is the address for the cold path *after* the first run (which tries to link the call). m_callStructureStubCompilationInfo[callLinkInfoIndex].coldPathOther = MacroAssembler::Label(this); // The arguments have been set up on the hot path for op_call_eval if (opcodeID == op_call) compileOpCallSetupArgs(instruction); else if (opcodeID == op_construct) compileOpConstructSetupArgs(instruction); // Check for JSFunctions. Jump isNotObject = emitJumpIfNotJSCell(X86::ecx); Jump isJSFunction = jePtr(Address(X86::ecx), ImmPtr(m_interpreter->m_jsFunctionVptr)); // This handles host functions isNotObject.link(this); callLinkFailNotObject.link(this); callLinkFailNotJSFunction.link(this); emitCTICall(((opcodeID == op_construct) ? Interpreter::cti_op_construct_NotJSConstruct : Interpreter::cti_op_call_NotJSFunction)); Jump wasNotJSFunction = jump(); // Next, handle JSFunctions... isJSFunction.link(this); // First, in the case of a construct, allocate the new object. if (opcodeID == op_construct) { emitCTICall(Interpreter::cti_op_construct_JSConstruct); emitPutVirtualRegister(registerOffset - RegisterFile::CallFrameHeaderSize - argCount); emitGetVirtualRegister(callee, X86::ecx); } // Speculatively roll the callframe, assuming argCount will match the arity. storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)))); addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister); move(Imm32(argCount), X86::edx); emitNakedCall(m_interpreter->m_ctiVirtualCall); // Put the return value in dst. In the interpreter, op_ret does this. wasNotJSFunction.link(this); storeResultForFirstRun.link(this); emitPutVirtualRegister(dst); #if ENABLE(CODEBLOCK_SAMPLING) storePtr(ImmPtr(m_codeBlock), m_interpreter->sampler()->codeBlockSlot()); #endif }
void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex) { int callee = instruction[1].u.operand; /* Caller always: - Updates callFrameRegister to callee callFrame. - Initializes ArgumentCount; CallerFrame; Callee. For a JS call: - Caller initializes ScopeChain. - Callee initializes ReturnPC; CodeBlock. - Callee restores callFrameRegister before return. For a non-JS call: - Caller initializes ScopeChain; ReturnPC; CodeBlock. - Caller restores callFrameRegister after return. */ if (opcodeID == op_call_varargs) compileLoadVarargs(instruction); else { int argCount = instruction[2].u.operand; int registerOffset = instruction[3].u.operand; if (opcodeID == op_call && canBeOptimized()) { emitGetVirtualRegister(registerOffset + CallFrame::argumentOffsetIncludingThis(0), regT0); Jump done = emitJumpIfNotJSCell(regT0); loadPtr(Address(regT0, JSCell::structureOffset()), regT0); storePtr(regT0, instruction[5].u.arrayProfile->addressOfLastSeenStructure()); done.link(this); } addPtr(TrustedImm32(registerOffset * sizeof(Register)), callFrameRegister, regT1); store32(TrustedImm32(argCount), Address(regT1, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))); } // regT1 holds newCallFrame with ArgumentCount initialized. store32(TrustedImm32(instruction - m_codeBlock->instructions().begin()), Address(callFrameRegister, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag))); emitGetVirtualRegister(callee, regT0); // regT0 holds callee. store64(callFrameRegister, Address(regT1, JSStack::CallerFrame * static_cast<int>(sizeof(Register)))); store64(regT0, Address(regT1, JSStack::Callee * static_cast<int>(sizeof(Register)))); move(regT1, callFrameRegister); if (opcodeID == op_call_eval) { compileCallEval(); return; } DataLabelPtr addressOfLinkedFunctionCheck; BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall); Jump slowCase = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0)); END_UNINTERRUPTED_SEQUENCE(sequenceOpCall); addSlowCase(slowCase); ASSERT(m_callStructureStubCompilationInfo.size() == callLinkInfoIndex); m_callStructureStubCompilationInfo.append(StructureStubCompilationInfo()); m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck; m_callStructureStubCompilationInfo[callLinkInfoIndex].callType = CallLinkInfo::callTypeFor(opcodeID); m_callStructureStubCompilationInfo[callLinkInfoIndex].bytecodeIndex = m_bytecodeOffset; loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scope)), regT1); emitPutToCallFrameHeader(regT1, JSStack::ScopeChain); m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall(); sampleCodeBlock(m_codeBlock); }
void AssemblyHelpers::jitAssertIsCell(GPRReg gpr) { Jump checkCell = branchTestPtr(MacroAssembler::Zero, gpr, GPRInfo::tagMaskRegister); breakpoint(); checkCell.link(this); }
void AssemblyHelpers::jitAssertIsJSNumber(GPRReg gpr) { Jump checkJSNumber = branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagTypeNumberRegister); abortWithReason(AHIsNotJSNumber); checkJSNumber.link(this); }
void AssemblyHelpers::jitAssertIsJSDouble(GPRReg gpr) { Jump checkJSDouble = branch32(Below, gpr, TrustedImm32(JSValue::LowestTag)); breakpoint(); checkJSDouble.link(this); }
void AssemblyHelpers::jitAssertIsJSDouble(GPRReg gpr) { Jump checkJSDouble = branch32(Below, gpr, TrustedImm32(JSValue::LowestTag)); abortWithReason(AHIsNotJSDouble); checkJSDouble.link(this); }
void AssemblyHelpers::jitAssertIsCell(GPRReg gpr) { Jump checkCell = branch32(Equal, gpr, TrustedImm32(JSValue::CellTag)); breakpoint(); checkCell.link(this); }
void AssemblyHelpers::jitAssertHasValidCallFrame() { Jump checkCFR = branchTestPtr(Zero, GPRInfo::callFrameRegister, TrustedImm32(7)); abortWithReason(AHCallFrameMisaligned); checkCFR.link(this); }
CompileStatus mjit::Compiler::compileArrayPopShift(FrameEntry *thisValue, bool isPacked, bool isArrayPop) { /* Filter out silly cases. */ if (thisValue->isConstant()) return Compile_InlineAbort; #ifdef JSGC_INCREMENTAL_MJ /* Write barrier. */ if (cx->compartment->needsBarrier()) return Compile_InlineAbort; #endif RegisterID objReg = frame.tempRegForData(thisValue); frame.pinReg(objReg); RegisterID lengthReg = frame.allocReg(); RegisterID slotsReg = frame.allocReg(); JSValueType type = knownPushedType(0); MaybeRegisterID dataReg, typeReg; if (!analysis->popGuaranteed(PC)) { dataReg = frame.allocReg(); if (type == JSVAL_TYPE_UNKNOWN || type == JSVAL_TYPE_DOUBLE) typeReg = frame.allocReg(); } if (isArrayPop) { frame.unpinReg(objReg); } else { /* * Sync up front for shift() so we can jump over the inline stub. * The result will be stored in memory rather than registers. */ frame.syncAndKillEverything(); frame.unpinKilledReg(objReg); } masm.loadPtr(Address(objReg, JSObject::offsetOfElements()), slotsReg); masm.load32(Address(slotsReg, ObjectElements::offsetOfLength()), lengthReg); /* Test for 'length == initializedLength' */ Int32Key key = Int32Key::FromRegister(lengthReg); Jump initlenGuard = masm.guardArrayExtent(ObjectElements::offsetOfInitializedLength(), slotsReg, key, Assembler::NotEqual); stubcc.linkExit(initlenGuard, Uses(3)); /* * Test for length != 0. On zero length either take a slow call or generate * an undefined value, depending on whether the call is known to produce * undefined. */ bool maybeUndefined = pushedTypeSet(0)->hasType(types::Type::UndefinedType()); Jump emptyGuard = masm.branch32(Assembler::Equal, lengthReg, Imm32(0)); if (!maybeUndefined) stubcc.linkExit(emptyGuard, Uses(3)); masm.bumpKey(key, -1); if (dataReg.isSet()) { Jump holeCheck; if (isArrayPop) { BaseIndex slot(slotsReg, lengthReg, masm.JSVAL_SCALE); holeCheck = masm.fastArrayLoadSlot(slot, !isPacked, typeReg, dataReg.reg()); } else { holeCheck = masm.fastArrayLoadSlot(Address(slotsReg), !isPacked, typeReg, dataReg.reg()); Address addr = frame.addressOf(frame.peek(-2)); if (typeReg.isSet()) masm.storeValueFromComponents(typeReg.reg(), dataReg.reg(), addr); else masm.storeValueFromComponents(ImmType(type), dataReg.reg(), addr); } if (!isPacked) stubcc.linkExit(holeCheck, Uses(3)); } masm.store32(lengthReg, Address(slotsReg, ObjectElements::offsetOfLength())); masm.store32(lengthReg, Address(slotsReg, ObjectElements::offsetOfInitializedLength())); if (!isArrayPop) INLINE_STUBCALL(stubs::ArrayShift, REJOIN_NONE); stubcc.leave(); stubcc.masm.move(Imm32(0), Registers::ArgReg1); OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH); frame.freeReg(slotsReg); frame.freeReg(lengthReg); frame.popn(2); if (dataReg.isSet()) { if (isArrayPop) { if (typeReg.isSet()) frame.pushRegs(typeReg.reg(), dataReg.reg(), type); else frame.pushTypedPayload(type, dataReg.reg()); } else { frame.pushSynced(type); if (typeReg.isSet()) frame.freeReg(typeReg.reg()); frame.freeReg(dataReg.reg()); } } else { frame.push(UndefinedValue()); } stubcc.rejoin(Changes(1)); if (maybeUndefined) { /* Generate an OOL path to push an undefined value, and rejoin. */ if (dataReg.isSet()) { stubcc.linkExitDirect(emptyGuard, stubcc.masm.label()); if (isArrayPop) { if (typeReg.isSet()) { stubcc.masm.loadValueAsComponents(UndefinedValue(), typeReg.reg(), dataReg.reg()); } else { JS_ASSERT(type == JSVAL_TYPE_UNDEFINED); stubcc.masm.loadValuePayload(UndefinedValue(), dataReg.reg()); } } else { stubcc.masm.storeValue(UndefinedValue(), frame.addressOf(frame.peek(-1))); } stubcc.crossJump(stubcc.masm.jump(), masm.label()); } else { emptyGuard.linkTo(masm.label(), &masm); } } return Compile_Okay; }
void AssemblyHelpers::jitAssertArgumentCountSane() { Jump ok = branch32(Below, payloadFor(JSStack::ArgumentCount), TrustedImm32(10000000)); abortWithReason(AHInsaneArgumentCount); ok.link(this); }
CompileStatus mjit::Compiler::compileParseInt(JSValueType argType, uint32_t argc) { bool needStubCall = false; if (argc > 1) { FrameEntry *arg = frame.peek(-(int32_t)argc + 1); if (!arg->isTypeKnown() || arg->getKnownType() != JSVAL_TYPE_INT32) return Compile_InlineAbort; if (arg->isConstant()) { int32_t base = arg->getValue().toInt32(); if (base != 0 && base != 10) return Compile_InlineAbort; } else { RegisterID baseReg = frame.tempRegForData(arg); needStubCall = true; Jump isTen = masm.branch32(Assembler::Equal, baseReg, Imm32(10)); Jump isNotZero = masm.branch32(Assembler::NotEqual, baseReg, Imm32(0)); stubcc.linkExit(isNotZero, Uses(2 + argc)); isTen.linkTo(masm.label(), &masm); } } if (argType == JSVAL_TYPE_INT32) { if (needStubCall) { stubcc.leave(); stubcc.masm.move(Imm32(argc), Registers::ArgReg1); OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH); } /* * Stack looks like callee, this, arg1, arg2, argN. * First pop all args other than arg1. */ frame.popn(argc - 1); /* "Shimmy" arg1 to the callee slot and pop this + arg1. */ frame.shimmy(2); if (needStubCall) { stubcc.rejoin(Changes(1)); } } else { FrameEntry *arg = frame.peek(-(int32_t)argc); FPRegisterID fpScratchReg = frame.allocFPReg(); FPRegisterID fpReg; bool allocate; DebugOnly<MaybeJump> notNumber = loadDouble(arg, &fpReg, &allocate); JS_ASSERT(!((MaybeJump)notNumber).isSet()); masm.slowLoadConstantDouble(1, fpScratchReg); /* Slow path for NaN and numbers < 1. */ Jump lessThanOneOrNan = masm.branchDouble(Assembler::DoubleLessThanOrUnordered, fpReg, fpScratchReg); stubcc.linkExit(lessThanOneOrNan, Uses(2 + argc)); frame.freeReg(fpScratchReg); /* Truncate to integer, slow path if this overflows. */ RegisterID reg = frame.allocReg(); Jump overflow = masm.branchTruncateDoubleToInt32(fpReg, reg); stubcc.linkExit(overflow, Uses(2 + argc)); if (allocate) frame.freeReg(fpReg); stubcc.leave(); stubcc.masm.move(Imm32(argc), Registers::ArgReg1); OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH); frame.popn(2 + argc); frame.pushTypedPayload(JSVAL_TYPE_INT32, reg); stubcc.rejoin(Changes(1)); } return Compile_Okay; }
Palette* MuseScore::newRepeatsPalette() { Palette* sp = new Palette; sp->setName(QT_TRANSLATE_NOOP("Palette", "Repeats")); sp->setMag(0.65); sp->setGrid(84, 28); sp->setDrawGrid(true); RepeatMeasure* rm = new RepeatMeasure(gscore); sp->append(rm, tr("Repeat measure sign")); Marker* mk = new Marker(gscore); mk->setMarkerType(Marker::Type::SEGNO); sp->append(mk, tr("Segno")); mk = new Marker(gscore); mk->setMarkerType(Marker::Type::VARSEGNO); sp->append(mk, tr("Segno Variation")); mk = new Marker(gscore); mk->setMarkerType(Marker::Type::CODA); sp->append(mk, tr("Coda")); mk = new Marker(gscore); mk->setMarkerType(Marker::Type::VARCODA); sp->append(mk, tr("Varied coda")); /* mk = new Marker(gscore); // not in smufl mk->setMarkerType(Marker::Type::CODETTA); sp->append(mk, tr("Codetta")); */ mk = new Marker(gscore); mk->setMarkerType(Marker::Type::FINE); sp->append(mk, tr("Fine")); Jump* jp = new Jump(gscore); jp->setJumpType(Jump::Type::DC); sp->append(jp, tr("Da Capo")); jp = new Jump(gscore); jp->setJumpType(Jump::Type::DC_AL_FINE); sp->append(jp, tr("Da Capo al Fine")); jp = new Jump(gscore); jp->setJumpType(Jump::Type::DC_AL_CODA); sp->append(jp, tr("Da Capo al Coda")); jp = new Jump(gscore); jp->setJumpType(Jump::Type::DS_AL_CODA); sp->append(jp, tr("D.S. al Coda")); jp = new Jump(gscore); jp->setJumpType(Jump::Type::DS_AL_FINE); sp->append(jp, tr("D.S. al Fine")); jp = new Jump(gscore); jp->setJumpType(Jump::Type::DS); sp->append(jp, tr("D.S.")); mk = new Marker(gscore); mk->setMarkerType(Marker::Type::TOCODA); sp->append(mk, tr("To Coda")); return sp; }
static MacroAssemblerCodeRef arrayIteratorNextThunkGenerator(VM* vm, ArrayIterationKind kind) { typedef SpecializedThunkJIT::TrustedImm32 TrustedImm32; typedef SpecializedThunkJIT::TrustedImmPtr TrustedImmPtr; typedef SpecializedThunkJIT::Address Address; typedef SpecializedThunkJIT::BaseIndex BaseIndex; typedef SpecializedThunkJIT::Jump Jump; SpecializedThunkJIT jit(vm); // Make sure we're being called on an array iterator, and load m_iteratedObject, and m_nextIndex into regT0 and regT1 respectively jit.loadArgumentWithSpecificClass(JSArrayIterator::info(), SpecializedThunkJIT::ThisArgument, SpecializedThunkJIT::regT4, SpecializedThunkJIT::regT1); // Early exit if we don't have a thunk for this form of iteration jit.appendFailure(jit.branch32(SpecializedThunkJIT::AboveOrEqual, Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfIterationKind()), TrustedImm32(ArrayIterateKeyValue))); jit.loadPtr(Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfIteratedObject()), SpecializedThunkJIT::regT0); jit.load32(Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex()), SpecializedThunkJIT::regT1); // Pull out the butterfly from iteratedObject jit.load8(Address(SpecializedThunkJIT::regT0, JSCell::indexingTypeOffset()), SpecializedThunkJIT::regT3); jit.loadPtr(Address(SpecializedThunkJIT::regT0, JSObject::butterflyOffset()), SpecializedThunkJIT::regT2); jit.and32(TrustedImm32(IndexingShapeMask), SpecializedThunkJIT::regT3); Jump notDone = jit.branch32(SpecializedThunkJIT::Below, SpecializedThunkJIT::regT1, Address(SpecializedThunkJIT::regT2, Butterfly::offsetOfPublicLength())); // Return the termination signal to indicate that we've finished jit.move(TrustedImmPtr(vm->iterationTerminator.get()), SpecializedThunkJIT::regT0); jit.returnJSCell(SpecializedThunkJIT::regT0); notDone.link(&jit); if (kind == ArrayIterateKey) { jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex())); jit.returnInt32(SpecializedThunkJIT::regT1); return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "array-iterator-next-key"); } ASSERT(kind == ArrayIterateValue); // Okay, now we're returning a value so make sure we're inside the vector size jit.appendFailure(jit.branch32(SpecializedThunkJIT::AboveOrEqual, SpecializedThunkJIT::regT1, Address(SpecializedThunkJIT::regT2, Butterfly::offsetOfVectorLength()))); // So now we perform inline loads for int32, value/undecided, and double storage Jump undecidedStorage = jit.branch32(SpecializedThunkJIT::Equal, SpecializedThunkJIT::regT3, TrustedImm32(UndecidedShape)); Jump notContiguousStorage = jit.branch32(SpecializedThunkJIT::NotEqual, SpecializedThunkJIT::regT3, TrustedImm32(ContiguousShape)); undecidedStorage.link(&jit); jit.loadPtr(Address(SpecializedThunkJIT::regT0, JSObject::butterflyOffset()), SpecializedThunkJIT::regT2); #if USE(JSVALUE64) jit.load64(BaseIndex(SpecializedThunkJIT::regT2, SpecializedThunkJIT::regT1, SpecializedThunkJIT::TimesEight), SpecializedThunkJIT::regT0); Jump notHole = jit.branchTest64(SpecializedThunkJIT::NonZero, SpecializedThunkJIT::regT0); jit.move(JSInterfaceJIT::TrustedImm64(ValueUndefined), JSInterfaceJIT::regT0); notHole.link(&jit); jit.addPtr(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex())); jit.returnJSValue(SpecializedThunkJIT::regT0); #else jit.load32(BaseIndex(SpecializedThunkJIT::regT2, SpecializedThunkJIT::regT1, SpecializedThunkJIT::TimesEight, JSValue::offsetOfTag()), SpecializedThunkJIT::regT3); Jump notHole = jit.branch32(SpecializedThunkJIT::NotEqual, SpecializedThunkJIT::regT3, TrustedImm32(JSValue::EmptyValueTag)); jit.move(JSInterfaceJIT::TrustedImm32(JSValue::UndefinedTag), JSInterfaceJIT::regT1); jit.move(JSInterfaceJIT::TrustedImm32(0), JSInterfaceJIT::regT0); jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex())); jit.returnJSValue(SpecializedThunkJIT::regT0, JSInterfaceJIT::regT1); notHole.link(&jit); jit.load32(BaseIndex(SpecializedThunkJIT::regT2, SpecializedThunkJIT::regT1, SpecializedThunkJIT::TimesEight, JSValue::offsetOfPayload()), SpecializedThunkJIT::regT0); jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex())); jit.move(SpecializedThunkJIT::regT3, SpecializedThunkJIT::regT1); jit.returnJSValue(SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1); #endif notContiguousStorage.link(&jit); Jump notInt32Storage = jit.branch32(SpecializedThunkJIT::NotEqual, SpecializedThunkJIT::regT3, TrustedImm32(Int32Shape)); jit.loadPtr(Address(SpecializedThunkJIT::regT0, JSObject::butterflyOffset()), SpecializedThunkJIT::regT2); jit.load32(BaseIndex(SpecializedThunkJIT::regT2, SpecializedThunkJIT::regT1, SpecializedThunkJIT::TimesEight, JSValue::offsetOfPayload()), SpecializedThunkJIT::regT0); jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex())); jit.returnInt32(SpecializedThunkJIT::regT0); notInt32Storage.link(&jit); jit.appendFailure(jit.branch32(SpecializedThunkJIT::NotEqual, SpecializedThunkJIT::regT3, TrustedImm32(DoubleShape))); jit.loadPtr(Address(SpecializedThunkJIT::regT0, JSObject::butterflyOffset()), SpecializedThunkJIT::regT2); jit.loadDouble(BaseIndex(SpecializedThunkJIT::regT2, SpecializedThunkJIT::regT1, SpecializedThunkJIT::TimesEight), SpecializedThunkJIT::fpRegT0); jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex())); jit.returnDouble(SpecializedThunkJIT::fpRegT0); return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "array-iterator-next-value"); }