Optimizations of "+" operand for strings in JDK 17 - dart

We know that in JDK8 and below, strings using a plus sign for concatenation will be compiled into StringBuilder for performance optimization, but after JDK9, it will be implemented using the java.lang.invoke.StringConcatFactory#makeConcatWithConstants method.
However, after decompiling java.lang.Object, it can be seen that its toString method is still implemented using StringBuilder:
public java.lang.String toString();
descriptor: ()Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: new #1 // class java/lang/StringBuilder
3: dup
4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V
7: aload_0
8: invokevirtual #7 // Method getClass:()Ljava/lang/Class;
11: invokevirtual #13 // Method java/lang/Class.getName:()Ljava/lang/String;
14: invokevirtual #19 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: ldc #23 // String #
19: invokevirtual #19 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: aload_0
23: invokevirtual #25 // Method hashCode:()I
26: invokestatic #29 // Method java/lang/Integer.toHexString:(I)Ljava/lang/String;
29: invokevirtual #19 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
32: invokevirtual #35 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
35: areturn
LineNumberTable:
line 256: 0
LocalVariableTable:
Start Length Slot Name Signature
0 36 0 this Ljava/lang/Object;
Looking through the source code, it can be seen that it still uses the plus sign to connect the three parts:
public String toString() {
return getClass().getName() + "#" + Integer.toHexString(hashCode());
}
Rewrite the same code into a class to compile:
public class Main {
public String fooString() {
return getClass().getName() + "#" + Integer.toHexString(hashCode());
}
}
It can be seen from the decompilation that it is still implemented using the java.lang.invoke.StringConcatFactory#makeConcatWithConstants method:
public java.lang.String fooString();
descriptor: ()Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
start local 0 // Main this
0: aload_0
1: invokevirtual #7 // Method java/lang/Object.getClass:()Ljava/lang/Class;
4: invokevirtual #11 // Method java/lang/Class.getName:()Ljava/lang/String;
7: aload_0
8: invokevirtual #17 // Method java/lang/Object.hashCode:()I
11: invokestatic #21 // Method java/lang/Integer.toHexString:(I)Ljava/lang/String;
14: invokedynamic #27, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
19: areturn
end local 0 // Main this
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
0 20 0 this LMain;
So why is the plus sign used in Object class implemented using StringBuilder while class A(mentioned above) using makeConcatWithConstants? Does the bytecode of the Object class provided by the JDK do not match the source code, or is there a special optimization for the Object class at compile time?

It's explained in the JEP. Emphasis mine
java.base exemptions. Since this feature uses a core library feature
(java.lang.invoke) to implement a core language feature (String
concatenation), we have to exempt the java.base module from using the
indified String concat. Otherwise a circularity happens when the
java.lang.invoke.* machinery requires String concat to work, which in
turn requires the java.lang.invoke.* machinery. This exemption may
limit the performance improvements observed from this feature, since
many java.base classes will not be able to use it. We consider this an
acceptable downside, which should be covered by the VM's optimizing
compilers.

Related

How to comprehend that "lua_Hook is called when it jumps back in the code(This event only happens while Lua is executing a Lua function.)"?

