• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

C++ MONO_CONTEXT_GET_IP函数代码示例

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

本文整理汇总了C++中MONO_CONTEXT_GET_IP函数的典型用法代码示例。如果您正苦于以下问题:C++ MONO_CONTEXT_GET_IP函数的具体用法?C++ MONO_CONTEXT_GET_IP怎么用?C++ MONO_CONTEXT_GET_IP使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。



在下文中一共展示了MONO_CONTEXT_GET_IP函数的17个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的C++代码示例。

示例1: mono_native_state_add_ctx

static void
mono_native_state_add_ctx (MonoStateWriter *writer, MonoContext *ctx)
{
	// Context
	mono_state_writer_indent (writer);
	mono_state_writer_object_key (writer, "ctx");
	mono_state_writer_printf(writer, "{\n");
	writer->indent++;

	assert_has_space (writer);
	mono_state_writer_indent (writer);
	mono_state_writer_object_key (writer, "IP");
	mono_state_writer_printf(writer, "\"%p\",\n", (gpointer) MONO_CONTEXT_GET_IP (ctx));

	assert_has_space (writer);
	mono_state_writer_indent (writer);
	mono_state_writer_object_key (writer, "SP");
	mono_state_writer_printf(writer, "\"%p\",\n", (gpointer) MONO_CONTEXT_GET_SP (ctx));

	assert_has_space (writer);
	mono_state_writer_indent (writer);
	mono_state_writer_object_key (writer, "BP");
	mono_state_writer_printf(writer, "\"%p\"\n", (gpointer) MONO_CONTEXT_GET_BP (ctx));

	writer->indent--;
	mono_state_writer_indent (writer);
	mono_state_writer_printf(writer, "}");
}
开发者ID:LogosBible,项目名称:mono,代码行数:28,代码来源:mono-state.c


示例2: mono_arch_setup_resume_sighandler_ctx

/*
 * mono_arch_setup_resume_sighandler_ctx:
 *
 *   Setup CTX so execution continues at FUNC.
 */
void
mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func)
{
	MONO_CONTEXT_SET_IP (ctx,func);
	if ((mgreg_t)MONO_CONTEXT_GET_IP (ctx) & 1)
		/* Transition to thumb */
		ctx->cpsr |= (1 << 5);
	else
		/* Transition to ARM */
		ctx->cpsr &= ~(1 << 5);
}
开发者ID:aakashapoorv,项目名称:mono,代码行数:16,代码来源:exceptions-arm.c


示例3: is_thread_in_critical_region

/*
FIXME fix cardtable WB to be out of line and check with the runtime if the target is not the
WB trampoline. Another option is to encode wb ranges in MonoJitInfo, but that is somewhat hard.
*/
static gboolean
is_thread_in_critical_region (MonoThreadInfo *info)
{
	MonoMethod *method;
	MonoJitInfo *ji = mono_jit_info_table_find (
		info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN],
		MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));

	if (!ji)
		return FALSE;

	method = ji->method;

	return mono_gc_is_critical_method (method);
}
开发者ID:Andrea,项目名称:mono,代码行数:19,代码来源:mono-threads.c


示例4: handle_signal_exception

/*
 * handle_exception:
 *
 *   Called by resuming from a signal handler.
 */
static void
handle_signal_exception (gpointer obj, gboolean test_only)
{
	MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
	MonoContext ctx;
	static void (*restore_context) (MonoContext *);

	if (!restore_context)
		restore_context = mono_get_restore_context ();

	memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext));

	mono_handle_exception (&ctx, obj, MONO_CONTEXT_GET_IP (&ctx), test_only);

	restore_context (&ctx);
}
开发者ID:massimiliano-mantione,项目名称:mono,代码行数:21,代码来源:exceptions-arm.c


示例5: handle_signal_exception

/*
 * handle_exception:
 *
 *   Called by resuming from a signal handler.
 */
static void
handle_signal_exception (gpointer obj)
{
	MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
	MonoContext ctx;
	static void (*restore_context) (MonoContext *);

	if (!restore_context)
		restore_context = mono_get_restore_context ();

	memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext));

	if (mono_debugger_handle_exception (&ctx, (MonoObject *)obj))
		return;

	mono_handle_exception (&ctx, obj, MONO_CONTEXT_GET_IP (&ctx), FALSE);

	restore_context (&ctx);
}
开发者ID:Sciumo,项目名称:mono,代码行数:24,代码来源:exceptions-x86.c


示例6: is_thread_in_critical_region

/*
FIXME fix cardtable WB to be out of line and check with the runtime if the target is not the
WB trampoline. Another option is to encode wb ranges in MonoJitInfo, but that is somewhat hard.
*/
static gboolean
is_thread_in_critical_region (MonoThreadInfo *info)
{
	MonoMethod *method;
	MonoJitInfo *ji;

	if (info->inside_critical_region)
		return TRUE;

	ji = mono_jit_info_table_find (
		info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN],
		MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));

	if (!ji)
		return FALSE;

	method = mono_jit_info_get_method (ji);

	return threads_callbacks.mono_method_is_critical (method);
}
开发者ID:aakashapoorv,项目名称:mono,代码行数:24,代码来源:mono-threads.c


示例7: is_thread_in_critical_region

