def write_method(self): access = util.get_access_method(self.method.get_access_flags()) class_name = self.method.get_class_name() _, name, proto = self.method.get_triple() jni_name = JniLongName(class_name, name, proto) self.write("\n/* %s->%s%s */\n" % (class_name, name, proto)) self.write('extern "C" JNIEXPORT %s JNICALL\n' % get_native_type(self.irmethod.rtype)) self.write(jni_name) params = self.irmethod.params if 'static' not in access: params = params[1:] proto = '' if self.irmethod.params_type: proto = ', '.join(['%s p%s' % (get_native_type(p_type), param) for p_type, param in zip(self.irmethod.params_type, params)]) if proto: self.write('(JNIEnv *env, jobject thiz, %s)' % proto) else: self.write('(JNIEnv *env, jobject thiz)') self.write('{\n') nodes = self.irmethod.irblocks for node in nodes: self.visit_node(node) for lp in self.irmethod.landing_pads: self.write('\n') self.visit_landing_pad(lp) return_type = self.irmethod.rtype if return_type[0] != 'V': if return_type[0] == 'L': self.write("EX_UnwindBlock: return NULL;\n") else: self.write("EX_UnwindBlock: return (%s)0;\n" % (get_native_type(return_type))) else: self.write("EX_UnwindBlock: return;\n") self.write('}\n')
def visit_put_static(self, ins, clsdesc, name, ftype, rhs): self.write_trace(ins) self.write('{\n') self.write_define_ex_handle(ins) self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class()))) self.write('jfieldID &fld = %s;\n' % (self.fa(ins.get_field()))) self.write('D2C_RESOLVE_STATIC_FIELD(clz, fld, "%s", "%s", "%s");\n' % (get_type(clsdesc), name, ftype)) self.write('env->SetStatic%sField(clz,fld,(%s) %s);\n' % ( get_type_descriptor(ftype), get_native_type(ftype), self.get_variable_or_const(rhs))) self.write_undefine_ex_handle(ins) self.write('}\n')
def _invoke_common(self, ins, invoke_type, name, base, ptype, rtype, args, clsdesc): self.write('{\n') self.write_define_ex_handle(ins) if invoke_type != 'static': self.write("D2C_NOT_NULL(v%s);\n" % (self.ra(base))) self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class()))) self.write('jmethodID &mid = %s;\n' % (self.ma(ins.get_call_method()))) if invoke_type != 'static': self.write('D2C_RESOLVE_METHOD(clz, mid, "%s", "%s", "(%s)%s");\n' % (get_type(clsdesc), name, ''.join(ptype), rtype)) else: self.write('D2C_RESOLVE_STATIC_METHOD(clz, mid, "%s", "%s", "(%s)%s");\n' % (get_type(clsdesc), name, ''.join(ptype), rtype)) self.write('jvalue args[] = {') vars = [] for arg, atype in zip(args, ptype): if atype[0] == 'L' or atype[0] == '[': vars.append('{.l = %s}' % (self.get_variable_or_const(arg))) elif atype[0] == 'Z': vars.append('{.z = (jboolean) %s}' % (self.get_variable_or_const(arg))) elif atype[0] == 'B': vars.append('{.b = (jbyte) %s}' % (self.get_variable_or_const(arg))) elif atype[0] == 'C': vars.append('{.c = (jchar) %s}' % (self.get_variable_or_const(arg))) elif atype[0] == 'S': vars.append('{.s = (jshort) %s}' % (self.get_variable_or_const(arg))) elif atype[0] == 'I': vars.append('{.i = %s}' % (self.get_variable_or_const(arg))) elif atype[0] == 'J': vars.append('{.j = (jlong) %s}' % (self.get_variable_or_const(arg))) elif atype[0] == 'F': vars.append('{.f = %s}' % (self.get_variable_or_const(arg))) elif atype[0] == 'D': vars.append('{.d = %s}' % (self.get_variable_or_const(arg))) else: raise Exception("Unknow signuare type %s" % (atype)) self.write(','.join(vars)) self.write('};\n') if rtype != 'V': self.write_kill_local_reference(ins.get_value()) ins.get_value().visit(self) self.write(' = ') self.write("(%s) " % (get_native_type(ins.get_value().get_type()))) if invoke_type == 'super': self.write( 'env->CallNonvirtual%sMethodA(v%s, clz, mid, args);\n' % (get_type_descriptor(rtype), self.ra(base))) elif invoke_type == 'static': self.write('env->CallStatic%sMethodA(clz, mid, args);\n' % (get_type_descriptor(rtype))) else: self.write('env->Call%sMethodA(v%s, mid, args);\n' % (get_type_descriptor(rtype), self.ra(base))) self.write_undefine_ex_handle(ins) self.write('}\n') if rtype != 'V': self.write_delete_dead_local_reference(ins.get_value())
def visit_astore(self, ins, array, index, rhs): self.write_trace(ins) self.write('{\n') self.write_define_ex_handle(ins) self.write_not_null(array) elem_type = ins.get_elem_type() if is_primitive_type(elem_type): self.write('{%s val = %s;' % (get_native_type(elem_type), self.get_variable_or_const(rhs))) self.write('env->Set%sArrayRegion((%sArray) v%s, (jint) %s, 1, &val);' % (get_type_descriptor(elem_type), get_native_type(elem_type), self.ra(array), self.get_variable_or_const(index))) self.write('}\n') else: self.write('env->SetObjectArrayElement((jobjectArray) v%s, (jint) %s, v%s);' % (self.ra(array), self.get_variable_or_const(index), self.ra(rhs))) self.write_undefine_ex_handle(ins) self.write('}\n')
def write_kill_local_reference(self, val, tmp=False): if val is None: return if get_native_type(val.get_type()) in ('jarray', 'jobject', 'jstring'): if tmp or val.get_register() >= 0: reg = self.ra(val) self.write('if (v%s) {\n' % (reg)) self.write('LOGD("env->DeleteLocalRef(%%p):v%s", v%s);\n' % (reg, reg)) self.write('env->DeleteLocalRef(v%s);\n' % reg) self.write('}\n')
def visit_aload(self, ins, result, array, index): self.write_trace(ins) self.write('{\n') self.write_define_ex_handle(ins) self.write_not_null(array) elem_type = ins.get_elem_type() if is_primitive_type(elem_type): self.write('{%s val;' % (get_native_type(elem_type))) self.write('env->Get%sArrayRegion((%sArray) v%s, (jint) %s, 1, &val);' % (get_type_descriptor(elem_type), get_native_type(elem_type), self.ra(array), self.get_variable_or_const(index))) self.write('v%s = val;}' % (self.ra(result))) else: self.write_kill_local_reference(result) self.write('v%s = (%s) env->GetObjectArrayElement((jobjectArray) v%s, (jint) %s);' % (self.ra(result), get_native_type(result.get_type()), self.ra(array), self.get_variable_or_const(index))) self.write('\n') self.write_undefine_ex_handle(ins) self.write('}\n')
def visit_new(self, ins, result, atype): self.write_trace(ins) self.write('{\n') self.write_define_ex_handle(ins) # should kill local reference after D2C_RESOLVE_CLASS, since D2C_RESOLVE_CLASS may throw exception, # so this ref may be double killed in exception handle. self.write_kill_local_reference(ins.get_value()) self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class()))) self.write('D2C_RESOLVE_CLASS(clz,"%s");\n' % (get_type(atype))) self.write('v%s = (%s) env->AllocObject(clz);\n' % (self.ra(result), get_native_type(result.get_type()))) self.write_undefine_ex_handle(ins) self.write('}\n')
def visit_get_static(self, ins, result, ftype, clsdesc, name): self.write_trace(ins) self.write('{\n') self.write_define_ex_handle(ins) self.write_kill_local_reference(result) self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class()))) self.write('jfieldID &fld = %s;\n' % (self.fa(ins.get_field()))) self.write('D2C_RESOLVE_STATIC_FIELD(clz, fld, "%s", "%s", "%s");\n' % (get_type(clsdesc), name, ftype)) result.visit(self) self.write(' = (%s) env->GetStatic%sField(clz,fld);\n' % ( get_native_type(result.get_type()), get_type_descriptor(ftype))) self.write_undefine_ex_handle(ins) self.write('}\n')
def visit_fill_array(self, ins, array, value): self.write_trace(ins) self.write('{\n') self.write('static const unsigned char data[] = {') data = value.get_data() tab = [] elem_id = 'B' elem_size = 1 for i in range(0, value.size * value.element_width, elem_size): tab.append('%s' % unpack(elem_id, data[i:i + elem_size])[0]) self.write(', '.join(tab)) self.write('};\n') elem_type = array.get_type()[1:] array_size = value.size self.write( 'env->Set%sArrayRegion((%sArray) v%s, 0, %d, (const %s *) data);\n' % (get_type_descriptor(elem_type), \ get_native_type(elem_type), self.ra(array), \ array_size, get_native_type(elem_type))) self.write('}\n')
def visit_new_array(self, ins, result, atype, size): self.write_trace(ins) elem_type = ins.get_elem_type() self.write('{\n') self.write_define_ex_handle(ins) self.write_check_array_size(size) self.write_kill_local_reference(ins.get_value()) if is_primitive_type(elem_type): result.visit(self) self.write( ' = (%s) env->New%sArray((jint) %s);\n' % ( get_native_type(result.get_type()), get_type_descriptor(elem_type), self.get_variable_or_const(size))) else: self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class()))) self.write('D2C_RESOLVE_CLASS(clz,"%s");\n' % (get_type(elem_type))) result.visit(self) self.write(' = env->NewObjectArray((jint) %s, clz, NULL);\n' % (self.get_variable_or_const(size))) self.write_undefine_ex_handle(ins) self.write('}\n')
def visit_load_constant(self, ins): val = ins.get_value() atype = val.get_type() self.write_trace(ins) self.write_kill_local_reference(val) cst = ins.get_cst().get_constant() cst_type = ins.get_cst().get_type() if atype == 'F': self.write('v%s = d2c_bitcast_to_float(%r);\n' % (self.ra(val), cst)) elif atype == 'D': self.write('v%s = d2c_bitcast_to_double(%r);\n' % (self.ra(val), cst)) elif cst_type == 'Ljava/lang/String;': self.write( 'v%s = (%s) env->NewStringUTF("%s");\n' % (self.ra(val), get_native_type(atype), cst)) elif cst_type == 'Ljava/lang/Class;': self.write('{\n') self.write_define_ex_handle(ins) self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class()))) self.write('D2C_RESOLVE_CLASS(clz,"%s");\n' % (cst)) self.write('v%s = env->NewLocalRef(clz);\n' % (self.ra(val))) self.write_undefine_ex_handle(ins) self.write('}\n') else: self.write('v%s = %r;\n' % (self.ra(val), cst))
def visit_return(self, arg): return_type = self.irmethod.rtype if return_type[0] != 'V': self.write("return (%s) %s;\n" % (get_native_type(return_type), self.get_variable_or_const(arg))) else: self.write('return;')
def visit_param(self, param): decl_type = get_native_type(param.get_type()) if decl_type in ('jstring', 'jobject', 'jarray'): self.write('env->NewLocalRef(p%s)' % (param.get_register())) else: self.write('p%s' % param.get_register())