As per the documentation(https://www.lua.org/manual/5.3/manual.html#lua_sethook), which says[empasise mine]:
Argument f is the hook function. mask specifies on which events the
hook will be called: it is formed by a bitwise OR of the constants
LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE, and LUA_MASKCOUNT. The count
argument is only meaningful when the mask includes LUA_MASKCOUNT. For
each event, the hook is called as explained below:
The call hook: is called when the interpreter calls a function. The
hook is called just after Lua enters the new function, before the
function gets its arguments.
The return hook: is called when the
interpreter returns from a function. The hook is called just before
Lua leaves the function. There is no standard way to access the values
to be returned by the function.
The line hook: is called when the
interpreter is about to start the execution of a new line of code, or
when it jumps back in the code (even to the same line). (This event
only happens while Lua is executing a Lua function.)
How to comprehend that lua_Hook is called when it jumps back in the code(This event only happens while Lua is executing a Lua function?
We can look at the source (Lua 5.4):
int luaG_traceexec (lua_State *L, const Instruction *pc) {
-- some parts removed
if (mask & LUA_MASKLINE) {
if (npci == 0 || /* call linehook when enter a new function, */
pc <= L->oldpc || /* when jump back (loop), or when */
changedline(p, pcRel(L->oldpc, p), npci)) { /* enter new line */
int newline = luaG_getfuncline(p, npci);
luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */
}
}
return 1; /* keep 'trap' on */
}
As can be seen, LUA_HOOKLINE is called in three cases: (1) enter a new function, (2) jump back (loop), or (3) enter new line.
"Enter new line" is checked by a call to changedline:
static int changedline (const Proto *p, int oldpc, int newpc) {
while (oldpc++ < newpc) {
if (p->lineinfo[oldpc] != 0)
return (luaG_getfuncline(p, oldpc - 1) != luaG_getfuncline(p, newpc));
}
return 0; /* no line changes in the way */
}
This returns true if the new instruction is on a different line from the previous instruction.
luaG_getfuncline gets the line number for the instruction if there is debug information available. The function being checked is the active lua function based on the the current call info value.

Bad state: type '_SpecialTypeMirror' is not a subtype of type 'ClassMirror' in type cast

I'm trying to run the aqueduct's command to generate the DB.
aqueduct db generate
but I always receive this error:
Bad state: type '_SpecialTypeMirror' is not a subtype of type 'ClassMirror' in type cast
I'm using the model like this:
import 'package:aqueduct/aqueduct.dart';
import 'package:controle_rural_api/models/Farm.dart';
class User extends ManagedObject implements _User{}
class _User {
#primaryKey
int id;
String otherThings;
bool active;
ManagedSet<Farm> farms;
}
That is the complete error:
*** Uncaught error
Bad state: type '_SpecialTypeMirror' is not a subtype of type 'ClassMirror' in type cast
**** Stacktrace
* #0 EntityBuilder._getTableDefinitionForType (package:aqueduct/src/db/managed/builders/entity_builder.dart:236:16)
* #1 new EntityBuilder (package:aqueduct/src/db/managed/builders/entity_builder.dart:16:31)
* #2 new DataModelBuilder.<anonymous closure> (package:aqueduct/src/db/managed/builders/data_model_builder.dart:7:42)
* #3 MappedListIterable.elementAt (dart:_internal/iterable.dart:414:29)
* #4 ListIterable.toList (dart:_internal/iterable.dart:219:19)
* #5 new DataModelBuilder (package:aqueduct/src/db/managed/builders/data_model_builder.dart:7:71)
* #6 new ManagedDataModel.fromCurrentMirrorSystem (package:aqueduct/src/db/managed/data_model.dart:46:9)
* #7 MigrationBuilderExecutable.execute (<data:application/dart>:13:557)
* <asynchronous suspension>
* #8 main (<data:application/dart>:9:35)
* <asynchronous suspension>
* #9 _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:296:32)
* #10 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
****
Don't look be anything about my code, but I can't generate the code, What can be?
I found the error. Was in the generics.
In the class User extends ManagedObject implements _User{} I forgot the type, so should be like this: class User extends ManagedObject<_User> implements _User{}

Dart Polymer error 'List' is not a subtype of type 'ObservableList' of 'value'

I am using core-ajax-dart to fetch some data and put it in core-list-dart. And i keep getting this error. I am able to successfully pass heading which is String but I am not able to pass contacts. It fails with the following error
Exception: Uncaught Error: type 'List' is not a subtype of type
'ObservableList' of 'value'.
main page
<core-ajax-dart auto id="_ajax" url="https://polymer-contacts.firebaseio.com/{{category}}.json" handleAs="json"></core-ajax-dart>
<contacts-page class="page" id="contacts" contacts="{{contacts}}" heading="{{heading}}" flex></contacts-page>
List contacts;
ContactsPage cp = $['contacts'] as ContactsPage;
var ajax = $['_ajax'] as CoreAjax;
ajax.on["core-response"].listen((event) {
var detail = event.detail;
var response = detail['response'];
cp.contacts = response;
});
element definition
<div id="title" flex>{{heading}}</div>
<core-list-dart id="list" data="{{contacts}}">
#published List contacts;
#published String heading;
Stack trace:
Exception: Uncaught Error: type 'List' is not a subtype of type 'ObservableList' of 'value'.
Stack Trace:
#0 CoreList.data= (package:core_elements/core_list_dart.dart:48:124)
#1 main.<anonymous closure> (http://localhost:8080/index.html_bootstrap.dart:114:27)
#2 GeneratedObjectAccessorService.write (package:smoke/static.dart:114:11)
#3 write (package:smoke/smoke.dart:34:40)
#4 _updateNode (package:polymer/src/instance.dart:1412:16)
#5 _convertAndCheck (package:polymer_expressions/polymer_expressions.dart:302:16)
#6 _RootZone.runUnaryGuarded (dart:async/zone.dart:1093)
#7 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341)
#8 _DelayedData.perform (dart:async/stream_impl.dart:595)
#9 _StreamImplEvents.handleNext (dart:async/stream_impl.dart:711)
#10 _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:671)
#11 _asyncRunCallbackLoop (dart:async/schedule_microtask.dart:41)
#12 _asyncRunCallback (dart:async/schedule_microtask.dart:48)
#13 _handleMutation (dart:html:41817)
Almost full source
The data attribute of <core-list-dart> requires an ObservableList instead of List.
What you can do is to change the field to a getter/setter where a passed List is automatically converted to a ObservableList like
class Model extends Object with Observable {
// or class SomeElement extends PolymerElement {
ObservableList _contacts;
#observable ObservableList get contacts => _contacts;
set contacts(List contacts) {
final old = _contacts;
if(contacts is ObservableList) {
_contacts = contacts;
}
_contacts = toObservable(contacts);
notifyPropertyChange(#contacts, old, _contacts);
}
}

Why the implementation of ARC's objc_autoreleaseReturnValue differs for x86_64 and ARM?

After reading the excellent blog post by Mike Ash "Friday Q&A 2014-05-09: When an Autorelease Isn't" on ARC, I decided to check out the details of the optimisations that ARC applies to speed up the retain/release process.
The trick I'm referring to is called "Fast autorelease" in which the caller and callee cooperate to keep the returned object out of the autorelease pool. This works best in situation like the following:
- (id) myMethod {
id obj = [MYClass new];
return [obj autorelease];
}
- (void) mainMethod {
obj = [[self myMethod] retain];
// Do something with obj
[obj release];
}
that can be optimised by skipping the autorelease pool completely:
- (id) myMethod {
id obj = [MYClass new];
return obj;
}
- (void) mainMethod {
obj = [self myMethod];
// Do something with obj
[obj release];
}
The way this optimisation is implemented is very interesting. I quote from Mike's post:
"There is some extremely fancy and mind-bending code in the Objective-C runtime's implementation of autorelease. Before actually sending an autorelease message, it first inspects the caller's code. If it sees that the caller is going to immediately call objc_retainAutoreleasedReturnValue, it completely skips the message send. It doesn't actually do an autorelease at all. Instead, it just stashes the object in a known location, which signals that it hasn't sent autorelease at all."
So far so good. The implementation for x86_64 on NSObject.mm is quite straightforward. The code analyses the assembler located after the return address of objc_autoreleaseReturnValue for the presence of a call to objc_retainAutoreleasedReturnValue.
static bool callerAcceptsFastAutorelease(const void * const ra0)
{
const uint8_t *ra1 = (const uint8_t *)ra0;
const uint16_t *ra2;
const uint32_t *ra4 = (const uint32_t *)ra1;
const void **sym;
//1. Navigate the DYLD stubs to get to the real pointer of the function to be called
// 48 89 c7 movq %rax,%rdi
// e8 callq symbol
if (*ra4 != 0xe8c78948) {
return false;
}
ra1 += (long)*(const int32_t *)(ra1 + 4) + 8l;
ra2 = (const uint16_t *)ra1;
// ff 25 jmpq *symbol#DYLDMAGIC(%rip)
if (*ra2 != 0x25ff) {
return false;
}
ra1 += 6l + (long)*(const int32_t *)(ra1 + 2);
sym = (const void **)ra1;
//2. Check that the code to be called belongs to objc_retainAutoreleasedReturnValue
if (*sym != objc_retainAutoreleasedReturnValue)
{
return false;
}
return true;
}
But when it comes to ARM, I just can't understand how it works. The code looks like this (I've simplified a little bit):
static bool callerAcceptsFastAutorelease(const void *ra)
{
// 07 70 a0 e1 mov r7, r7
if (*(uint32_t *)ra == 0xe1a07007) {
return true;
}
return false;
}
It looks like the code is identifying the presence of objc_retainAutoreleasedReturnValue not by looking up the presence of a call to that specific function, but by looking instead for a special no-op operation mov r7, r7.
Diving into LLVM source code I found the following explanation:
"The implementation of objc_autoreleaseReturnValue sniffs the instruction stream following its return address to decide whether it's a call to objc_retainAutoreleasedReturnValue. This can be prohibitively expensive, depending on the relocation model, and so on some targets it instead sniffs for a particular instruction sequence. This functions returns that instruction sequence in inline assembly, which will be empty if none is required."
I was wondering why is that so on ARM?
Having the compiler put there a certain marker so that a specific implementation of a library can find it sounds like a strong coupling between compiler and the library code. Why can't the "sniffing" be implemented the same way as on the x86_64 platform?
IIRC (been a while since I've written ARM assembly), ARM's addressing modes don't really allow for direct addressing across the full address space. The instructions used to do addressing -- loads, stores, etc... -- don't support direct access to the full address space as they are limited in bit width.
Thus, any kind of go to this arbitrary address and check for that value, then use that value to go look over there will be significantly slower on ARM as you have to use indirect addressing which involves math and... math eats CPU cycles.
By having a compiler emit a NO-OP instruction that can easily be checked, it eliminates the need for indirection through the DYLD stubs.
At least, I'm pretty sure that is what is going on. Two ways to know for sure; take the code for those two functions and compile it with -Os for x86_64 vs. ARM and see what the resulting instruction streams look like (i.e. both functions on each architecture) or wait until Greg Parker shows up to correct this answer.

Fitnesse slim: Call generic method (fitSharp)

Linux 3.2.0-3-amd64 #1 SMP Mon Jul 23 02:45:17 UTC 2012 x86_64 GNU/Linux
Mono 2.10.8.1 (Debian 2.10.8.1-7) (64-bit)
glib-sharp 2.12.0.0
FitNesse (v20121220)
FitSharp release 2.2 for .net 4.0
I have a C# fixture that contains the following generic method
public Func<T> GetProcedure<T>(string name)
{
return () => default(T);
}
Question: How do I call GetProcedure from a Slim script table?
| show | GetProcedure; <?specify type here?> | text |
I found the following test in the source code, so it should be possible. However, I don't know how to define the type T within the script table so that slim can parse it...
https://github.com/jediwhale/fitsharp/blob/master/source/fitSharpTest/NUnit/Machine/MemberQueryTest.cs
[Test] public void GenericMethodWithParmsIsInvoked() {
var member = new MemberName("genericmethodofsystemint32", "genericmethod", new[] { typeof(int)});
var method = MemberQuery.FindInstance(MemberQuery.FindMember, instance, new MemberSpecification(member, 1));
Assert.IsNotNull(method);
var result = method.Invoke(new object[] {123});
Assert.AreEqual("sample123", result.Value.ToString());
}
// This method found via the reflection above.
// see: fitSharp.Test.Double.SampleClass
public string GenericMethod<T>(T input) {
return "sample" + input;
}
Unfortunately generic methods are not supported in Slim. If you're using the Fit test system, you'd say 'getprocedure of mytype' as the method name.

Resources