void Initialize() { if (base::win::get_version() < base::win::VERSION_WIN7) { return ; } const wchar_t* currentAppID = 0; HRESULT hr = windows7::GetCurrentProcessExplicitAppUserModelID((wchar_t**)¤tAppID); if (FAILED(hr) || !currentAppID) { currentAppID = getCurrentAppID(); windows7::SetCurrentProcessExplicitAppUserModelID(currentAppID); } JumpList jumpList; jumpList.SetAppID(currentAppID); if (jumpList.InitializeList()) { fs::path ydweDirectory = base::path::get(base::path::DIR_MODULE).remove_filename().remove_filename(); jumpList.AddTaskSeparator(); jumpList.AddTask(L"YDWEÅäÖÃ", [&](CComPtr<IShellLinkW>& shellLinkPtr) { shellLinkPtr->SetPath((ydweDirectory / L"bin" / L"YDWEConfig.exe").c_str()); shellLinkPtr->SetDescription(L"´ò¿ªYDWEÅäÖóÌÐò¡£"); shellLinkPtr->SetIconLocation((ydweDirectory / L"bin" / L"logo.ico").c_str(), 0); }); } }
void Generator::terminateAlternative(JumpList& successes, JumpList& failures) { successes.append(jump()); failures.link(this); peek(index); }
void JIT::compileLoadVarargs(Instruction* instruction) { int thisValue = instruction[2].u.operand; int arguments = instruction[3].u.operand; int firstFreeRegister = instruction[4].u.operand; killLastResultRegister(); JumpList slowCase; JumpList end; if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister()) { emitGetVirtualRegister(arguments, regT0); slowCase.append(branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(JSValue())))); emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); slowCase.append(branch32(Above, regT0, TrustedImm32(Arguments::MaxArguments + 1))); // regT0: argumentCountIncludingThis move(regT0, regT1); add32(TrustedImm32(firstFreeRegister + RegisterFile::CallFrameHeaderSize), regT1); lshift32(TrustedImm32(3), regT1); addPtr(callFrameRegister, regT1); // regT1: newCallFrame slowCase.append(branchPtr(Below, AbsoluteAddress(m_globalData->interpreter->registerFile().addressOfEnd()), regT1)); // Initialize ArgumentCount. emitFastArithReTagImmediate(regT0, regT2); storePtr(regT2, Address(regT1, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register)))); // Initialize 'this'. emitGetVirtualRegister(thisValue, regT2); storePtr(regT2, Address(regT1, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register)))); // Copy arguments. neg32(regT0); signExtend32ToPtr(regT0, regT0); end.append(branchAddPtr(Zero, Imm32(1), regT0)); // regT0: -argumentCount Label copyLoop = label(); loadPtr(BaseIndex(callFrameRegister, regT0, TimesEight, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))), regT2); storePtr(regT2, BaseIndex(regT1, regT0, TimesEight, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register)))); branchAddPtr(NonZero, Imm32(1), regT0).linkTo(copyLoop, this); end.append(jump()); } if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister()) slowCase.link(this); JITStubCall stubCall(this, cti_op_load_varargs); stubCall.addArgument(thisValue, regT0); stubCall.addArgument(arguments, regT0); stubCall.addArgument(Imm32(firstFreeRegister)); stubCall.call(regT1); if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister()) end.link(this); }
void JIT::compileLoadVarargs(Instruction* instruction) { int thisValue = instruction[3].u.operand; int arguments = instruction[4].u.operand; int firstFreeRegister = instruction[5].u.operand; JumpList slowCase; JumpList end; bool canOptimize = m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister().offset() && !m_codeBlock->symbolTable()->slowArguments(); if (canOptimize) { emitGetVirtualRegister(arguments, regT0); slowCase.append(branch64(NotEqual, regT0, TrustedImm64(JSValue::encode(JSValue())))); emitGetFromCallFrameHeader32(JSStack::ArgumentCount, regT0); slowCase.append(branch32(Above, regT0, TrustedImm32(Arguments::MaxArguments + 1))); // regT0: argumentCountIncludingThis move(regT0, regT1); neg64(regT1); add64(TrustedImm32(firstFreeRegister - JSStack::CallFrameHeaderSize), regT1); lshift64(TrustedImm32(3), regT1); addPtr(callFrameRegister, regT1); // regT1: newCallFrame slowCase.append(branchPtr(Above, AbsoluteAddress(m_vm->addressOfJSStackLimit()), regT1)); // Initialize ArgumentCount. store32(regT0, Address(regT1, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))); // Initialize 'this'. emitGetVirtualRegister(thisValue, regT2); store64(regT2, Address(regT1, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register)))); // Copy arguments. signExtend32ToPtr(regT0, regT0); end.append(branchSub64(Zero, TrustedImm32(1), regT0)); // regT0: argumentCount Label copyLoop = label(); load64(BaseIndex(callFrameRegister, regT0, TimesEight, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))), regT2); store64(regT2, BaseIndex(regT1, regT0, TimesEight, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register)))); branchSub64(NonZero, TrustedImm32(1), regT0).linkTo(copyLoop, this); end.append(jump()); } if (canOptimize) slowCase.link(this); emitGetVirtualRegister(thisValue, regT0); emitGetVirtualRegister(arguments, regT1); callOperation(operationLoadVarargs, regT0, regT1, firstFreeRegister); move(returnValueGPR, regT1); if (canOptimize) end.link(this); }
void JIT::compileLoadVarargs(Instruction* instruction) { int thisValue = instruction[2].u.operand; int arguments = instruction[3].u.operand; int firstFreeRegister = instruction[4].u.operand; JumpList slowCase; JumpList end; if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister()) { emitLoadTag(arguments, regT1); slowCase.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::EmptyValueTag))); load32(payloadFor(RegisterFile::ArgumentCount), regT2); slowCase.append(branch32(Above, regT2, TrustedImm32(Arguments::MaxArguments + 1))); // regT2: argumentCountIncludingThis move(regT2, regT3); add32(TrustedImm32(firstFreeRegister + RegisterFile::CallFrameHeaderSize), regT3); lshift32(TrustedImm32(3), regT3); addPtr(callFrameRegister, regT3); // regT3: newCallFrame slowCase.append(branchPtr(Below, AbsoluteAddress(m_globalData->interpreter->registerFile().addressOfEnd()), regT3)); // Initialize ArgumentCount. store32(regT2, payloadFor(RegisterFile::ArgumentCount, regT3)); // Initialize 'this'. emitLoad(thisValue, regT1, regT0); store32(regT0, Address(regT3, OBJECT_OFFSETOF(JSValue, u.asBits.payload) + (CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))))); store32(regT1, Address(regT3, OBJECT_OFFSETOF(JSValue, u.asBits.tag) + (CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))))); // Copy arguments. neg32(regT2); end.append(branchAdd32(Zero, TrustedImm32(1), regT2)); // regT2: -argumentCount; Label copyLoop = label(); load32(BaseIndex(callFrameRegister, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload) +(CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register)))), regT0); load32(BaseIndex(callFrameRegister, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag) +(CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register)))), regT1); store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload) +(CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))))); store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag) +(CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))))); branchAdd32(NonZero, TrustedImm32(1), regT2).linkTo(copyLoop, this); end.append(jump()); } if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister()) slowCase.link(this); JITStubCall stubCall(this, cti_op_load_varargs); stubCall.addArgument(thisValue); stubCall.addArgument(arguments); stubCall.addArgument(Imm32(firstFreeRegister)); stubCall.call(regT3); if (m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister()) end.link(this); }
void Generator::generateAssertionEOL(JumpList& failures) { if (m_parser.multiline()) { JumpList nextIsNewline; generateLoadCharacter(nextIsNewline); // end of input == success generateCharacterClassInverted(nextIsNewline, CharacterClass::newline()); failures.append(jump()); nextIsNewline.link(this); } else { failures.append(jne32(length, index)); } }
void Generator::generateParenthesesInvertedAssertion(JumpList& failures) { JumpList disjunctionFailed; push(index); m_parser.parseDisjunction(disjunctionFailed); // If the disjunction succeeded, the inverted assertion failed. pop(index); failures.append(jump()); // If the disjunction failed, the inverted assertion succeeded. disjunctionFailed.link(this); pop(index); }
void Generator::generateParenthesesAssertion(JumpList& failures) { JumpList disjunctionFailed; push(index); m_parser.parseDisjunction(disjunctionFailed); Jump success = jump(); disjunctionFailed.link(this); pop(index); failures.append(jump()); success.link(this); pop(index); }
void Generator::generateCharacterClass(JumpList& failures, const CharacterClass& charClass, bool invert) { generateLoadCharacter(failures); if (invert) generateCharacterClassInverted(failures, charClass); else { JumpList successes; generateCharacterClassInverted(successes, charClass); failures.append(jump()); successes.link(this); } add32(Imm32(1), index); }
void Generator::generateAssertionWordBoundary(JumpList& failures, bool invert) { JumpList wordBoundary; JumpList notWordBoundary; // (1) Check if the previous value was a word char // (1.1) check for begin of input Jump atBegin = je32(index, Imm32(0)); // (1.2) load the last char, and chck if is word character load16(BaseIndex(input, index, TimesTwo, -2), character); JumpList previousIsWord; generateCharacterClassInverted(previousIsWord, CharacterClass::wordchar()); // (1.3) if we get here, previous is not a word char atBegin.link(this); // (2) Handle situation where previous was NOT a \w generateLoadCharacter(notWordBoundary); generateCharacterClassInverted(wordBoundary, CharacterClass::wordchar()); // (2.1) If we get here, neither chars are word chars notWordBoundary.append(jump()); // (3) Handle situation where previous was a \w // (3.0) link success in first match to here previousIsWord.link(this); generateLoadCharacter(wordBoundary); generateCharacterClassInverted(notWordBoundary, CharacterClass::wordchar()); // (3.1) If we get here, this is an end of a word, within the input. // (4) Link everything up if (invert) { // handle the fall through case wordBoundary.append(jump()); // looking for non word boundaries, so link boundary fails to here. notWordBoundary.link(this); failures.append(wordBoundary); } else { // looking for word boundaries, so link successes here. wordBoundary.link(this); failures.append(notWordBoundary); } }
// // FUNCTION: InitMainWindowInstance(HINSTANCE, int) // // PURPOSE: Saves instance handle and creates main window // // COMMENTS: // // In this function, we save the instance handle in a global variable and // create and display the main program window. // HWND InitMainWindowInstance( HINSTANCE hInstance, int nCmdShow, PTCHAR szWindowClass, PTCHAR szTitle) { hInst = hInstance; // Store instance handle in our global variable beginMainWindowCreationTime.Now(); // Should make window size be data driven mainWindowHandle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW | WS_EX_CLIENTEDGE, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, // WS_POPUP, CW_USEDEFAULT, 0, DEFAULT_WIN_WIDTH, DEFAULT_WIN_HEIGHT, NULL, NULL, hInstance, NULL); if (mainWindowHandle) { if (!devMode) { jumpList.SetUpJumpList(hInst); } } return mainWindowHandle; }
void Generator::generatePatternCharacter(JumpList& failures, int ch) { generateLoadCharacter(failures); // used for unicode case insensitive bool hasUpper = false; Jump isUpper; // if case insensitive match if (m_parser.ignoreCase()) { UChar lower, upper; // check for ascii case sensitive characters if (isASCIIAlpha(ch)) { or32(Imm32(32), character); ch |= 32; } else if (!isASCII(ch) && ((lower = Unicode::toLower(ch)) != (upper = Unicode::toUpper(ch)))) { // handle unicode case sentitive characters - branch to success on upper isUpper = je32(character, Imm32(upper)); hasUpper = true; ch = lower; } } // checks for ch, or lower case version of ch, if insensitive failures.append(jne32(character, Imm32((unsigned short)ch))); if (m_parser.ignoreCase() && hasUpper) { // for unicode case insensitive matches, branch here if upper matches. isUpper.link(this); } // on success consume the char add32(Imm32(1), index); }
void Generator::generateCharacterClassInvertedRange(JumpList& failures, JumpList& matchDest, const CharacterRange* ranges, unsigned count, unsigned* matchIndex, const UChar* matches, unsigned matchCount) { do { // pick which range we're going to generate int which = count >> 1; char lo = ranges[which].begin; char hi = ranges[which].end; // check if there are any ranges or matches below lo. If not, just jl to failure - // if there is anything else to check, check that first, if it falls through jmp to failure. if ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)) { Jump loOrAbove = jge32(character, Imm32((unsigned short)lo)); // generate code for all ranges before this one if (which) generateCharacterClassInvertedRange(failures, matchDest, ranges, which, matchIndex, matches, matchCount); do { matchDest.append(je32(character, Imm32((unsigned short)matches[*matchIndex]))); ++*matchIndex; } while ((*matchIndex < matchCount) && (matches[*matchIndex] < lo)); failures.append(jump()); loOrAbove.link(this); } else if (which) { Jump loOrAbove = jge32(character, Imm32((unsigned short)lo)); generateCharacterClassInvertedRange(failures, matchDest, ranges, which, matchIndex, matches, matchCount); failures.append(jump()); loOrAbove.link(this); } else failures.append(jl32(character, Imm32((unsigned short)lo))); while ((*matchIndex < matchCount) && (matches[*matchIndex] <= hi)) ++*matchIndex; matchDest.append(jle32(character, Imm32((unsigned short)hi))); // fall through to here, the value is above hi. // shuffle along & loop around if there are any more matches to handle. unsigned next = which + 1; ranges += next; count -= next; } while (count); }
bool Generator::generatePatternCharacterPair(JumpList& failures, int ch1, int ch2) { if (m_parser.ignoreCase()) { // Non-trivial case folding requires more than one test, so we can't // test as a pair with an adjacent character. if (!isASCII(ch1) && Unicode::toLower(ch1) != Unicode::toUpper(ch1)) return false; if (!isASCII(ch2) && Unicode::toLower(ch2) != Unicode::toUpper(ch2)) return false; } // Optimistically consume 2 characters. add32(Imm32(2), index); failures.append(jg32(index, length)); // Load the characters we just consumed, offset -2 characters from index. load32(BaseIndex(input, index, TimesTwo, -2 * 2), character); if (m_parser.ignoreCase()) { // Convert ASCII alphabet characters to upper case before testing for // equality. (ASCII non-alphabet characters don't require upper-casing // because they have no uppercase equivalents. Unicode characters don't // require upper-casing because we only handle Unicode characters whose // upper and lower cases are equal.) int ch1Mask = 0; if (isASCIIAlpha(ch1)) { ch1 |= 32; ch1Mask = 32; } int ch2Mask = 0; if (isASCIIAlpha(ch2)) { ch2 |= 32; ch2Mask = 32; } int mask = ch1Mask | (ch2Mask << 16); if (mask) or32(Imm32(mask), character); } int pair = ch1 | (ch2 << 16); failures.append(jne32(character, Imm32(pair))); return true; }
void JIT::privateCompileClosureCall(CallLinkInfo* callLinkInfo, CodeBlock* calleeCodeBlock, Structure* expectedStructure, ExecutableBase* expectedExecutable, MacroAssemblerCodePtr codePtr) { JumpList slowCases; slowCases.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag))); slowCases.append(branchPtr(NotEqual, Address(regT0, JSCell::structureOffset()), TrustedImmPtr(expectedStructure))); slowCases.append(branchPtr(NotEqual, Address(regT0, JSFunction::offsetOfExecutable()), TrustedImmPtr(expectedExecutable))); loadPtr(Address(regT0, JSFunction::offsetOfScopeChain()), regT1); emitPutCellToCallFrameHeader(regT1, JSStack::ScopeChain); Call call = nearCall(); Jump done = jump(); slowCases.link(this); move(TrustedImmPtr(callLinkInfo->callReturnLocation.executableAddress()), regT2); restoreReturnAddressBeforeReturn(regT2); Jump slow = jump(); LinkBuffer patchBuffer(*m_vm, this, m_codeBlock); patchBuffer.link(call, FunctionPtr(codePtr.executableAddress())); patchBuffer.link(done, callLinkInfo->hotPathOther.labelAtOffset(0)); patchBuffer.link(slow, CodeLocationLabel(m_vm->getCTIStub(virtualCallThunkGenerator).code())); RefPtr<ClosureCallStubRoutine> stubRoutine = adoptRef(new ClosureCallStubRoutine( FINALIZE_CODE( patchBuffer, ("Baseline closure call stub for %s, return point %p, target %p (%s)", toCString(*m_codeBlock).data(), callLinkInfo->hotPathOther.labelAtOffset(0).executableAddress(), codePtr.executableAddress(), toCString(pointerDump(calleeCodeBlock)).data())), *m_vm, m_codeBlock->ownerExecutable(), expectedStructure, expectedExecutable, callLinkInfo->codeOrigin)); RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.replaceWithJump( RepatchBuffer::startOfBranchPtrWithPatchOnRegister(callLinkInfo->hotPathBegin), CodeLocationLabel(stubRoutine->code().code())); repatchBuffer.relink(callLinkInfo->callReturnLocation, m_vm->getCTIStub(virtualCallThunkGenerator).code()); callLinkInfo->stub = stubRoutine.release(); }
void Generator::generateAssertionBOL(JumpList& failures) { if (m_parser.multiline()) { JumpList previousIsNewline; // begin of input == success previousIsNewline.append(je32(index, Imm32(0))); // now check prev char against newline characters. load16(BaseIndex(input, index, TimesTwo, -2), character); generateCharacterClassInverted(previousIsNewline, CharacterClass::newline()); failures.append(jump()); previousIsNewline.link(this); } else failures.append(jne32(index, Imm32(0))); }
void Generator::generateNonGreedyQuantifier(JumpList& failures, GenerateAtomFunctor& functor, unsigned min, unsigned max) { JumpList atomFailedList; JumpList alternativeFailedList; // (0) Setup: Save, then init repeatCount. push(repeatCount); move(Imm32(0), repeatCount); Jump start = jump(); // (4) Quantifier failed: No more atom reading possible. Label quantifierFailed(this); pop(repeatCount); failures.append(jump()); // (3) Alternative failed: If we can, read another atom, then fall through to (2) to try again. Label alternativeFailed(this); pop(index); if (max != Quantifier::Infinity) je32(repeatCount, Imm32(max), quantifierFailed); // (1) Read an atom. if (min) start.link(this); Label readAtom(this); functor.generateAtom(this, atomFailedList); atomFailedList.linkTo(quantifierFailed, this); add32(Imm32(1), repeatCount); // (2) Keep reading if we're under the minimum. if (min > 1) jl32(repeatCount, Imm32(min), readAtom); // (3) Test the rest of the alternative. if (!min) start.link(this); push(index); m_parser.parseAlternative(alternativeFailedList); alternativeFailedList.linkTo(alternativeFailed, this); pop(); pop(repeatCount); }
bool JumpListAddRecentTask(JumpList& jumpList, fs::path const& ydweDirectory, fs::path const& filePath) { HRESULT hr = jumpList.AddTask(filePath.filename().c_str(), [&](CComPtr<IShellLinkW>& shellLinkPtr) { shellLinkPtr->SetPath((ydweDirectory / L"YDWE.exe").c_str()); shellLinkPtr->SetArguments((L" -loadfile \"" + filePath.wstring() + L"\"").c_str()); shellLinkPtr->SetDescription(filePath.c_str()); shellLinkPtr->SetIconLocation((ydweDirectory / L"bin" / L"logo.ico").c_str(), 0); }); return SUCCEEDED(hr); }
Generator::Jump Generator::generateParenthesesResetTrampoline(JumpList& newFailures, unsigned subpatternIdBefore, unsigned subpatternIdAfter) { Jump skip = jump(); newFailures.link(this); for (unsigned i = subpatternIdBefore + 1; i <= subpatternIdAfter; ++i) { store32(Imm32(-1), Address(output, (2 * i) * sizeof(int))); store32(Imm32(-1), Address(output, (2 * i + 1) * sizeof(int))); } Jump newFailJump = jump(); skip.link(this); return newFailJump; }
void Generator::generateGreedyQuantifier(JumpList& failures, GenerateAtomFunctor& functor, unsigned min, unsigned max) { if (!max) return; JumpList doneReadingAtomsList; JumpList alternativeFailedList; // (0) Setup: Save, then init repeatCount. push(repeatCount); move(Imm32(0), repeatCount); // (1) Greedily read as many copies of the atom as possible, then jump to (2). Label readAtom(this); functor.generateAtom(this, doneReadingAtomsList); add32(Imm32(1), repeatCount); if (max == Quantifier::Infinity) jump(readAtom); else if (max == 1) doneReadingAtomsList.append(jump()); else { jne32(repeatCount, Imm32(max), readAtom); doneReadingAtomsList.append(jump()); } // (5) Quantifier failed: No more backtracking possible. Label quantifierFailed(this); pop(repeatCount); failures.append(jump()); // (4) Alternative failed: Backtrack, then fall through to (2) to try again. Label alternativeFailed(this); pop(index); functor.backtrack(this); sub32(Imm32(1), repeatCount); // (2) Verify that we have enough atoms. doneReadingAtomsList.link(this); jl32(repeatCount, Imm32(min), quantifierFailed); // (3) Test the rest of the alternative. push(index); m_parser.parseAlternative(alternativeFailedList); alternativeFailedList.linkTo(alternativeFailed, this); pop(); pop(repeatCount); }
void JIT::compileSetupVarargsFrame(Instruction* instruction, CallLinkInfo* info) { int thisValue = instruction[3].u.operand; int arguments = instruction[4].u.operand; int firstFreeRegister = instruction[5].u.operand; int firstVarArgOffset = instruction[6].u.operand; JumpList slowCase; JumpList end; bool canOptimize = m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister().offset() && !m_codeBlock->symbolTable()->slowArguments(); if (canOptimize) { emitGetVirtualRegister(arguments, regT0); slowCase.append(branch64(NotEqual, regT0, TrustedImm64(JSValue::encode(JSValue())))); move(TrustedImm32(-firstFreeRegister), regT1); emitSetupVarargsFrameFastCase(*this, regT1, regT0, regT1, regT2, firstVarArgOffset, slowCase); end.append(jump()); slowCase.link(this); } emitGetVirtualRegister(arguments, regT1); callOperation(operationSizeFrameForVarargs, regT1, -firstFreeRegister, firstVarArgOffset); move(TrustedImm32(-firstFreeRegister), regT1); emitSetVarargsFrame(*this, returnValueGPR, false, regT1, regT1); addPtr(TrustedImm32(-(sizeof(CallerFrameAndPC) + WTF::roundUpToMultipleOf(stackAlignmentBytes(), 5 * sizeof(void*)))), regT1, stackPointerRegister); emitGetVirtualRegister(arguments, regT2); callOperation(operationSetupVarargsFrame, regT1, regT2, firstVarArgOffset, regT0); move(returnValueGPR, regT1); if (canOptimize) end.link(this); // Profile the argument count. load32(Address(regT1, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset), regT2); load8(&info->maxNumArguments, regT0); Jump notBiggest = branch32(Above, regT0, regT2); Jump notSaturated = branch32(BelowOrEqual, regT2, TrustedImm32(255)); move(TrustedImm32(255), regT2); notSaturated.link(this); store8(regT2, &info->maxNumArguments); notBiggest.link(this); // Initialize 'this'. emitGetVirtualRegister(thisValue, regT0); store64(regT0, Address(regT1, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register)))); addPtr(TrustedImm32(sizeof(CallerFrameAndPC)), regT1, stackPointerRegister); }
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(); }
void Generator::generateLoadCharacter(JumpList& failures) { failures.append(je32(length, index)); load16(BaseIndex(input, index, TimesTwo), character); }
void Generator::generateCharacterClassInverted(JumpList& matchDest, const CharacterClass& charClass) { Jump unicodeFail; if (charClass.numMatchesUnicode || charClass.numRangesUnicode) { Jump isAscii = jle32(character, Imm32(0x7f)); if (charClass.numMatchesUnicode) { for (unsigned i = 0; i < charClass.numMatchesUnicode; ++i) { UChar ch = charClass.matchesUnicode[i]; matchDest.append(je32(character, Imm32(ch))); } } if (charClass.numRangesUnicode) { for (unsigned i = 0; i < charClass.numRangesUnicode; ++i) { UChar lo = charClass.rangesUnicode[i].begin; UChar hi = charClass.rangesUnicode[i].end; Jump below = jl32(character, Imm32(lo)); matchDest.append(jle32(character, Imm32(hi))); below.link(this); } } unicodeFail = jump(); isAscii.link(this); } if (charClass.numRanges) { unsigned matchIndex = 0; JumpList failures; generateCharacterClassInvertedRange(failures, matchDest, charClass.ranges, charClass.numRanges, &matchIndex, charClass.matches, charClass.numMatches); while (matchIndex < charClass.numMatches) matchDest.append(je32(character, Imm32((unsigned short)charClass.matches[matchIndex++]))); failures.link(this); } else if (charClass.numMatches) { // optimization: gather 'a','A' etc back together, can mask & test once. Vector<char> matchesAZaz; for (unsigned i = 0; i < charClass.numMatches; ++i) { char ch = charClass.matches[i]; if (m_parser.ignoreCase()) { if (isASCIILower(ch)) { matchesAZaz.append(ch); continue; } if (isASCIIUpper(ch)) continue; } matchDest.append(je32(character, Imm32((unsigned short)ch))); } if (unsigned countAZaz = matchesAZaz.size()) { or32(Imm32(32), character); for (unsigned i = 0; i < countAZaz; ++i) matchDest.append(je32(character, Imm32(matchesAZaz[i]))); } } if (charClass.numMatchesUnicode || charClass.numRangesUnicode) unicodeFail.link(this); }
void JIT::compileLoadVarargs(Instruction* instruction) { int thisValue = instruction[3].u.operand; int arguments = instruction[4].u.operand; int firstFreeRegister = instruction[5].u.operand; JumpList slowCase; JumpList end; bool canOptimize = m_codeBlock->usesArguments() && VirtualRegister(arguments) == m_codeBlock->argumentsRegister() && !m_codeBlock->symbolTable()->slowArguments(); if (canOptimize) { emitLoadTag(arguments, regT1); slowCase.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::EmptyValueTag))); load32(payloadFor(JSStack::ArgumentCount), regT2); slowCase.append(branch32(Above, regT2, TrustedImm32(Arguments::MaxArguments + 1))); // regT2: argumentCountIncludingThis move(regT2, regT3); neg32(regT3); add32(TrustedImm32(firstFreeRegister - JSStack::CallFrameHeaderSize), regT3); lshift32(TrustedImm32(3), regT3); addPtr(callFrameRegister, regT3); // regT3: newCallFrame slowCase.append(branchPtr(Above, AbsoluteAddress(m_vm->interpreter->stack().addressOfEnd()), regT3)); // Initialize ArgumentCount. store32(regT2, payloadFor(JSStack::ArgumentCount, regT3)); // Initialize 'this'. emitLoad(thisValue, regT1, regT0); store32(regT0, Address(regT3, OBJECT_OFFSETOF(JSValue, u.asBits.payload) + (CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))))); store32(regT1, Address(regT3, OBJECT_OFFSETOF(JSValue, u.asBits.tag) + (CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))))); // Copy arguments. end.append(branchSub32(Zero, TrustedImm32(1), regT2)); // regT2: argumentCount; Label copyLoop = label(); load32(BaseIndex(callFrameRegister, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload) +(CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register)))), regT0); load32(BaseIndex(callFrameRegister, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag) +(CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register)))), regT1); store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload) +(CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))))); store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag) +(CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))))); branchSub32(NonZero, TrustedImm32(1), regT2).linkTo(copyLoop, this); end.append(jump()); } if (canOptimize) slowCase.link(this); emitLoad(thisValue, regT1, regT0); emitLoad(arguments, regT3, regT2); callOperation(operationLoadVarargs, regT1, regT0, regT3, regT2, firstFreeRegister); move(returnValueRegister, regT3); if (canOptimize) end.link(this); }
// // FUNCTION: MainWindowWndProc(HWND, UINT, WPARAM, LPARAM) // // PURPOSE: Processes messages for the main window. // LRESULT CALLBACK MainWindowWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; HMENU sysMenu; // Callback for the main window switch (message) { case WM_CREATE: { DWORD bufferSize = 65535; wstring buff; buff.resize(bufferSize); bufferSize = ::GetEnvironmentVariable(L"lala", &buff[0], bufferSize); if (bufferSize) { buff.resize(bufferSize); SetEnvironmentVariable(L"lala", NULL); } // Add exit option to system menu TCHAR szDescription[INFOTIPSIZE]; StringManager.LoadString(IDS_EXIT_CAFFEINE, szDescription, INFOTIPSIZE); sysMenu = GetSystemMenu(hWnd, FALSE); InsertMenu(sysMenu, 2, MF_SEPARATOR, 0, L"-"); AppendMenu(sysMenu, MF_STRING, IDS_EXIT_CAFFEINE, szDescription); WTSRegisterSessionNotification(hWnd, NOTIFY_FOR_THIS_SESSION); app->m_WindowHandler[mainUUID] = new CaffeineClientHandler(); app->m_WindowHandler[mainUUID]->SetMainHwnd(hWnd); // Create the child windows used for navigation RECT rect; GetClientRect(hWnd, &rect); CefWindowInfo info; CefBrowserSettings browser_settings; browser_settings.universal_access_from_file_urls = STATE_ENABLED; // browser_settings.file_access_from_file_urls = STATE_ENABLED; browser_settings.web_security = STATE_DISABLED; browser_settings.local_storage = STATE_ENABLED; browser_settings.application_cache = STATE_DISABLED; browser_settings.javascript_open_windows = STATE_DISABLED; // browser_settings.accelerated_compositing = STATE_DISABLED; // Initialize window info to the defaults for a child window info.SetAsChild(hWnd, rect); // Create the new child browser window wstring URL(L"file:///stub.html?" + AppGetCommandLine()->GetSwitchValue("querystring").ToWString()); if (AppGetCommandLine()->HasSwitch("yid")) { URL += L"&yid=" + ExtractYID(AppGetCommandLine()->GetSwitchValue("yid").ToWString()); } // TODO: Can we just use the same window handler (assuming we get rid of the globals and add some sync)? CefRefPtr<CefBrowser> browser = CefBrowserHost::CreateBrowserSync(info, app->m_WindowHandler[mainUUID].get(), URL, browser_settings, NULL); app->m_WindowHandler[mainUUID]->m_MainBrowser = browser; mainWinBrowser = browser; app->hwndRender = hWnd; // setup current handle to use in Show/HideWindow CefRefPtr<CefProcessMessage> process_message = CefProcessMessage::Create("setHandle"); process_message->GetArgumentList()->SetInt(0, reinterpret_cast<int>(hWnd)); browser->SendProcessMessage(PID_RENDERER, process_message); // Send the main window creation start time to the renderer process_message = CefProcessMessage::Create("mainWindowCreationTime"); CefRefPtr<CefBinaryValue> startTime = CefBinaryValue::Create(&beginMainWindowCreationTime, sizeof(CefTime)); process_message->GetArgumentList()->SetBinary(0, startTime); browser->SendProcessMessage(PID_RENDERER, process_message); if (bufferSize) { process_message = CefProcessMessage::Create("lala"); process_message->GetArgumentList()->SetString(0, buff); browser->SendProcessMessage(PID_RENDERER, process_message); } SetWindowLongPtr(hWnd, 0, reinterpret_cast<LONG_PTR>(new WindowExtras)); SetTimer(hWnd, IDLETIMER, IdleTimerPollIntervalMS, NULL); SetTimer(hWnd, NETWORKTIMER, NetworkTimerPollIntervalMS, NULL); return 0; } case WM_MOVE: if (app->m_WindowHandler[mainUUID].get()) { // TODO: Below is a hack to work around the fact that CEF isn't updating screenX and screenY. Periodically, // TODO: check to see if they fix it. // TODO: See issue https://code.google.com/p/chromiumembedded/issues/detail?id=1303&thanks=1303&ts=1402082749 WINDOWINFO wi = {sizeof(WINDOWINFO), 0}; GetWindowInfo(hWnd, &wi); RECT rClient = wi.rcWindow; CefString JS = "window.screenLeft = window.screenX = " + to_string(_Longlong(rClient.left)) + "; window.screenTop = window.screenY = " + to_string(_Longlong(rClient.top)) + ";"; CefRefPtr<CefFrame> frame = app->m_WindowHandler[mainUUID]->GetBrowser()->GetMainFrame(); frame->ExecuteJavaScript(JS, frame->GetURL(), 0); // TODO: Another workaround. For whatever reason, the window positions get updated when the size changes, // TODO: but not when the window is moved. CefWindowHandle hwnd = app->m_WindowHandler[mainUUID]->GetBrowser()->GetHost()->GetWindowHandle(); if (hwnd) { wi.cbSize = sizeof(WINDOWINFO); GetWindowInfo(hwnd, &wi); RECT rWindow = wi.rcWindow; MoveWindow(hwnd, 0, 0, rWindow.right - rWindow.left, rWindow.bottom - rWindow.top + 1, FALSE); MoveWindow(hwnd, 0, 0, rWindow.right - rWindow.left, rWindow.bottom - rWindow.top, FALSE); } app->m_WindowHandler[mainUUID]->CreateAndDispatchCustomEvent("move"); } break; case WM_POWERBROADCAST: if (app->m_WindowHandler[mainUUID].get()) { if (wParam == PBT_APMRESUMEAUTOMATIC || wParam == PBT_APMSUSPEND) { app->m_WindowHandler[mainUUID]->CreateAndDispatchCustomEvent(wParam == PBT_APMSUSPEND? "suspend" : "resume"); // Do we really need a return value? return TRUE; } } break; case WM_WTSSESSION_CHANGE: if (app->m_WindowHandler[mainUUID].get()) { string eventName; switch(wParam) { // Used case WTS_SESSION_LOGON: eventName = "os:logon"; break; // Used case WTS_SESSION_LOGOFF: eventName = "os:logoff"; break; // Used case WTS_SESSION_LOCK: eventName = "os:locked"; break; // Used case WTS_SESSION_UNLOCK: eventName = "os:unlocked"; break; } app->m_WindowHandler[mainUUID]->CreateAndDispatchCustomEvent(eventName); } break; case WM_PAINT: { //RECT cr = {0,}; //::GetClientRect(hWnd, &cr); //::InvalidateRect(hWnd, &cr, FALSE); hdc = BeginPaint(hWnd, &ps); EndPaint(hWnd, &ps); return 0; } case WM_ACTIVATE: if (app->m_WindowHandler[mainUUID].get() && app->m_WindowHandler[mainUUID]->GetBrowser()) { app->m_WindowHandler[mainUUID]->CreateAndDispatchCustomEvent((LOWORD(wParam)>0)? "activated" : "deactivated"); } break; case WM_SETFOCUS: if (app->m_WindowHandler[mainUUID].get() && app->m_WindowHandler[mainUUID]->GetBrowser()) { // Pass focus to the browser window CefWindowHandle hwnd = app->m_WindowHandler[mainUUID]->GetBrowser()->GetHost()->GetWindowHandle(); if (hwnd) PostMessage(hwnd, message, wParam, lParam); } return 0; case WM_SIZE: // Minimizing resizes the window to 0x0 which causes our layout to go all // screwy, so we just ignore it. if (wParam != SIZE_MINIMIZED && app->m_WindowHandler[mainUUID].get() && app->m_WindowHandler[mainUUID]->GetBrowser()) { CefWindowHandle hwnd = app->m_WindowHandler[mainUUID]->GetBrowser()->GetHost()->GetWindowHandle(); if (hwnd) { // This will send a WM_SIZE and WM_PAINT message to the render process SetWindowPos(hwnd, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); return 0; } } break; case WM_ERASEBKGND: if (app->m_WindowHandler[mainUUID].get() && app->m_WindowHandler[mainUUID]->GetBrowser()) { CefWindowHandle hwnd = app->m_WindowHandler[mainUUID]->GetBrowser()->GetHost()->GetWindowHandle(); if (hwnd) { // Dont erase the background if the browser window has been loaded // (this avoids flashing) return 0; } } break; case WM_SYSCOMMAND: if (wParam == IDS_EXIT_CAFFEINE) { PostMessage(hWnd, WM_CLOSE, g_exitCode, 0); return 0; } break; case WM_COMMAND: // Currently only option from the context menu is to exit, hence the fall through to the WM_CLOSE wParam = g_exitCode; case WM_CLOSE: { if (devMode || enableClose) { wParam = g_exitCode; } CefRefPtr<CaffeineClientHandler> handler = app->m_WindowHandler[mainUUID].get(); if (handler && !handler->IsClosing()) { if (wParam == g_exitCode) // Jump list exit { for (map<string, CefRefPtr<CaffeineClientHandler> >::iterator it=app->m_WindowHandler.begin(); it!=app->m_WindowHandler.end(); ++it) { if(it->second.get()) { CefRefPtr<CefBrowser> browser = it->second->GetBrowser(); browser->GetHost()->CloseBrowser(false); } } //CefRefPtr<CefBrowser> browser = handler->GetBrowser(); //if (browser.get()) { // browser->GetHost()->CloseBrowser(false); //} } else { ShowWindow(hWnd, SW_MINIMIZE); } return 0; } break; } case WM_TIMER: { if(IDLETIMER == wParam) { // TODO: Check timer id LASTINPUTINFO lif = {sizeof(LASTINPUTINFO), 0}; GetLastInputInfo(&lif); UINT IdleTimePassed = GetTickCount() - lif.dwTime; WindowExtras *pWE = reinterpret_cast<WindowExtras *>(::GetWindowLongPtr(hWnd, 0)); bool CurrentlyIdle = (pWE->IdleTimeThreshold < IdleTimePassed); if(CurrentlyIdle != pWE->IsIdle) { const CefString EventName = (CurrentlyIdle? "startIdle" : "stopIdle"); pWE->IsIdle = CurrentlyIdle; app->m_WindowHandler[mainUUID]->CreateAndDispatchCustomEvent(EventName); } } // TODO: When we drop XP support, we can use COM and get network connectivity events. else if(NETWORKTIMER == wParam) { WindowExtras *pWE = reinterpret_cast<WindowExtras *>(::GetWindowLongPtr(hWnd, 0)); bool CurrentlyConnected = pWE->NetworkAvailable(); if(CurrentlyConnected != pWE->IsConnected) { const CefString EventName = (CurrentlyConnected? "os:online" : "os:offline"); pWE->IsConnected = CurrentlyConnected; app->m_WindowHandler[mainUUID]->CreateAndDispatchCustomEvent(EventName); } } break; } case WM_DESTROY: { WTSUnRegisterSessionNotification(hWnd); // The frame window has exited if (!devMode) { jumpList.RemoveAllTasks(); } KillTimer(hWnd, IDLETIMER); KillTimer(hWnd, NETWORKTIMER); WindowExtras *pWE = reinterpret_cast<WindowExtras *>(::GetWindowLongPtr(hWnd, 0)); delete pWE; SetWindowLongPtr(hWnd, 0, 0); SetShutdownFlag(true); PostQuitMessage(0); return 0; } case WM_GETMINMAXINFO: { LPMINMAXINFO minmaxInfoPtr = (LPMINMAXINFO) lParam; minmaxInfoPtr->ptMinTrackSize.x = MAIN_WINDOW_MIN_WIN_WIDTH; minmaxInfoPtr->ptMinTrackSize.y = MAIN_WINDOW_MIN_WIN_HEIGHT; // Keep the width the same RECT rect; GetWindowRect(hWnd, &rect); minmaxInfoPtr->ptMaxSize.x = (rect.right - rect.left); // Keep window at same position minmaxInfoPtr->ptMaxPosition.x = rect.left; minmaxInfoPtr->ptMaxPosition.y = 0; SystemParametersInfo( SPI_GETWORKAREA, 0, &rect, 0 ); minmaxInfoPtr->ptMaxSize.y = (rect.bottom - rect.top); return 0; } case WM_COPYDATA: { BOOL retval = FALSE; PCOPYDATASTRUCT pCds = reinterpret_cast<PCOPYDATASTRUCT>(lParam); if (pCds->dwData == WM_PENDING_YID) { if (app->m_WindowHandler[mainUUID].get() && app->m_WindowHandler[mainUUID]->GetBrowser()) { CefRefPtr<CefFrame> frame = app->m_WindowHandler[mainUUID]->GetBrowser()->GetMainFrame(); wstring code = L"Caffeine.pendingYIDs.push(\""; // TODO: Escape this ... otherwise there's an XSS code += static_cast<LPWSTR>(pCds->lpData); code += L"\");"; frame->ExecuteJavaScript(code, frame->GetURL(), 0); } retval = TRUE; } return retval; } case CAFFEINE_SOCKETS_MSG: CefRefPtr<CefProcessMessage> process_message = CefProcessMessage::Create("invokeSocketMethod"); process_message->GetArgumentList()->SetInt(0, wParam); if (WSAGETSELECTERROR(lParam)) { process_message->GetArgumentList()->SetString(1, "error"); process_message->GetArgumentList()->SetInt(2, WSAGETSELECTERROR(lParam)); } else { // No error switch(WSAGETSELECTEVENT(lParam)) { case FD_CONNECT: process_message->GetArgumentList()->SetString(1, "connect"); break; case FD_CLOSE: process_message->GetArgumentList()->SetString(1, "close"); break; case FD_READ: process_message->GetArgumentList()->SetString(1, "read"); break; case FD_WRITE: process_message->GetArgumentList()->SetString(1, "write"); break; } } mainWinBrowser->SendProcessMessage(PID_RENDERER, process_message); break; } return DefWindowProc(hWnd, message, wParam, lParam); }
void Generator::generateParenthesesNonGreedy(JumpList& failures, Label start, Jump success, Jump fail) { jump(start); success.link(this); failures.append(fail); }
void Generator::terminateDisjunction(JumpList& successes) { successes.link(this); }
void JIT::emitSlow_op_urshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { unsigned dst = currentInstruction[1].u.operand; unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; if (isOperandConstantImmediateInt(op2)) { int shift = getConstantOperand(op2).asInt32(); // op1 = regT0 linkSlowCase(iter); // int32 check if (supportsFloatingPointTruncate()) { JumpList failures; failures.append(emitJumpIfNotImmediateNumber(regT0)); // op1 is not a double addPtr(tagTypeNumberRegister, regT0); movePtrToDouble(regT0, fpRegT0); failures.append(branchTruncateDoubleToInt32(fpRegT0, regT0)); if (shift) urshift32(Imm32(shift & 0x1f), regT0); if (shift < 0 || !(shift & 31)) failures.append(branch32(LessThan, regT0, Imm32(0))); emitFastArithReTagImmediate(regT0, regT0); emitPutVirtualRegister(dst, regT0); emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift)); failures.link(this); } if (shift < 0 || !(shift & 31)) linkSlowCase(iter); // failed to box in hot path } else { // op1 = regT0 // op2 = regT1 if (!isOperandConstantImmediateInt(op1)) { linkSlowCase(iter); // int32 check -- op1 is not an int if (supportsFloatingPointTruncate()) { JumpList failures; failures.append(emitJumpIfNotImmediateNumber(regT0)); // op1 is not a double addPtr(tagTypeNumberRegister, regT0); movePtrToDouble(regT0, fpRegT0); failures.append(branchTruncateDoubleToInt32(fpRegT0, regT0)); failures.append(emitJumpIfNotImmediateInteger(regT1)); // op2 is not an int emitFastArithImmToInt(regT1); urshift32(regT1, regT0); failures.append(branch32(LessThan, regT0, Imm32(0))); emitFastArithReTagImmediate(regT0, regT0); emitPutVirtualRegister(dst, regT0); emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift)); failures.link(this); } } linkSlowCase(iter); // int32 check - op2 is not an int linkSlowCase(iter); // Can't represent unsigned result as an immediate } JITStubCall stubCall(this, cti_op_urshift); stubCall.addArgument(op1, regT0); stubCall.addArgument(op2, regT1); stubCall.call(dst); }
void JIT::compileLoadVarargs(Instruction* instruction) { int thisValue = instruction[3].u.operand; int arguments = instruction[4].u.operand; int firstFreeRegister = instruction[5].u.operand; int firstVarArgOffset = instruction[6].u.operand; JumpList slowCase; JumpList end; bool canOptimize = m_codeBlock->usesArguments() && arguments == m_codeBlock->argumentsRegister().offset() && !m_codeBlock->symbolTable()->slowArguments(); if (canOptimize) { emitGetVirtualRegister(arguments, regT0); slowCase.append(branch64(NotEqual, regT0, TrustedImm64(JSValue::encode(JSValue())))); emitGetFromCallFrameHeader32(JSStack::ArgumentCount, regT0); if (firstVarArgOffset) { Jump sufficientArguments = branch32(GreaterThan, regT0, TrustedImm32(firstVarArgOffset + 1)); move(TrustedImm32(1), regT0); Jump endVarArgs = jump(); sufficientArguments.link(this); sub32(TrustedImm32(firstVarArgOffset), regT0); endVarArgs.link(this); } slowCase.append(branch32(Above, regT0, TrustedImm32(Arguments::MaxArguments + 1))); // regT0: argumentCountIncludingThis move(regT0, regT1); add64(TrustedImm32(-firstFreeRegister + JSStack::CallFrameHeaderSize), regT1); // regT1 now has the required frame size in Register units // Round regT1 to next multiple of stackAlignmentRegisters() add64(TrustedImm32(stackAlignmentRegisters() - 1), regT1); and64(TrustedImm32(~(stackAlignmentRegisters() - 1)), regT1); neg64(regT1); lshift64(TrustedImm32(3), regT1); addPtr(callFrameRegister, regT1); // regT1: newCallFrame slowCase.append(branchPtr(Above, AbsoluteAddress(m_vm->addressOfStackLimit()), regT1)); // Initialize ArgumentCount. store32(regT0, Address(regT1, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))); // Initialize 'this'. emitGetVirtualRegister(thisValue, regT2); store64(regT2, Address(regT1, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register)))); // Copy arguments. signExtend32ToPtr(regT0, regT0); end.append(branchSub64(Zero, TrustedImm32(1), regT0)); // regT0: argumentCount Label copyLoop = label(); load64(BaseIndex(callFrameRegister, regT0, TimesEight, (CallFrame::thisArgumentOffset() + firstVarArgOffset) * static_cast<int>(sizeof(Register))), regT2); store64(regT2, BaseIndex(regT1, regT0, TimesEight, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register)))); branchSub64(NonZero, TrustedImm32(1), regT0).linkTo(copyLoop, this); end.append(jump()); } if (canOptimize) slowCase.link(this); emitGetVirtualRegister(arguments, regT1); callOperation(operationSizeFrameForVarargs, regT1, firstFreeRegister, firstVarArgOffset); move(returnValueGPR, stackPointerRegister); emitGetVirtualRegister(thisValue, regT1); emitGetVirtualRegister(arguments, regT2); callOperation(operationLoadVarargs, returnValueGPR, regT1, regT2, firstVarArgOffset); move(returnValueGPR, regT1); if (canOptimize) end.link(this); addPtr(TrustedImm32(sizeof(CallerFrameAndPC)), regT1, stackPointerRegister); }