/*
FIXME fix cardtable WB to be out of line and check with the runtime if the target is not the
WB trampoline. Another option is to encode wb ranges in MonoJitInfo, but that is somewhat hard.
*/
static gboolean
is_thread_in_critical_region (MonoThreadInfo *info)
{
	MonoMethod *method;
	MonoJitInfo *ji;

	if (info->inside_critical_region)
		return TRUE;

	/* The target thread might be shutting down and the domain might be null, which means no managed code left to run. */
	if (!info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN])
		return FALSE;

	ji = mono_jit_info_table_find (
		info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN],
		MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));

	if (!ji)
		return FALSE;

	method = mono_jit_info_get_method (ji);

	return threads_callbacks.mono_method_is_critical (method);
}
开发者ID:glinos,项目名称:mono,代码行数:28,代码来源:mono-threads.c


示例8: mono_arch_unwind_frame

/*
 * mono_arch_unwind_frame:
 *
 * This function is used to gather information from @ctx, and store it in @frame_info.
 * It unwinds one stack frame, and stores the resulting context into @new_ctx. @lmf
 * is modified if needed.
 * Returns TRUE on success, FALSE otherwise.
 */
gboolean
mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, 
							 MonoJitInfo *ji, MonoContext *ctx, 
							 MonoContext *new_ctx, MonoLMF **lmf,
							 mgreg_t **save_locations,
							 StackFrameInfo *frame)
{
	gpointer ip = MONO_CONTEXT_GET_IP (ctx);
	int i;

	memset (frame, 0, sizeof (StackFrameInfo));
	frame->ji = ji;

	*new_ctx = *ctx;

	if (ji != NULL) {
		mgreg_t regs [MONO_MAX_IREGS + 1];
		guint8 *cfa;
		guint32 unwind_info_len;
		guint8 *unwind_info;
		guint8 *epilog = NULL;

		if (ji->is_trampoline)
			frame->type = FRAME_TYPE_TRAMPOLINE;
		else
			frame->type = FRAME_TYPE_MANAGED;

		unwind_info = mono_jinfo_get_unwind_info (ji, &unwind_info_len);

		frame->unwind_info = unwind_info;
		frame->unwind_info_len = unwind_info_len;

		/*
		printf ("%s %p %p\n", ji->d.method->name, ji->code_start, ip);
		mono_print_unwind_info (unwind_info, unwind_info_len);
		*/
		/* LLVM compiled code doesn't have this info */
		if (ji->has_arch_eh_info)
			epilog = (guint8*)ji->code_start + ji->code_size - mono_jinfo_get_epilog_size (ji);
 
		for (i = 0; i < AMD64_NREG; ++i)
			regs [i] = new_ctx->gregs [i];

		mono_unwind_frame (unwind_info, unwind_info_len, (guint8 *)ji->code_start,
						   (guint8*)ji->code_start + ji->code_size,
						   (guint8 *)ip, epilog ? &epilog : NULL, regs, MONO_MAX_IREGS + 1,
						   save_locations, MONO_MAX_IREGS, &cfa);

		for (i = 0; i < AMD64_NREG; ++i)
			new_ctx->gregs [i] = regs [i];
 
		/* The CFA becomes the new SP value */
		new_ctx->gregs [AMD64_RSP] = (mgreg_t)cfa;

		/* Adjust IP */
		new_ctx->gregs [AMD64_RIP] --;

		return TRUE;
	} else if (*lmf) {
		guint64 rip;

		if (((guint64)(*lmf)->previous_lmf) & 2) {
			/* 
			 * This LMF entry is created by the soft debug code to mark transitions to
			 * managed code done during invokes.
			 */
			MonoLMFExt *ext = (MonoLMFExt*)(*lmf);

			g_assert (ext->debugger_invoke);

			memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));

			*lmf = (MonoLMF *)(((guint64)(*lmf)->previous_lmf) & ~7);

			frame->type = FRAME_TYPE_DEBUGGER_INVOKE;

			return TRUE;
		}

		if (((guint64)(*lmf)->previous_lmf) & 4) {
			MonoLMFTramp *ext = (MonoLMFTramp*)(*lmf);

			rip = (guint64)MONO_CONTEXT_GET_IP (ext->ctx);
		} else if (((guint64)(*lmf)->previous_lmf) & 1) {
			/* This LMF has the rip field set */
			rip = (*lmf)->rip;
		} else if ((*lmf)->rsp == 0) {
			/* Top LMF entry */
			return FALSE;
		} else {
			/* 
			 * The rsp field is set just before the call which transitioned to native 
//.........这里部分代码省略.........
开发者ID:TheMetalMage,项目名称:mono,代码行数:101,代码来源:exceptions-amd64.c


示例9: mono_arch_find_jit_info

/*
 * mono_arch_find_jit_info:
 *
 * See exceptions-amd64.c for docs.
 */
gboolean
mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, 
							 MonoJitInfo *ji, MonoContext *ctx, 
							 MonoContext *new_ctx, MonoLMF **lmf,
							 mgreg_t **save_locations,
							 StackFrameInfo *frame)
{
	gpointer ip = MONO_CONTEXT_GET_IP (ctx);

	memset (frame, 0, sizeof (StackFrameInfo));
	frame->ji = ji;

	*new_ctx = *ctx;

	if (ji != NULL) {
		gssize regs [MONO_MAX_IREGS + 1];
		guint8 *cfa;
		guint32 unwind_info_len;
		guint8 *unwind_info;

		frame->type = FRAME_TYPE_MANAGED;

		if (ji->from_aot)
			unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len);
		else
			unwind_info = mono_get_cached_unwind_info (ji->used_regs, &unwind_info_len);

		regs [X86_EAX] = new_ctx->eax;
		regs [X86_EBX] = new_ctx->ebx;
		regs [X86_ECX] = new_ctx->ecx;
		regs [X86_EDX] = new_ctx->edx;
		regs [X86_ESP] = new_ctx->esp;
		regs [X86_EBP] = new_ctx->ebp;
		regs [X86_ESI] = new_ctx->esi;
		regs [X86_EDI] = new_ctx->edi;
		regs [X86_NREG] = new_ctx->eip;

		mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
						   (guint8*)ji->code_start + ji->code_size,
						   ip, regs, MONO_MAX_IREGS + 1,
						   save_locations, MONO_MAX_IREGS, &cfa);

		new_ctx->eax = regs [X86_EAX];
		new_ctx->ebx = regs [X86_EBX];
		new_ctx->ecx = regs [X86_ECX];
		new_ctx->edx = regs [X86_EDX];
		new_ctx->esp = regs [X86_ESP];
		new_ctx->ebp = regs [X86_EBP];
		new_ctx->esi = regs [X86_ESI];
		new_ctx->edi = regs [X86_EDI];
		new_ctx->eip = regs [X86_NREG];

 		/* The CFA becomes the new SP value */
		new_ctx->esp = (gssize)cfa;

		/* Adjust IP */
		new_ctx->eip --;

		if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
			/* remove any unused lmf */
			*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
		}

		/* Pop arguments off the stack */
		/* 
		 * FIXME: LLVM doesn't push these, we can't use ji->from_llvm as it describes
		 * the callee.
		 */
