void ConstantPoolCacheEntry::set_method_handle_common(constantPoolHandle cpool,
                                                      Bytecodes::Code invoke_code,
                                                      const CallInfo &call_info) {
  // NOTE: This CPCE can be the subject of data races.
  // There are three words to update: flags, refs[f2], f1 (in that order).
  // Writers must store all other values before f1.
  // Readers must test f1 first for non-null before reading other fields.
  // Competing writers must acquire exclusive access via a lock.
  // A losing writer waits on the lock until the winner writes f1 and leaves
  // the lock, so that when the losing writer returns, he can use the linked
  // cache entry.

  MonitorLockerEx ml(cpool->lock());
  if (!is_f1_null()) {
    return;
  }

  const methodHandle adapter = call_info.resolved_method();
  const Handle appendix      = call_info.resolved_appendix();
  const Handle method_type   = call_info.resolved_method_type();
  const bool has_appendix    = appendix.not_null();
  const bool has_method_type = method_type.not_null();

  // Write the flags.
  set_method_flags(as_TosState(adapter->result_type()),
                   ((has_appendix    ? 1 : 0) << has_appendix_shift   ) |
                   ((has_method_type ? 1 : 0) << has_method_type_shift) |
                   (                   1      << is_final_shift       ),
                   adapter->size_of_parameters());

  if (TraceInvokeDynamic) {
    tty->print_cr("set_method_handle bc=%d appendix="PTR_FORMAT"%s method_type="PTR_FORMAT"%s method="PTR_FORMAT" ",
                  invoke_code,
                  (void *)appendix(),    (has_appendix    ? "" : " (unused)"),
                  (void *)method_type(), (has_method_type ? "" : " (unused)"),
                  (intptr_t)adapter());
    adapter->print();
    if (has_appendix)  appendix()->print();
  }

  // Method handle invokes and invokedynamic sites use both cp cache words.
  // refs[f2], if not null, contains a value passed as a trailing argument to the adapter.
  // In the general case, this could be the call site's MethodType,
  // for use with java.lang.Invokers.checkExactType, or else a CallSite object.
  // f1 contains the adapter method which manages the actual call.
  // In the general case, this is a compiled LambdaForm.
  // (The Java code is free to optimize these calls by binding other
  // sorts of methods and appendices to call sites.)
  // JVM-level linking is via f1, as if for invokespecial, and signatures are erased.
  // The appendix argument (if any) is added to the signature, and is counted in the parameter_size bits.
  // Even with the appendix, the method will never take more than 255 parameter slots.
  //
  // This means that given a call site like (List)mh.invoke("foo"),
  // the f1 method has signature '(Ljl/Object;Ljl/invoke/MethodType;)Ljl/Object;',
  // not '(Ljava/lang/String;)Ljava/util/List;'.
  // The fact that String and List are involved is encoded in the MethodType in refs[f2].
  // This allows us to create fewer method oops, while keeping type safety.
  //

  objArrayHandle resolved_references = cpool->resolved_references();
  // Store appendix, if any.
  if (has_appendix) {
    const int appendix_index = f2_as_index() + _indy_resolved_references_appendix_offset;
    assert(appendix_index >= 0 && appendix_index < resolved_references->length(), "oob");
    assert(resolved_references->obj_at(appendix_index) == NULL, "init just once");
    resolved_references->obj_at_put(appendix_index, appendix());
  }

  // Store MethodType, if any.
  if (has_method_type) {
    const int method_type_index = f2_as_index() + _indy_resolved_references_method_type_offset;
    assert(method_type_index >= 0 && method_type_index < resolved_references->length(), "oob");
    assert(resolved_references->obj_at(method_type_index) == NULL, "init just once");
    resolved_references->obj_at_put(method_type_index, method_type());
  }

  release_set_f1(adapter());  // This must be the last one to set (see NOTE above)!

  // The interpreter assembly code does not check byte_2,
  // but it is used by is_resolved, method_if_resolved, etc.
  set_bytecode_1(invoke_code);
  NOT_PRODUCT(verify(tty));
  if (TraceInvokeDynamic) {
    this->print(tty, 0);
  }
}
Esempio n. 2
0
void ConstantPoolCacheEntry::set_method_handle_common(constantPoolHandle cpool,
                                                      Bytecodes::Code invoke_code,
                                                      methodHandle adapter,
                                                      Handle appendix, Handle method_type) {
  // NOTE: This CPCE can be the subject of data races.
  // There are three words to update: flags, f2, f1 (in that order).
  // Writers must store all other values before f1.
  // Readers must test f1 first for non-null before reading other fields.
  // Competing writers must acquire exclusive access via a lock.
  // A losing writer waits on the lock until the winner writes f1 and leaves
  // the lock, so that when the losing writer returns, he can use the linked
  // cache entry.

  Thread* THREAD = Thread::current();
  ObjectLocker ol(cpool, THREAD);
  if (!is_f1_null()) {
    return;
  }

  const bool has_appendix    = appendix.not_null();
  const bool has_method_type = method_type.not_null();

  if (!has_appendix) {
    // The extra argument is not used, but we need a non-null value to signify linkage state.
    // Set it to something benign that will never leak memory.
    appendix = Universe::void_mirror();
  }

  // Write the flags.
  set_method_flags(as_TosState(adapter->result_type()),
                   ((has_appendix    ? 1 : 0) << has_appendix_shift)    |
                   ((has_method_type ? 1 : 0) << has_method_type_shift) |
                   (                   1      << is_vfinal_shift)       |
                   (                   1      << is_final_shift),
                   adapter->size_of_parameters());

  if (TraceInvokeDynamic) {
    tty->print_cr("set_method_handle bc=%d appendix="PTR_FORMAT"%s method_type="PTR_FORMAT"%s method="PTR_FORMAT" ",
                  invoke_code,
                  (intptr_t)appendix(),    (has_appendix    ? "" : " (unused)"),
                  (intptr_t)method_type(), (has_method_type ? "" : " (unused)"),
                  (intptr_t)adapter());
    adapter->print();
    if (has_appendix)  appendix()->print();
  }

  // Method handle invokes and invokedynamic sites use both cp cache words.
  // f1, if not null, contains a value passed as a trailing argument to the adapter.
  // In the general case, this could be the call site's MethodType,
  // for use with java.lang.Invokers.checkExactType, or else a CallSite object.
  // f2 contains the adapter method which manages the actual call.
  // In the general case, this is a compiled LambdaForm.
  // (The Java code is free to optimize these calls by binding other
  // sorts of methods and appendices to call sites.)
  // JVM-level linking is via f2, as if for invokevfinal, and signatures are erased.
  // The appendix argument (if any) is added to the signature, and is counted in the parameter_size bits.
  // In principle this means that the method (with appendix) could take up to 256 parameter slots.
  //
  // This means that given a call site like (List)mh.invoke("foo"),
  // the f2 method has signature '(Ljl/Object;Ljl/invoke/MethodType;)Ljl/Object;',
  // not '(Ljava/lang/String;)Ljava/util/List;'.
  // The fact that String and List are involved is encoded in the MethodType in f1.
  // This allows us to create fewer method oops, while keeping type safety.
  //

  set_f2_as_vfinal_method(adapter());

  // Store MethodType, if any.
  if (has_method_type) {
    ConstantPoolCacheEntry* e2 = cpool->cache()->find_secondary_entry_for(this);

    // Write the flags.
    e2->set_method_flags(as_TosState(adapter->result_type()),
                     ((has_method_type ? 1 : 0) << has_method_type_shift) |
                     (                   1      << is_vfinal_shift)       |
                     (                   1      << is_final_shift),
                     adapter->size_of_parameters());
    e2->release_set_f1(method_type());
  }

  assert(appendix.not_null(), "needed for linkage state");
  release_set_f1(appendix());  // This must be the last one to set (see NOTE above)!

  if (!is_secondary_entry()) {
    // The interpreter assembly code does not check byte_2,
    // but it is used by is_resolved, method_if_resolved, etc.
    set_bytecode_2(invoke_code);
  }

  NOT_PRODUCT(verify(tty));
  if (TraceInvokeDynamic) {
    this->print(tty, 0);
  }
}