static dispex_data_t *preprocess_dispex_data(DispatchEx *This) { const tid_t *tid; dispex_data_t *data; DWORD size = 16, i; ITypeInfo *dti; HRESULT hres; TRACE("(%p)\n", This); if(This->data->disp_tid) { hres = get_typeinfo(This->data->disp_tid, &dti); if(FAILED(hres)) { ERR("Could not get disp type info: %08x\n", hres); return NULL; } } data = heap_alloc(sizeof(dispex_data_t)); if (!data) { ERR("Out of memory\n"); return NULL; } data->func_cnt = 0; data->func_disp_cnt = 0; data->funcs = heap_alloc_zero(size*sizeof(func_info_t)); if (!data->funcs) { heap_free (data); ERR("Out of memory\n"); return NULL; } list_add_tail(&dispex_data_list, &data->entry); for(tid = This->data->iface_tids; *tid; tid++) { hres = process_interface(data, *tid, dti, &size); if(FAILED(hres)) break; } if(This->data->additional_tid) process_interface(data, This->data->additional_tid, NULL, &size); if(!data->func_cnt) { heap_free(data->funcs); data->name_table = NULL; data->funcs = NULL; return data; } data->funcs = heap_realloc(data->funcs, data->func_cnt * sizeof(func_info_t)); qsort(data->funcs, data->func_cnt, sizeof(func_info_t), dispid_cmp); data->name_table = heap_alloc(data->func_cnt * sizeof(func_info_t*)); for(i=0; i < data->func_cnt; i++) data->name_table[i] = data->funcs+i; qsort(data->name_table, data->func_cnt, sizeof(func_info_t*), func_name_cmp); return data; }
void CHA::process_interface(instanceKlassHandle r, GrowableArray<KlassHandle>* receivers, GrowableArray<methodHandle>* methods, symbolHandle name, symbolHandle signature) { // recursively add non-abstract implementors of interface r to receivers list assert(r->is_interface(), "should call process_class instead"); // We only store the implementors for an interface, if there is exactly one implementor klassOop k = r->implementor(); assert(k == NULL || r->nof_implementors() == 1, "inconsistent implementor list"); if (k != NULL && !methods->is_full()) { instanceKlass* kl = instanceKlass::cast(k); assert(kl->oop_is_instance(), "primitive klasses don't implement interfaces"); assert(!kl->is_interface(), "must be a real klass"); process_class(kl, receivers, methods, name, signature); } // now process all subinterfaces for (Klass* s = r->subklass(); s != NULL && !methods->is_full(); s = s->next_sibling()) { assert(s->is_interface(), "must be an interface"); instanceKlassHandle sub(s->as_klassOop()); process_interface(sub, receivers, methods, name, signature); if (methods->is_full()) break; // give up -- too many overriding methods } }
/** Process endpoint descriptor. * * @param mapping Endpoint mapping list. * @param mapping_count Number of endpoint mappings in @p mapping. * @param interface Interface descriptor under which belongs the @p endpoint. * @param endpoint Endpoint descriptor. * @return Error code. */ static int process_endpoint( usb_endpoint_mapping_t *mapping, size_t mapping_count, usb_standard_interface_descriptor_t *interface, usb_standard_endpoint_descriptor_t *endpoint_desc, usb_dev_session_t *bus_session) { /* * Get endpoint characteristics. */ /* Actual endpoint number is in bits 0..3 */ const usb_endpoint_t ep_no = endpoint_desc->endpoint_address & 0x0F; const usb_endpoint_description_t description = { /* Endpoint direction is set by bit 7 */ .direction = (endpoint_desc->endpoint_address & 128) ? USB_DIRECTION_IN : USB_DIRECTION_OUT, /* Transfer type is in bits 0..2 and * the enum values corresponds 1:1 */ .transfer_type = endpoint_desc->attributes & 3, /* Get interface characteristics. */ .interface_class = interface->interface_class, .interface_subclass = interface->interface_subclass, .interface_protocol = interface->interface_protocol, }; /* * Find the most fitting mapping and initialize the pipe. */ usb_endpoint_mapping_t *ep_mapping = find_endpoint_mapping(mapping, mapping_count, &description, interface->interface_number, interface->alternate_setting); if (ep_mapping == NULL) { return ENOENT; } if (ep_mapping->present) { return EEXIST; } int rc = usb_pipe_initialize(&ep_mapping->pipe, ep_no, description.transfer_type, ED_MPS_PACKET_SIZE_GET( uint16_usb2host(endpoint_desc->max_packet_size)), description.direction, ED_MPS_TRANS_OPPORTUNITIES_GET( uint16_usb2host(endpoint_desc->max_packet_size)), bus_session); if (rc != EOK) { return rc; } ep_mapping->present = true; ep_mapping->descriptor = endpoint_desc; ep_mapping->interface = interface; return EOK; } /** Process whole USB interface. * * @param mapping Endpoint mapping list. * @param mapping_count Number of endpoint mappings in @p mapping. * @param parser Descriptor parser. * @param parser_data Descriptor parser data. * @param interface_descriptor Interface descriptor. * @return Error code. */ static int process_interface( usb_endpoint_mapping_t *mapping, size_t mapping_count, const usb_dp_parser_t *parser, const usb_dp_parser_data_t *parser_data, const uint8_t *interface_descriptor, usb_dev_session_t *bus_session) { const uint8_t *descriptor = usb_dp_get_nested_descriptor(parser, parser_data, interface_descriptor); if (descriptor == NULL) { return ENOENT; } do { if (is_endpoint_descriptor(descriptor)) { (void) process_endpoint(mapping, mapping_count, (usb_standard_interface_descriptor_t *) interface_descriptor, (usb_standard_endpoint_descriptor_t *) descriptor, bus_session); } descriptor = usb_dp_get_sibling_descriptor(parser, parser_data, interface_descriptor, descriptor); } while (descriptor != NULL); return EOK; } /** Initialize endpoint pipes from configuration descriptor. * * The mapping array is expected to conform to following rules: * - @c pipe must be uninitialized pipe * - @c description must point to prepared endpoint description * - @c descriptor does not need to be initialized (will be overwritten) * - @c interface does not need to be initialized (will be overwritten) * - @c present does not need to be initialized (will be overwritten) * * After processing the configuration descriptor, the mapping is updated * in the following fashion: * - @c present will be set to @c true when the endpoint was found in the * configuration * - @c descriptor will point inside the configuration descriptor to endpoint * corresponding to given description (or NULL for not found descriptor) * - @c interface will point inside the configuration descriptor to interface * descriptor the endpoint @c descriptor belongs to (or NULL for not found * descriptor) * - @c pipe will be initialized when found, otherwise left untouched * - @c description will be untouched under all circumstances * * @param mapping Endpoint mapping list. * @param mapping_count Number of endpoint mappings in @p mapping. * @param configuration_descriptor Full configuration descriptor (is expected * to be in USB endianness: i.e. as-is after being retrieved from * the device). * @param configuration_descriptor_size Size of @p configuration_descriptor * in bytes. * @param connection Connection backing the endpoint pipes. * @return Error code. */ int usb_pipe_initialize_from_configuration( usb_endpoint_mapping_t *mapping, size_t mapping_count, const uint8_t *config_descriptor, size_t config_descriptor_size, usb_dev_session_t *bus_session) { if (config_descriptor == NULL) return EBADMEM; if (config_descriptor_size < sizeof(usb_standard_configuration_descriptor_t)) { return ERANGE; } /* Go through the mapping and set all endpoints to not present. */ for (size_t i = 0; i < mapping_count; i++) { mapping[i].present = false; mapping[i].descriptor = NULL; mapping[i].interface = NULL; } /* Prepare the descriptor parser. */ const usb_dp_parser_t dp_parser = { .nesting = descriptor_nesting }; const usb_dp_parser_data_t dp_data = { .data = config_descriptor, .size = config_descriptor_size, }; /* * Iterate through all interfaces. */ const uint8_t *interface = usb_dp_get_nested_descriptor(&dp_parser, &dp_data, config_descriptor); if (interface == NULL) { return ENOENT; } do { (void) process_interface(mapping, mapping_count, &dp_parser, &dp_data, interface, bus_session); interface = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data, config_descriptor, interface); } while (interface != NULL); return EOK; } /** Probe default control pipe for max packet size. * * The function tries to get the correct value of max packet size several * time before giving up. * * The session on the pipe shall not be started. * * @param pipe Default control pipe. * @return Error code. */ int usb_pipe_probe_default_control(usb_pipe_t *pipe) { assert(pipe); static_assert(DEV_DESCR_MAX_PACKET_SIZE_OFFSET < CTRL_PIPE_MIN_PACKET_SIZE); if ((pipe->direction != USB_DIRECTION_BOTH) || (pipe->transfer_type != USB_TRANSFER_CONTROL) || (pipe->endpoint_no != 0)) { return EINVAL; } uint8_t dev_descr_start[CTRL_PIPE_MIN_PACKET_SIZE]; size_t transferred_size; int rc; for (size_t attempt_var = 0; attempt_var < 3; ++attempt_var) { rc = usb_request_get_descriptor(pipe, USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE, USB_DESCTYPE_DEVICE, 0, 0, dev_descr_start, CTRL_PIPE_MIN_PACKET_SIZE, &transferred_size); if (rc == EOK) { if (transferred_size != CTRL_PIPE_MIN_PACKET_SIZE) { rc = ELIMIT; continue; } break; } } if (rc != EOK) { return rc; } pipe->max_packet_size = dev_descr_start[DEV_DESCR_MAX_PACKET_SIZE_OFFSET]; return EOK; }
CHAResult* CHA::analyze_call(KlassHandle calling_klass, KlassHandle static_receiver, KlassHandle actual_receiver, symbolHandle name, symbolHandle signature) { assert(static_receiver->oop_is_instance(), "must be instance klass"); methodHandle m; // Only do exact lookup if receiver klass has been linked. Otherwise, // the vtables has not been setup, and the LinkResolver will fail. if (instanceKlass::cast(static_receiver())->is_linked() && instanceKlass::cast(actual_receiver())->is_linked()) { if (static_receiver->is_interface()) { // no point trying to resolve unless actual receiver is a klass if (!actual_receiver->is_interface()) { m = LinkResolver::resolve_interface_call_or_null(actual_receiver, static_receiver, name, signature, calling_klass); } } else { m = LinkResolver::resolve_virtual_call_or_null(actual_receiver, static_receiver, name, signature, calling_klass); } if (m.is_null()) { // didn't find method (e.g., could be abstract method) return new CHAResult(actual_receiver, name, signature, NULL, NULL, m, false); } if( Klass::can_be_statically_bound(m()) || m()->is_private() || actual_receiver->subklass() == NULL ) { // always optimize final methods, private methods or methods with no // subclasses. return new CHAResult(actual_receiver, name, signature, NULL, NULL, m); } if (!UseCHA) { // don't optimize this call return new CHAResult(actual_receiver, name, signature, NULL, NULL, m, false); } } // If the method is abstract then each non-abstract subclass must implement // the method and inlining is not possible. If there is exactly 1 subclass // then there can be only 1 implementation and we are OK. if( !m.is_null() && m()->is_abstract() ) {// Method is abstract? Klass *sr = Klass::cast(static_receiver()); if( sr == sr->up_cast_abstract() ) return new CHAResult(actual_receiver, name, signature, NULL, NULL, m, false); // Fall into the next code; it will find the one implementation // and that implementation is correct. } _used = true; GrowableArray<methodHandle>* methods = new GrowableArray<methodHandle>(CHA::max_result()); GrowableArray<KlassHandle>* receivers = new GrowableArray<KlassHandle>(CHA::max_result()); // Since 'm' is visible from the actual receiver we can call it if the // runtime receiver class does not override 'm'. if( !m.is_null() && m()->method_holder() != actual_receiver() && !m->is_abstract() ) { receivers->push(actual_receiver); methods->push(m); } if (static_receiver->is_interface()) { instanceKlassHandle sr = static_receiver(); process_interface(sr, receivers, methods, name, signature); } else { process_class(static_receiver, receivers, methods, name, signature); } methodHandle dummy; CHAResult* res = new CHAResult(actual_receiver, name, signature, receivers, methods, dummy); //res->print(); return res; }