#ifndef ENABLE_LLVM
		if (ji->has_arch_eh_info)
			new_ctx->esp += mono_jit_info_get_arch_eh_info (ji)->stack_size;
#endif

		return TRUE;
	} else if (*lmf) {

		if (((guint64)(*lmf)->previous_lmf) & 2) {
			/* 
			 * This LMF entry is created by the soft debug code to mark transitions to
			 * managed code done during invokes.
			 */
			MonoLMFExt *ext = (MonoLMFExt*)(*lmf);

			g_assert (ext->debugger_invoke);

			memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));

			*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);

			frame->type = FRAME_TYPE_DEBUGGER_INVOKE;

			return TRUE;
		}
		
		if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL))) {
//.........这里部分代码省略.........
开发者ID:efcastrillon,项目名称:mono,代码行数:101,代码来源:exceptions-x86.c


示例10: mono_arch_unwind_frame

/*
 * mono_arch_unwind_frame:
 *
 * See exceptions-amd64.c for docs.
 */
gboolean
mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, 
							 MonoJitInfo *ji, MonoContext *ctx, 
							 MonoContext *new_ctx, MonoLMF **lmf,
							 mgreg_t **save_locations,
							 StackFrameInfo *frame)
{
	gpointer ip = MONO_CONTEXT_GET_IP (ctx);
	MonoPPCStackFrame *sframe;

	memset (frame, 0, sizeof (StackFrameInfo));
	frame->ji = ji;

	*new_ctx = *ctx;
	setup_context (new_ctx);

	if (ji != NULL) {
		int i;
		mgreg_t regs [ppc_lr + 1];
		guint8 *cfa;
		guint32 unwind_info_len;
		guint8 *unwind_info;

		if (ji->is_trampoline)
			frame->type = FRAME_TYPE_TRAMPOLINE;
		else
			frame->type = FRAME_TYPE_MANAGED;

		unwind_info = mono_jinfo_get_unwind_info (ji, &unwind_info_len);

		sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_SP (ctx);
		MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
		if (!ji->is_trampoline && jinfo_get_method (ji)->save_lmf) {
			/* sframe->sp points just past the end of the LMF */
			guint8 *lmf_addr = (guint8*)sframe->sp - sizeof (MonoLMF);
			memcpy (&new_ctx->fregs [MONO_PPC_FIRST_SAVED_FREG], lmf_addr + G_STRUCT_OFFSET (MonoLMF, fregs), sizeof (double) * MONO_SAVED_FREGS);
			memcpy (&new_ctx->regs [MONO_PPC_FIRST_SAVED_GREG], lmf_addr + G_STRUCT_OFFSET (MonoLMF, iregs), sizeof (mgreg_t) * MONO_SAVED_GREGS);
			/* the calling IP is in the parent frame */
			sframe = (MonoPPCStackFrame*)sframe->sp;
			/* we substract 4, so that the IP points into the call instruction */
			MONO_CONTEXT_SET_IP (new_ctx, sframe->lr - 4);
		} else {
			regs [ppc_lr] = ctx->sc_ir;
			regs [ppc_sp] = ctx->sc_sp;
			for (i = MONO_PPC_FIRST_SAVED_GREG; i < MONO_MAX_IREGS; ++i)
				regs [i] = ctx->regs [i];

			mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
							   (guint8*)ji->code_start + ji->code_size,
							   ip, NULL, regs, ppc_lr + 1,
							   save_locations, MONO_MAX_IREGS, &cfa);

			/* we substract 4, so that the IP points into the call instruction */
			MONO_CONTEXT_SET_IP (new_ctx, regs [ppc_lr] - 4);
			MONO_CONTEXT_SET_BP (new_ctx, cfa);

			for (i = MONO_PPC_FIRST_SAVED_GREG; i < MONO_MAX_IREGS; ++i)
				new_ctx->regs [i] = regs [i];
		}

		return TRUE;
	} else if (*lmf) {
		
		if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL))) {
		} else {
			if (!(*lmf)->method)
				return FALSE;

			/* Trampoline lmf frame */
			frame->method = (*lmf)->method;
		}

		/*sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_SP (ctx);
		MONO_CONTEXT_SET_BP (new_ctx, sframe->sp);
		MONO_CONTEXT_SET_IP (new_ctx, sframe->lr);*/
		MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp);
		MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip);
		memcpy (&new_ctx->regs [MONO_PPC_FIRST_SAVED_GREG], (*lmf)->iregs, sizeof (mgreg_t) * MONO_SAVED_GREGS);
		memcpy (&new_ctx->fregs [MONO_PPC_FIRST_SAVED_FREG], (*lmf)->fregs, sizeof (double) * MONO_SAVED_FREGS);

		frame->ji = ji;
		frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;

		/* FIXME: what about trampoline LMF frames?  see exceptions-x86.c */

		*lmf = (*lmf)->previous_lmf;

		return TRUE;
	}

	return FALSE;
}
开发者ID:medo64,项目名称:mono,代码行数:97,代码来源:exceptions-ppc.c


