MacroAssemblerCodeRef stringLengthTrampolineGenerator(VM* vm) { JSInterfaceJIT jit; #if USE(JSVALUE64) // Check eax is a string JSInterfaceJIT::Jump failureCases1 = jit.emitJumpIfNotJSCell(JSInterfaceJIT::regT0); JSInterfaceJIT::Jump failureCases2 = jit.branchPtr( JSInterfaceJIT::NotEqual, JSInterfaceJIT::Address( JSInterfaceJIT::regT0, JSCell::structureOffset()), JSInterfaceJIT::TrustedImmPtr(vm->stringStructure.get())); // Checks out okay! - get the length from the Ustring. jit.load32( JSInterfaceJIT::Address(JSInterfaceJIT::regT0, JSString::offsetOfLength()), JSInterfaceJIT::regT0); JSInterfaceJIT::Jump failureCases3 = jit.branch32( JSInterfaceJIT::LessThan, JSInterfaceJIT::regT0, JSInterfaceJIT::TrustedImm32(0)); // regT0 contains a 64 bit value (is positive, is zero extended) so we don't need sign extend here. jit.emitFastArithIntToImmNoCheck(JSInterfaceJIT::regT0, JSInterfaceJIT::regT0); #else // USE(JSVALUE64) // regT0 holds payload, regT1 holds tag JSInterfaceJIT::Jump failureCases1 = jit.branch32( JSInterfaceJIT::NotEqual, JSInterfaceJIT::regT1, JSInterfaceJIT::TrustedImm32(JSValue::CellTag)); JSInterfaceJIT::Jump failureCases2 = jit.branchPtr( JSInterfaceJIT::NotEqual, JSInterfaceJIT::Address(JSInterfaceJIT::regT0, JSCell::structureOffset()), JSInterfaceJIT::TrustedImmPtr(vm->stringStructure.get())); // Checks out okay! - get the length from the Ustring. jit.load32( JSInterfaceJIT::Address(JSInterfaceJIT::regT0, JSString::offsetOfLength()), JSInterfaceJIT::regT2); JSInterfaceJIT::Jump failureCases3 = jit.branch32( JSInterfaceJIT::Above, JSInterfaceJIT::regT2, JSInterfaceJIT::TrustedImm32(INT_MAX)); jit.move(JSInterfaceJIT::regT2, JSInterfaceJIT::regT0); jit.move(JSInterfaceJIT::TrustedImm32(JSValue::Int32Tag), JSInterfaceJIT::regT1); #endif // USE(JSVALUE64) jit.ret(); JSInterfaceJIT::Call failureCases1Call = jit.makeTailRecursiveCall(failureCases1); JSInterfaceJIT::Call failureCases2Call = jit.makeTailRecursiveCall(failureCases2); JSInterfaceJIT::Call failureCases3Call = jit.makeTailRecursiveCall(failureCases3); LinkBuffer patchBuffer(*vm, &jit, GLOBAL_THUNK_ID); patchBuffer.link(failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail)); patchBuffer.link(failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail)); patchBuffer.link(failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail)); return FINALIZE_CODE(patchBuffer, ("string length trampoline")); }
static MacroAssemblerCodeRef virtualForGenerator(VM* vm, FunctionPtr compile, FunctionPtr notJSFunction, const char* name, CodeSpecializationKind kind) { JSInterfaceJIT jit; JSInterfaceJIT::JumpList slowCase; #if USE(JSVALUE64) slowCase.append(jit.emitJumpIfNotJSCell(JSInterfaceJIT::regT0)); #else // USE(JSVALUE64) slowCase.append(jit.branch32(JSInterfaceJIT::NotEqual, JSInterfaceJIT::regT1, JSInterfaceJIT::TrustedImm32(JSValue::CellTag))); #endif // USE(JSVALUE64) slowCase.append(jit.emitJumpIfNotType(JSInterfaceJIT::regT0, JSInterfaceJIT::regT1, JSFunctionType)); // Finish canonical initialization before JS function call. jit.loadPtr(JSInterfaceJIT::Address(JSInterfaceJIT::regT0, JSFunction::offsetOfScopeChain()), JSInterfaceJIT::regT1); jit.emitPutCellToCallFrameHeader(JSInterfaceJIT::regT1, JSStack::ScopeChain); jit.loadPtr(JSInterfaceJIT::Address(JSInterfaceJIT::regT0, JSFunction::offsetOfExecutable()), JSInterfaceJIT::regT2); JSInterfaceJIT::Jump hasCodeBlock1 = jit.branch32(JSInterfaceJIT::GreaterThanOrEqual, JSInterfaceJIT::Address(JSInterfaceJIT::regT2, FunctionExecutable::offsetOfNumParametersFor(kind)), JSInterfaceJIT::TrustedImm32(0)); jit.preserveReturnAddressAfterCall(JSInterfaceJIT::regT3); jit.storePtr(JSInterfaceJIT::callFrameRegister, &vm->topCallFrame); jit.restoreArgumentReference(); JSInterfaceJIT::Call callCompile = jit.call(); jit.restoreReturnAddressBeforeReturn(JSInterfaceJIT::regT3); jit.loadPtr(JSInterfaceJIT::Address(JSInterfaceJIT::regT0, JSFunction::offsetOfExecutable()), JSInterfaceJIT::regT2); hasCodeBlock1.link(&jit); jit.loadPtr(JSInterfaceJIT::Address(JSInterfaceJIT::regT2, FunctionExecutable::offsetOfJITCodeWithArityCheckFor(kind)), JSInterfaceJIT::regT0); #if !ASSERT_DISABLED JSInterfaceJIT::Jump ok = jit.branchTestPtr(JSInterfaceJIT::NonZero, JSInterfaceJIT::regT0); jit.breakpoint(); ok.link(&jit); #endif jit.jump(JSInterfaceJIT::regT0); slowCase.link(&jit); JSInterfaceJIT::Call callNotJSFunction = generateSlowCaseFor(vm, jit); LinkBuffer patchBuffer(*vm, &jit, GLOBAL_THUNK_ID); patchBuffer.link(callCompile, compile); patchBuffer.link(callNotJSFunction, notJSFunction); return FINALIZE_CODE(patchBuffer, ("virtual %s trampoline", name)); }
static MacroAssemblerCodeRef linkForGenerator(VM* vm, FunctionPtr lazyLink, FunctionPtr notJSFunction, const char* name) { JSInterfaceJIT jit; JSInterfaceJIT::JumpList slowCase; #if USE(JSVALUE64) slowCase.append(jit.emitJumpIfNotJSCell(JSInterfaceJIT::regT0)); slowCase.append(jit.emitJumpIfNotType(JSInterfaceJIT::regT0, JSInterfaceJIT::regT1, JSFunctionType)); #else // USE(JSVALUE64) slowCase.append(jit.branch32(JSInterfaceJIT::NotEqual, JSInterfaceJIT::regT1, JSInterfaceJIT::TrustedImm32(JSValue::CellTag))); slowCase.append(jit.emitJumpIfNotType(JSInterfaceJIT::regT0, JSInterfaceJIT::regT1, JSFunctionType)); #endif // USE(JSVALUE64) // Finish canonical initialization before JS function call. jit.loadPtr(JSInterfaceJIT::Address(JSInterfaceJIT::regT0, JSFunction::offsetOfScopeChain()), JSInterfaceJIT::regT1); jit.emitPutCellToCallFrameHeader(JSInterfaceJIT::regT1, JSStack::ScopeChain); // Also initialize ReturnPC for use by lazy linking and exceptions. jit.preserveReturnAddressAfterCall(JSInterfaceJIT::regT3); jit.emitPutToCallFrameHeader(JSInterfaceJIT::regT3, JSStack::ReturnPC); jit.storePtr(JSInterfaceJIT::callFrameRegister, &vm->topCallFrame); jit.restoreArgumentReference(); JSInterfaceJIT::Call callLazyLink = jit.call(); jit.restoreReturnAddressBeforeReturn(JSInterfaceJIT::regT3); jit.jump(JSInterfaceJIT::regT0); slowCase.link(&jit); JSInterfaceJIT::Call callNotJSFunction = generateSlowCaseFor(vm, jit); LinkBuffer patchBuffer(*vm, &jit, GLOBAL_THUNK_ID); patchBuffer.link(callLazyLink, lazyLink); patchBuffer.link(callNotJSFunction, notJSFunction); return FINALIZE_CODE(patchBuffer, ("link %s trampoline", name)); }