示例11: mono_arch_find_jit_info

/* mono_arch_find_jit_info:
 *
 * This function is used to gather information from @ctx. It returns the 
 * MonoJitInfo of the corresponding function, unwinds one stack frame and
 * stores the resulting context into @new_ctx. It also stores a string 
 * describing the stack location into @trace (if not NULL), and modifies
 * the @lmf if necessary. @native_offset return the IP offset from the 
 * start of the function or -1 if that info is not available.
 */
MonoJitInfo *
mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls,
			 MonoJitInfo *res, MonoJitInfo *prev_ji,
			 MonoContext *ctx, MonoContext *new_ctx,
			 MonoLMF **lmf, gboolean *managed)
{
	MonoJitInfo *ji;
	gpointer ip = MONO_CONTEXT_GET_IP (ctx);
	gpointer fp = MONO_CONTEXT_GET_BP (ctx);
	guint32 sp;

	/* Avoid costly table lookup during stack overflow */
	if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
		ji = prev_ji;
	else
		ji = mini_jit_info_table_find (domain, ip, NULL);

	if (managed)
		*managed = FALSE;

	memcpy (new_ctx, ctx, sizeof (MonoContext));

	if (ji != NULL) {
		int i;
		gint32 address;
		int offset = 0;

		if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
			/* remove any unused lmf */
			*lmf = (*lmf)->previous_lmf;
		}

		address = (char *)ip - (char *)ji->code_start;

		if (managed)
			if (!ji->method->wrapper_type)
				*managed = TRUE;

		/* My stack frame */
		fp = MONO_CONTEXT_GET_BP (ctx);

		/* Compute the previous stack frame */
		sp = (guint32)(fp) - (short)(*(guint32 *)(ji->code_start));

		/* Sanity check the frame */
		if (!sp || (sp == 0xffffffff)
		    || (sp & 0x07) || (sp < 64*1024)) {
#ifdef DEBUG_EXCEPTIONS
			g_print ("mono_arch_find_jit_info: bad stack sp=%p\n", (void *) sp);
#endif
			return (gpointer)-1;
		}

		if (ji->method->save_lmf && 0) {
			/* only enable this when prologue stops emitting
			 * normal save of s-regs when save_lmf is true.
			 * Will have to sync with prologue code at that point.
			 */
			memcpy (&new_ctx->sc_fpregs,
				(char*)sp - sizeof (float) * MONO_SAVED_FREGS,
				sizeof (float) * MONO_SAVED_FREGS);
			memcpy (&new_ctx->sc_regs,
				(char*)sp - sizeof (float) * MONO_SAVED_FREGS - sizeof (gulong) * MONO_SAVED_GREGS,
				sizeof (gulong) * MONO_SAVED_GREGS);
		} else if (ji->used_regs) {
			guint32 *insn;
			guint32 mask = ji->used_regs;

			/* these all happen before adjustment of fp */
			/* Look for sw ??, ????(sp) */
			insn = ((guint32 *)ji->code_start) + 1;
			while (!*insn || ((*insn & 0xffe00000) == 0xafa00000) || ((*insn & 0xffe00000) == 0xffa00000)) {
				int reg = (*insn >> 16) & 0x1f;
				guint32 addr = (((guint32)fp) + (short)(*insn & 0x0000ffff));

				mask &= ~(1 << reg);
				if ((*insn & 0xffe00000) == 0xafa00000)
					new_ctx->sc_regs [reg] = *(guint32 *)addr;
				else
					new_ctx->sc_regs [reg] = *(guint64 *)addr;
				insn++;
			}
			MONO_CONTEXT_SET_SP (new_ctx, sp);
			MONO_CONTEXT_SET_BP (new_ctx, sp);
			/* assert that we found all registers we were supposed to */
			g_assert (!mask);
		}
开发者ID:moander,项目名称:mono,代码行数:96,代码来源:exceptions-mips.c


示例12: mono_arch_find_jit_info

/* 
 * mono_arch_find_jit_info:
 *
 * See exceptions-amd64.c for docs;
 */
gboolean
mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, 
							 MonoJitInfo *ji, MonoContext *ctx, 
							 MonoContext *new_ctx, MonoLMF **lmf,
							 mgreg_t **save_locations,
							 StackFrameInfo *frame)
{
	gpointer ip = MONO_CONTEXT_GET_IP (ctx);

	memset (frame, 0, sizeof (StackFrameInfo));
	frame->ji = ji;

	*new_ctx = *ctx;

	if (ji != NULL) {
		int i;
		gssize regs [MONO_MAX_IREGS + 1];
		guint8 *cfa;
		guint32 unwind_info_len;
		guint8 *unwind_info;

		frame->type = FRAME_TYPE_MANAGED;

		if (ji->from_aot)
			unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len);
		else
			unwind_info = mono_get_cached_unwind_info (ji->used_regs, &unwind_info_len);

		for (i = 0; i < 16; ++i)
			regs [i] = new_ctx->regs [i];

		mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
						   (guint8*)ji->code_start + ji->code_size,
						   ip, regs, MONO_MAX_IREGS,
						   save_locations, MONO_MAX_IREGS, &cfa);

		for (i = 0; i < 16; ++i)
			new_ctx->regs [i] = regs [i];
		new_ctx->pc = regs [ARMREG_LR];
		new_ctx->regs [ARMREG_SP] = (gsize)cfa;

		if (*lmf && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->sp)) {
			/* remove any unused lmf */
			*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
		}

		/* Clear thumb bit */
		new_ctx->pc &= ~1;

		/* we substract 1, so that the IP points into the call instruction */
		new_ctx->pc--;

		return TRUE;
	} else if (*lmf) {

		if (((gsize)(*lmf)->previous_lmf) & 2) {
			/* 
			 * This LMF entry is created by the soft debug code to mark transitions to
			 * managed code done during invokes.
			 */
			MonoLMFExt *ext = (MonoLMFExt*)(*lmf);

			g_assert (ext->debugger_invoke);

			memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));

			*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);

			frame->type = FRAME_TYPE_DEBUGGER_INVOKE;

			return TRUE;
		}

		frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
		
		if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->ip, NULL))) {
			frame->ji = ji;
		} else {
			if (!(*lmf)->method)
				return FALSE;
			frame->method = (*lmf)->method;
		}

		/*
		 * The LMF is saved at the start of the method using:
		 * ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP)
		 * ARM_PUSH (code, 0x5ff0);
		 * So it stores the register state as it existed at the caller. We need to
		 * produce the register state which existed at the time of the call which
		 * transitioned to native call, so we save the sp/fp/ip in the LMF.
		 */
		memcpy (&new_ctx->regs [0], &(*lmf)->iregs [0], sizeof (mgreg_t) * 13);
		new_ctx->pc = (*lmf)->ip;
		new_ctx->regs [ARMREG_SP] = (*lmf)->sp;
		new_ctx->regs [ARMREG_FP] = (*lmf)->fp;
//.........这里部分代码省略.........
开发者ID:aakashapoorv,项目名称:mono,代码行数:101,代码来源:exceptions-arm.c


示例13: suspend_thread

static void
suspend_thread (SgenThreadInfo *info, void *context)
{
	int stop_count;
#ifndef USE_MONO_CTX
	gpointer regs [ARCH_NUM_REGS];
#endif
	MonoContext ctx;
	gpointer stack_start;

	info->client_info.stopped_domain = mono_domain_get ();
	info->client_info.signal = 0;
	stop_count = sgen_global_stop_count;
	/* duplicate signal */
	if (0 && info->client_info.stop_count == stop_count)
		return;

#ifdef USE_MONO_CTX
	if (context) {
		mono_sigctx_to_monoctx (context, &ctx);
		info->client_info.stopped_ip = MONO_CONTEXT_GET_IP (&ctx);
		stack_start = (((guint8 *) MONO_CONTEXT_GET_SP (&ctx)) - REDZONE_SIZE);
	} else {
		info->client_info.stopped_ip = NULL;
		stack_start = NULL;
	}
#else
	info->client_info.stopped_ip = context ? (gpointer) ARCH_SIGCTX_IP (context) : NULL;
	stack_start = context ? (char*) ARCH_SIGCTX_SP (context) - REDZONE_SIZE : NULL;
#endif

	/* If stack_start is not within the limits, then don't set it
	   in info and we will be restarted. */
	if (stack_start >= info->client_info.stack_start_limit && stack_start <= info->client_info.stack_end) {
		info->client_info.stack_start = stack_start;

#ifdef USE_MONO_CTX
		if (context) {
			memcpy (&info->client_info.ctx, &ctx, sizeof (MonoContext));
		} else {
			memset (&info->client_info.ctx, 0, sizeof (MonoContext));
		}
#else
		if (context) {
			ARCH_COPY_SIGCTX_REGS (regs, context);
			memcpy (&info->client_info.regs, regs, sizeof (info->client_info.regs));
		} else {
			memset (&info->client_info.regs, 0, sizeof (info->client_info.regs));
		}
#endif
	} else {
		g_assert (!info->client_info.stack_start);
	}

	/* Notify the JIT */
	if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
		mono_gc_get_gc_callbacks ()->thread_suspend_func (info->client_info.runtime_data, context, NULL);

	SGEN_LOG (4, "Posting suspend_ack_semaphore for suspend from %p %p", info, (gpointer) (gsize) mono_native_thread_id_get ());

	/*
	Block the restart signal. 
	We need to block the restart signal while posting to the suspend_ack semaphore or we race to sigsuspend,
	which might miss the signal and get stuck.
	*/
	pthread_sigmask (SIG_BLOCK, &suspend_ack_signal_mask, NULL);

	/* notify the waiting thread */
	SGEN_SEMAPHORE_POST (suspend_ack_semaphore_ptr);
	info->client_info.stop_count = stop_count;

	/* wait until we receive the restart signal */
	do {
		info->client_info.signal = 0;
		sigsuspend (&suspend_signal_mask);
	} while (info->client_info.signal != restart_signal_num);

	/* Unblock the restart signal. */
	pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL);

	SGEN_LOG (4, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer) (gsize) mono_native_thread_id_get ());
	/* notify the waiting thread */
	SGEN_SEMAPHORE_POST (suspend_ack_semaphore_ptr);
}
开发者ID:campolake,项目名称:mono_research,代码行数:84,代码来源:sgen-os-posix.c


示例14: mono_arch_find_jit_info

/*
 * mono_arch_find_jit_info:
 *
 * This function is used to gather information from @ctx, and store it in @frame_info.
 * It unwinds one stack frame, and stores the resulting context into @new_ctx. @lmf
 * is modified if needed.
 * Returns TRUE on success, FALSE otherwise.
 */
gboolean
mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, 
							 MonoJitInfo *ji, MonoContext *ctx, 
							 MonoContext *new_ctx, MonoLMF **lmf, 
							 mgreg_t **save_locations,
							 StackFrameInfo *frame)
{
	memset (frame, 0, sizeof (StackFrameInfo));
	frame->ji = ji;

	*new_ctx = *ctx;

	if (ji != NULL) {
		int i;
		gpointer ip = MONO_CONTEXT_GET_IP (ctx);
		mgreg_t regs [MONO_MAX_IREGS + 1];
		guint8 *cfa;
		guint32 unwind_info_len;
		guint8 *unwind_info;

		frame->type = FRAME_TYPE_MANAGED;

		unwind_info = mono_jinfo_get_unwind_info (ji, &unwind_info_len);

		for (i = 0; i < MONO_MAX_IREGS; ++i)
			regs [i] = new_ctx->sc_regs [i];

		mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
						   (guint8*)ji->code_start + ji->code_size,
						   ip, NULL, regs, MONO_MAX_IREGS,
						   save_locations, MONO_MAX_IREGS, &cfa);

		for (i = 0; i < MONO_MAX_IREGS; ++i)
			new_ctx->sc_regs [i] = regs [i];
		new_ctx->sc_pc = regs [mips_ra];
		new_ctx->sc_regs [mips_sp] = (mgreg_t)cfa;

		/* we substract 8, so that the IP points into the call instruction */
		MONO_CONTEXT_SET_IP (new_ctx, new_ctx->sc_pc - 8);

		/* Sanity check -- we should have made progress here */
		g_assert (MONO_CONTEXT_GET_SP (new_ctx) != MONO_CONTEXT_GET_SP (ctx));
		return TRUE;
	} else if (*lmf) {

		if (((mgreg_t)(*lmf)->previous_lmf) & 2) {
			/* 
			 * This LMF entry is created by the soft debug code to mark transitions to
			 * managed code done during invokes.
			 */
			MonoLMFExt *ext = (MonoLMFExt*)(*lmf);

			g_assert (ext->debugger_invoke);

			memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));

			*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);

			frame->type = FRAME_TYPE_DEBUGGER_INVOKE;

			return TRUE;
		}

		if (!(*lmf)->method) {
#ifdef DEBUG_EXCEPTIONS
			g_print ("mono_arch_find_jit_info: bad lmf @ %p\n", (void *) *lmf);
#endif
			return FALSE;
		}
		g_assert (((*lmf)->magic == MIPS_LMF_MAGIC1) || ((*lmf)->magic == MIPS_LMF_MAGIC2));

		ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL);
		if (!ji) {
			// FIXME: This can happen with multiple appdomains (bug #444383)
			return FALSE;
		}

		frame->ji = ji;
		frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;

		memcpy (&new_ctx->sc_regs, (*lmf)->iregs, sizeof (gulong) * MONO_SAVED_GREGS);
		memcpy (&new_ctx->sc_fpregs, (*lmf)->fregs, sizeof (float) * MONO_SAVED_FREGS);
		MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip);
		/* ensure that we've made progress */
		g_assert (new_ctx->sc_pc != ctx->sc_pc);

		*lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);

		return TRUE;
	}

	return FALSE;
//.........这里部分代码省略.........
开发者ID:Adamcbrz,项目名称:mono,代码行数:101,代码来源:exceptions-mips.c


示例15: mono_arch_unwind_frame

/*
 * mono_arch_unwind_frame:
 *
 * See exceptions-amd64.c for docs;
 */
gboolean
mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls,
                        MonoJitInfo *ji, MonoContext *ctx,
                        MonoContext *new_ctx, MonoLMF **lmf,
                        mgreg_t **save_locations,
                        StackFrameInfo *frame)
{
    gpointer ip = MONO_CONTEXT_GET_IP (ctx);

    memset (frame, 0, sizeof (StackFrameInfo));
    frame->ji = ji;

    *new_ctx = *ctx;

    if (ji != NULL) {
        mgreg_t regs [MONO_MAX_IREGS + 8 + 1];
        guint8 *cfa;
        guint32 unwind_info_len;
        guint8 *unwind_info;

        frame->type = FRAME_TYPE_MANAGED;

        unwind_info = mono_jinfo_get_unwind_info (ji, &unwind_info_len);

        memcpy (regs, &new_ctx->regs, sizeof (mgreg_t) * 32);
        /* v8..v15 are callee saved */
        memcpy (regs + MONO_MAX_IREGS, &(new_ctx->fregs [8]), sizeof (mgreg_t) * 8);

        mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start,
                           (guint8*)ji->code_start + ji->code_size,
                           ip, NULL, regs, MONO_MAX_IREGS + 8,
                           save_locations, MONO_MAX_IREGS, &cfa);

        memcpy (&new_ctx->regs, regs, sizeof (mgreg_t) * 32);
        memcpy (&(new_ctx->fregs [8]), regs + MONO_MAX_IREGS, sizeof (mgreg_t) * 8);

        new_ctx->pc = regs [ARMREG_LR];
        new_ctx->regs [ARMREG_SP] = (mgreg_t)cfa;

        if (*lmf && (*lmf)->gregs [MONO_ARCH_LMF_REG_SP] && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->gregs [MONO_ARCH_LMF_REG_SP])) {
            /* remove any unused lmf */
            *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
        }

        /* we substract 1, so that the IP points into the call instruction */
        new_ctx->pc--;

        return TRUE;
    } else if (*lmf) {
        if (((gsize)(*lmf)->previous_lmf) & 2) {
            /*
             * This LMF entry is created by the soft debug code to mark transitions to
             * managed code done during invokes.
             */
            MonoLMFExt *ext = (MonoLMFExt*)(*lmf);

            g_assert (ext->debugger_invoke);

            memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));

            *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);

            frame->type = FRAME_TYPE_DEBUGGER_INVOKE;

            return TRUE;
        }

        frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;

        ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->pc, NULL);
        if (!ji)
            return FALSE;

        g_assert (MONO_ARCH_LMF_REGS == ((0x3ff << 19) | (1 << ARMREG_FP) | (1 << ARMREG_SP)));
        memcpy (&new_ctx->regs [ARMREG_R19], &(*lmf)->gregs [0], sizeof (mgreg_t) * 10);
        new_ctx->regs [ARMREG_FP] = (*lmf)->gregs [MONO_ARCH_LMF_REG_FP];
        new_ctx->regs [ARMREG_SP] = (*lmf)->gregs [MONO_ARCH_LMF_REG_SP];
        new_ctx->pc = (*lmf)->pc;

        /* we substract 1, so that the IP points into the call instruction */
        new_ctx->pc--;

        *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);

        return TRUE;
    }

    return FALSE;
}
开发者ID:mono,项目名称:mono,代码行数:94,代码来源:exceptions-arm64.c


示例16: sgen_unified_suspend_stop_world


//.........这里部分代码省略.........
		FOREACH_THREAD (info) {
			gint suspend_count;

			int reason = 0;
			if (info->client_info.suspend_done || !sgen_is_thread_in_current_stw (info, &reason)) {
				THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE RESUME thread %p not been processed done %d current %d reason %d\n", mono_thread_info_get_tid (info), info->client_info.suspend_done, !sgen_is_thread_in_current_stw (info, NULL), reason);
				continue;
			}

			/*
			All threads that reach here are pristine suspended. This means the following:

			- We haven't accepted the previous suspend as good.
			- We haven't gave up on it for this STW (it's either bad or asked not to)
			*/
			if (!mono_thread_info_in_critical_location (info)) {
				info->client_info.suspend_done = TRUE;

				THREADS_STW_DEBUG ("[GC-STW-RESTART] DONE thread %p deemed fully suspended\n", mono_thread_info_get_tid (info));
				continue;
			}

			suspend_count = mono_thread_info_suspend_count (info);
			if (!(suspend_count == 1))
				g_error ("[%p] suspend_count = %d, but should be 1", mono_thread_info_get_tid (info), suspend_count);

			info->client_info.skip = !mono_thread_info_begin_resume (info);
			if (!info->client_info.skip)
				restart_counter += 1;

			THREADS_STW_DEBUG ("[GC-STW-RESTART] RESTART thread %p skip %s\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false");
		} FOREACH_THREAD_END

		mono_threads_wait_pending_operations ();

		if (restart_counter == 0)
			break;

		if (sleep_duration < 0) {
			mono_thread_info_yield ();
			sleep_duration = 0;
		} else {
			g_usleep (sleep_duration);
			sleep_duration += 10;
		}

		FOREACH_THREAD (info) {
			int reason = 0;
			if (info->client_info.suspend_done || !sgen_is_thread_in_current_stw (info, &reason)) {
				THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE SUSPEND thread %p not been processed done %d current %d reason %d\n", mono_thread_info_get_tid (info), info->client_info.suspend_done, !sgen_is_thread_in_current_stw (info, NULL), reason);
				continue;
			}

			if (!mono_thread_info_is_running (info)) {
				THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE SUSPEND thread %p not running\n", mono_thread_info_get_tid (info));
				continue;
			}

			info->client_info.skip = !mono_thread_info_begin_suspend (info);

			THREADS_STW_DEBUG ("[GC-STW-RESTART] SUSPEND thread %p skip %s\n", mono_thread_info_get_tid (info), info->client_info.skip ? "true" : "false");
		} FOREACH_THREAD_END

		mono_threads_wait_pending_operations ();
	}

	FOREACH_THREAD (info) {
		gpointer stopped_ip;

		int reason = 0;
		if (!sgen_is_thread_in_current_stw (info, &reason)) {
			g_assert (!info->client_info.suspend_done || info == mono_thread_info_current ());

			THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is NOT suspended, reason %d\n", mono_thread_info_get_tid (info), reason);
			continue;
		}

		g_assert (info->client_info.suspend_done);

		info->client_info.ctx = mono_thread_info_get_suspend_state (info)->ctx;

		/* Once we remove the old suspend code, we should move sgen to directly access the state in MonoThread */
		info->client_info.stack_start = (gpointer) ((char*)MONO_CONTEXT_GET_SP (&info->client_info.ctx) - REDZONE_SIZE);

		/* altstack signal handler, sgen can't handle them, mono-threads should have handled this. */
		if (!info->client_info.stack_start
			 || info->client_info.stack_start < info->client_info.stack_start_limit
			 || info->client_info.stack_start >= info->client_info.stack_end) {
			g_error ("BAD STACK: stack_start = %p, stack_start_limit = %p, stack_end = %p",
				info->client_info.stack_start, info->client_info.stack_start_limit, info->client_info.stack_end);
		}

		stopped_ip = (gpointer) (MONO_CONTEXT_GET_IP (&info->client_info.ctx));

		binary_protocol_thread_suspend ((gpointer) mono_thread_info_get_tid (info), stopped_ip);

		THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is suspended, stopped_ip = %p, stack = %p -> %p\n",
			mono_thread_info_get_tid (info), stopped_ip, info->client_info.stack_start, info->client_info.stack_start ? info->client_info.stack_end : NULL);
	} FOREACH_THREAD_END
}
开发者ID:sushihangover,项目名称:playscript,代码行数:101,代码来源:sgen-stw.c


示例17: sgen_unified_suspend_stop_world


//.........这里部分代码省略.........
		FOREACH_THREAD (info) {
			int reason = 0;
			if (info->client_info.suspend_done || !sgen_is_thread_in_current_stw (info, &reason)) {
				THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE RESUME thread %p not been processed done %d current %d reason %d\n", mono_thread_info_get_tid (info), info->client_info.suspend_done, !sgen_is_thread_in_current_stw (info, NULL), reason);
				continue;
			}

			/*
			All threads that reach here are pristine suspended. This means the following:

			- We haven't accepted the previous suspend as good.
			- We haven't gave up on it for this STW (it's either bad or asked not to)
			*/
			if (mono_thread_info_in_critical_location (info)) {
				gboolean res;
				gint suspend_count = mono_thread_info_suspend_count (info);
				if (!(suspend_count == 1))
					g_error ("[%p] suspend_count = %d, but should be 1", mono_thread_info_get_tid (info), suspend_count);
				res = mono_thread_info_begin_resume (info);
				THREADS_STW_DEBUG ("[GC-STW-RESTART] RESTART thread %p skip %d\n", mono_thread_info_get_tid (info), res);
				if (res)
					++restart_counter;
				else
					info->client_info.skip = TRUE;
			} else {
				THREADS_STW_DEBUG ("[GC-STW-RESTART] DONE thread %p deemed fully suspended\n", mono_thread_info_get_tid (info));
				g_assert (!info->client_info.in_critical_region);
				info->client_info.suspend_done = TRUE;
			}
		} FOREACH_THREAD_END

		if (restart_counter == 0)
			break;
		mono_threads_wait_pending_operations ();

		if (sleep_duration < 0) {
			mono_thread_info_yield ();
			sleep_duration = 0;
		} else {
			g_usleep (sleep_duration);
			sleep_duration += 10;
		}

		FOREACH_THREAD (info) {
			int reason = 0;
			if (info->client_info.suspend_done || !sgen_is_thread_in_current_stw (info, &reason)) {
				THREADS_STW_DEBUG ("[GC-STW-RESTART] IGNORE SUSPEND thread %p not been processed done %d current %d reason %d\n", mono_thread_info_get_tid (info), info->client_info.suspend_done, !sgen_is_thread_in_current_stw (info, NULL), reason);
				continue;
			}

			if (mono_thread_info_is_running (info)) {
				gboolean res = mono_thread_info_begin_suspend (info);
				THREADS_STW_DEBUG ("[GC-STW-RESTART] SUSPEND thread %p skip %d\n", mono_thread_info_get_tid (info), res);
				if (!res)
					info->client_info.skip = TRUE;
			}
		} FOREACH_THREAD_END

		mono_threads_wait_pending_operations ();
	}

	FOREACH_THREAD (info) {
		int reason = 0;
		if (sgen_is_thread_in_current_stw (info, &reason)) {
			MonoThreadUnwindState *state;

			THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is suspended\n", mono_thread_info_get_tid (info));
			g_assert (info->client_info.suspend_done);

			state = mono_thread_info_get_suspend_state (info);

			info->client_info.ctx = state->ctx;

			if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !state->unwind_data [MONO_UNWIND_DATA_LMF]) {
				/* thread is starting or detaching, nothing to scan here */
				info->client_info.stopped_domain = NULL;
				info->client_info.stopped_ip = NULL;
				info->client_info.stack_start = NULL;
			} else {
				/* Once we remove the old suspend code, we should move sgen to directly access the state in MonoThread */
				info->client_info.stopped_domain = (MonoDomain*) mono_thread_info_tls_get (info, TLS_KEY_DOMAIN);
				info->client_info.stopped_ip = (gpointer) (MONO_CONTEXT_GET_IP (&info->client_info.ctx));
				info->client_info.stack_start = (gpointer) ((char*)MONO_CONTEXT_GET_SP (&info->client_info.ctx) - REDZONE_SIZE);

				/* altstack signal handler, sgen can't handle them, mono-threads should have handled this. */
				if (!info->client_info.stack_start
					 || info->client_info.stack_start < info->client_info.stack_start_limit
					 || info->client_info.stack_start >= info->client_info.stack_end) {
					g_error ("BAD STACK: stack_start = %p, stack_start_limit = %p, stack_end = %p",
						info->client_info.stack_start, info->client_info.stack_start_limit, info->client_info.stack_end);
				}
			}

			binary_protocol_thread_suspend ((gpointer) mono_thread_info_get_tid (info), info->client_info.stopped_ip);
		} else {
			THREADS_STW_DEBUG ("[GC-STW-SUSPEND-END] thread %p is NOT suspended, reason %d\n", mono_thread_info_get_tid (info), reason);
			g_assert (!info->client_info.suspend_done || info == mono_thread_info_current ());
		}
	} FOREACH_THREAD_END
}
开发者ID:ItsVeryWindy,项目名称:mono,代码行数:101,代码来源:sgen-stw.c



注:本文中的MONO_CONTEXT_GET_IP函数示例由纯净天空整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
C++ MONO_OBJECT_SETREF函数代码示例发布时间:2022-05-30
下一篇:
C++ MONGO_WRITE_CONFLICT_RETRY_LOOP_END函数代码示例发布时间:2022-05-30
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap