Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » Modeling (top-level project) » StackOverflowError on EPackage Initialization
StackOverflowError on EPackage Initialization [message #522384] Mon, 22 March 2010 14:12 Go to next message
Paul Hoser is currently offline Paul Hoser
Messages: 4
Registered: March 2010
Junior Member
Hi Everybody!

I have a problem with my EMF model. I am getting a StackOverflowError
when my EPackages are initialized. My model is rather large. It consists
of about 150 packages each containing at least one classifier.

Within the init() method of an EPackage the inter-depending EPackages
are initialized recursively. The interdenpendencies of an EPackage are
calculated by the GenPackageImpl.DependencyHelper. The algorithm looks
like this:

public DependencyHelper()
{
...
interDependencies = new ArrayList<GenPackage>();
collectPackages(interDependencies, getGenModel().getGenPackages(), -1);
interDependencies.remove(GenPackageImpl.this);
...
}



protected void collectPackages(List<GenPackage> result,
List<GenPackage> genPackages, int depth)
{
if (depth == 0) return;

for (GenPackage genPackage : genPackages)
{
if (genPackage.hasClassifiers())
{
result.add(genPackage);
collectPackages(result, genPackage.getNestedGenPackages(),
depth - 1);
}
else
{
collectPackages(result, genPackage.getNestedGenPackages(), depth);
}
}
}


This basically means that all EPackages within the model which contain
classifiers are inter-depedenent to each other. If we had an example
model containing three packages (MyPackage, YourPackage, OurPackage) we
would get generated code like this:



public class MyPackageImpl extends EPackageImpl implements MyPackage
{
...
public static MyPackage init() {
...
YourPackageImpl theYourPackage = (YourPackageImpl)
(EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) instanceof
YourPackageImpl ?
EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) :
YourPackage.eINSTANCE);
OurPackageImpl theOurPackage = (OurPackageImpl)
(EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) instanceof
OurPackageImpl ?
EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) :
OurPackage.eINSTANCE);
...
}
...
}

public class YourPackageImpl extends EPackageImpl implements YourPackage
{
...
public static YourPackage init() {
...
MyPackageImpl theMyPackage = (MyPackageImpl)
(EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) instanceof
MyPackageImpl ?
EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) :
MyPackage.eINSTANCE);
OurPackageImpl theOurPackage = (OurPackageImpl)
(EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) instanceof
OurPackageImpl ?
EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) :
OurPackage.eINSTANCE);
...
}
...
}

public class OurPackageImpl extends EPackageImpl implements OurPackage
{
...
public static OurPackage init() {
...
MyPackageImpl theMyPackage = (MyPackageImpl)
(EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) instanceof
MyPackageImpl ?
EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) :
MyPackage.eINSTANCE);
YourPackageImpl theYourPackage = (YourPackageImpl)
(EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) instanceof
YourPackageImpl ?
EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) :
YourPackage.eINSTANCE);

...
}
...
}


If we would now access any of these EPackages, for instance the
MyPackage, via the eINSTANCE field all three packages would be
initialized recursively and we would get the following stacktrace:

OurPackageImpl.init() line: 655
OurPackage.<clinit>() line: 75

Unsafe.ensureClassInitialized(Class) line: not available [native
method]
UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean) line: 25
ReflectionFactory.newFieldAccessor(Field, boolean) line: 122
Field.acquireFieldAccessor(boolean) line: 918
Field.getFieldAccessor(Object) line: 899
Field.get(Object) line: 358
RegistryReader$EPackageDescriptor.getEPackage() line: 274
EPackageRegistryImpl.getEPackage(String) line: 133
YourPackageImpl.init() line: 698
YourPackage.<clinit>() line: 78

Unsafe.ensureClassInitialized(Class) line: not available [native method]
UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean) line: 25
ReflectionFactory.newFieldAccessor(Field, boolean) line: 122
Field.acquireFieldAccessor(boolean) line: 918
Field.getFieldAccessor(Object) line: 899
Field.get(Object) line: 358
RegistryReader$EPackageDescriptor.getEPackage() line: 274
EPackageRegistryImpl.getEPackage(String) line: 133
MyPackageImpl.init() line: 714
MyPackage.<clinit>() line: 77


If this is performed not only for three packages (as listed above) but
for 150 the 64K of stack size are not sufficient anymore.



SOLUTION PROPOSALS & QUESTIONS
------------------------------

A possible solution would be to simply increase the stack size via the
Xss VM argument. Unfortunately, this does not work for Java 1.5 and I
need to support Java 1.5.

see also: http://bugs.sun.com/view_bug.do?bug_id=6316197


I thought of some options for solving this issue. Unfortunately, my
knowledge of EMF internals is too little to decide if these approaches
are reasonable or not.

1. Reducing the number of interdependencies
The algorithm for calculating the set of inter-depending EPackages could
be optimized.
- Is this a reasonable approach?
- Or is it necessary to always initialize all EPackages as soon as one
EPackage is initialized?
- What is the interdependency initialization required for?

2. Make the Interdependency Initialization Non-Recursive
It could be possible to set a "inDependencyInitialization" flag which is
set by the first EPackage initialized. Subsequent calls to init() in
other EPackages could skip their interdependency initialization.
- Again, is this reasonable?
- Would this approach lead to concurrency problems?

3. Reduce the number of method-calls per initialization
As the EPackageDescriptor accesses the eINSTANCE field within its
getEPackage() method via reflection each EPackage initialization
requires 10 method calls. This number could be reduced by providing a
public getInstance() method for accessing the EPackage instance.
- Why was this complicated way of accessing the EPackage instance via
the eINSTANCE field chosen?
- Could this be substituted by a getInstance() method or would this
introduce concurrency problems?

I would really like to better understand the rational behind the design
decisions made for the EPackage initialization and would appreciate any
feedback on the above proposed solutions and their corresponding questions.

Of course if anyone has a better idea on how to solve this StackOverflow
problem, it is more than welcome.

Thanks and best regards,

Paul
Re: StackOverflowError on EPackage Initialization [message #522453 is a reply to message #522384] Mon, 22 March 2010 16:45 Go to previous message
Ed Merks is currently offline Ed Merks
Messages: 26047
Registered: July 2009
Senior Member
Paul,

It's best to use the EMF newsgroup/forum, for EMF questions. I've added
it to the "to" list of the reply.


Paul Hoser wrote:
> Hi Everybody!
>
> I have a problem with my EMF model. I am getting a StackOverflowError
> when my EPackages are initialized. My model is rather large. It
> consists of about 150 packages each containing at least one classifier.
>
> Within the init() method of an EPackage the inter-depending EPackages
> are initialized recursively. The interdenpendencies of an EPackage are
> calculated by the GenPackageImpl.DependencyHelper. The algorithm looks
> like this:
>
> public DependencyHelper()
> {
> ...
> interDependencies = new ArrayList<GenPackage>();
> collectPackages(interDependencies, getGenModel().getGenPackages(),
> -1);
> interDependencies.remove(GenPackageImpl.this);
> ...
> }
>
>
>
> protected void collectPackages(List<GenPackage> result,
> List<GenPackage> genPackages, int depth)
> {
> if (depth == 0) return;
>
> for (GenPackage genPackage : genPackages)
> {
> if (genPackage.hasClassifiers())
> {
> result.add(genPackage);
> collectPackages(result, genPackage.getNestedGenPackages(),
> depth - 1);
> }
> else
> {
> collectPackages(result, genPackage.getNestedGenPackages(),
> depth);
> }
> }
> }
>
>
> This basically means that all EPackages within the model which contain
> classifiers are inter-depedenent to each other. If we had an example
> model containing three packages (MyPackage, YourPackage, OurPackage)
> we would get generated code like this:
>
>
>
> public class MyPackageImpl extends EPackageImpl implements MyPackage
> {
> ...
> public static MyPackage init() {
> ...
> YourPackageImpl theYourPackage = (YourPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI)
> instanceof YourPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) :
> YourPackage.eINSTANCE);
> OurPackageImpl theOurPackage = (OurPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) instanceof
> OurPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) :
> OurPackage.eINSTANCE);
> ...
> }
> ...
> }
>
> public class YourPackageImpl extends EPackageImpl implements YourPackage
> {
> ...
> public static YourPackage init() {
> ...
> MyPackageImpl theMyPackage = (MyPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) instanceof
> MyPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) :
> MyPackage.eINSTANCE);
> OurPackageImpl theOurPackage = (OurPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) instanceof
> OurPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) :
> OurPackage.eINSTANCE);
> ...
> }
> ...
> }
>
> public class OurPackageImpl extends EPackageImpl implements OurPackage
> {
> ...
> public static OurPackage init() {
> ...
> MyPackageImpl theMyPackage = (MyPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) instanceof
> MyPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) :
> MyPackage.eINSTANCE);
> YourPackageImpl theYourPackage = (YourPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI)
> instanceof YourPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) :
> YourPackage.eINSTANCE);
>
> ...
> }
> ...
> }
>
>
> If we would now access any of these EPackages, for instance the
> MyPackage, via the eINSTANCE field all three packages would be
> initialized recursively and we would get the following stacktrace:
>
> OurPackageImpl.init() line: 655
> OurPackage.<clinit>() line: 75
>
> Unsafe.ensureClassInitialized(Class) line: not available [native
> method]
> UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean) line: 25
> ReflectionFactory.newFieldAccessor(Field, boolean) line: 122
> Field.acquireFieldAccessor(boolean) line: 918
> Field.getFieldAccessor(Object) line: 899
> Field.get(Object) line: 358
> RegistryReader$EPackageDescriptor.getEPackage() line: 274
> EPackageRegistryImpl.getEPackage(String) line: 133
> YourPackageImpl.init() line: 698
> YourPackage.<clinit>() line: 78
>
> Unsafe.ensureClassInitialized(Class) line: not available [native
> method]
> UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean) line: 25
> ReflectionFactory.newFieldAccessor(Field, boolean) line: 122
> Field.acquireFieldAccessor(boolean) line: 918
> Field.getFieldAccessor(Object) line: 899
> Field.get(Object) line: 358
> RegistryReader$EPackageDescriptor.getEPackage() line: 274
> EPackageRegistryImpl.getEPackage(String) line: 133
> MyPackageImpl.init() line: 714
> MyPackage.<clinit>() line: 77
>
>
> If this is performed not only for three packages (as listed above) but
> for 150 the 64K of stack size are not sufficient anymore.
>
>
>
> SOLUTION PROPOSALS & QUESTIONS
> ------------------------------
>
> A possible solution would be to simply increase the stack size via the
> Xss VM argument. Unfortunately, this does not work for Java 1.5 and I
> need to support Java 1.5.
Surely there must be a way to increase the stack size on all JVMs. That
seems like a pretty basic thing.
>
> see also: http://bugs.sun.com/view_bug.do?bug_id=6316197
>
>
> I thought of some options for solving this issue. Unfortunately, my
> knowledge of EMF internals is too little to decide if these approaches
> are reasonable or not.
>
> 1. Reducing the number of interdependencies
> The algorithm for calculating the set of inter-depending EPackages
> could be optimized.
> - Is this a reasonable approach?
Certainly we make assumptions that packages all generated from the same
GenModel are interdependent. We could compute that in more detail...
> - Or is it necessary to always initialize all EPackages as soon as one
> EPackage is initialized?
Only if they are mutually dependent.
> - What is the interdependency initialization required for?
So that the metadata itself can be hooked up properly. Imagine each
package with a class with a feature of a type from the other package.
You'd need to create each package, each class, and each feature, and
then hook up the cross references between them.
>
> 2. Make the Interdependency Initialization Non-Recursive
You need to initialize the things on which you depend before can can
initialize. Each package knows it's own dependencies...
> It could be possible to set a "inDependencyInitialization" flag which
> is set by the first EPackage initialized. Subsequent calls to init()
> in other EPackages could skip their interdependency initialization.
> - Again, is this reasonable?
I'm not sure I follow, but I'd be very reluctant to change a process
that's proven to be a hot spot for unusual bugs.
> - Would this approach lead to concurrency problems?
Without a doubt it would lead to some unanticipated problem...
>
> 3. Reduce the number of method-calls per initialization
> As the EPackageDescriptor accesses the eINSTANCE field within its
> getEPackage() method via reflection each EPackage initialization
> requires 10 method calls. This number could be reduced by providing a
> public getInstance() method for accessing the EPackage instance.
Again, this is scary code the relies on how classes are loaded lazily by
the JVM. The stack size doesn't depend on the size of the method, only
the size of the stack frames which is related to the number of variables....
> - Why was this complicated way of accessing the EPackage instance via
> the eINSTANCE field chosen?
You could look through the bugzilla history for the template to see how
this has evolved based on subtle problems.
> - Could this be substituted by a getInstance() method or would this
> introduce concurrency problems?
>
> I would really like to better understand the rational behind the
> design decisions made for the EPackage initialization and would
> appreciate any feedback on the above proposed solutions and their
> corresponding questions.
> Of course if anyone has a better idea on how to solve this
> StackOverflow problem, it is more than welcome.
>
> Thanks and best regards,
>
> Paul
Are you using nested packages? Is that necessary? How are your packages
separated across GenModels? Do you have three different GenModels?
Re: StackOverflowError on EPackage Initialization [message #619491 is a reply to message #522384] Mon, 22 March 2010 16:45 Go to previous message
Ed Merks is currently offline Ed Merks
Messages: 26047
Registered: July 2009
Senior Member
Paul,

It's best to use the EMF newsgroup/forum, for EMF questions. I've added
it to the "to" list of the reply.


Paul Hoser wrote:
> Hi Everybody!
>
> I have a problem with my EMF model. I am getting a StackOverflowError
> when my EPackages are initialized. My model is rather large. It
> consists of about 150 packages each containing at least one classifier.
>
> Within the init() method of an EPackage the inter-depending EPackages
> are initialized recursively. The interdenpendencies of an EPackage are
> calculated by the GenPackageImpl.DependencyHelper. The algorithm looks
> like this:
>
> public DependencyHelper()
> {
> ...
> interDependencies = new ArrayList<GenPackage>();
> collectPackages(interDependencies, getGenModel().getGenPackages(),
> -1);
> interDependencies.remove(GenPackageImpl.this);
> ...
> }
>
>
>
> protected void collectPackages(List<GenPackage> result,
> List<GenPackage> genPackages, int depth)
> {
> if (depth == 0) return;
>
> for (GenPackage genPackage : genPackages)
> {
> if (genPackage.hasClassifiers())
> {
> result.add(genPackage);
> collectPackages(result, genPackage.getNestedGenPackages(),
> depth - 1);
> }
> else
> {
> collectPackages(result, genPackage.getNestedGenPackages(),
> depth);
> }
> }
> }
>
>
> This basically means that all EPackages within the model which contain
> classifiers are inter-depedenent to each other. If we had an example
> model containing three packages (MyPackage, YourPackage, OurPackage)
> we would get generated code like this:
>
>
>
> public class MyPackageImpl extends EPackageImpl implements MyPackage
> {
> ...
> public static MyPackage init() {
> ...
> YourPackageImpl theYourPackage = (YourPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI)
> instanceof YourPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) :
> YourPackage.eINSTANCE);
> OurPackageImpl theOurPackage = (OurPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) instanceof
> OurPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) :
> OurPackage.eINSTANCE);
> ...
> }
> ...
> }
>
> public class YourPackageImpl extends EPackageImpl implements YourPackage
> {
> ...
> public static YourPackage init() {
> ...
> MyPackageImpl theMyPackage = (MyPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) instanceof
> MyPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) :
> MyPackage.eINSTANCE);
> OurPackageImpl theOurPackage = (OurPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) instanceof
> OurPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(OurPackage.eNS_URI) :
> OurPackage.eINSTANCE);
> ...
> }
> ...
> }
>
> public class OurPackageImpl extends EPackageImpl implements OurPackage
> {
> ...
> public static OurPackage init() {
> ...
> MyPackageImpl theMyPackage = (MyPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) instanceof
> MyPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(MyPackage.eNS_URI) :
> MyPackage.eINSTANCE);
> YourPackageImpl theYourPackage = (YourPackageImpl)
> (EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI)
> instanceof YourPackageImpl ?
> EPackage.Registry.INSTANCE.getEPackage(YourPackage.eNS_URI) :
> YourPackage.eINSTANCE);
>
> ...
> }
> ...
> }
>
>
> If we would now access any of these EPackages, for instance the
> MyPackage, via the eINSTANCE field all three packages would be
> initialized recursively and we would get the following stacktrace:
>
> OurPackageImpl.init() line: 655
> OurPackage.<clinit>() line: 75
>
> Unsafe.ensureClassInitialized(Class) line: not available [native
> method]
> UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean) line: 25
> ReflectionFactory.newFieldAccessor(Field, boolean) line: 122
> Field.acquireFieldAccessor(boolean) line: 918
> Field.getFieldAccessor(Object) line: 899
> Field.get(Object) line: 358
> RegistryReader$EPackageDescriptor.getEPackage() line: 274
> EPackageRegistryImpl.getEPackage(String) line: 133
> YourPackageImpl.init() line: 698
> YourPackage.<clinit>() line: 78
>
> Unsafe.ensureClassInitialized(Class) line: not available [native
> method]
> UnsafeFieldAccessorFactory.newFieldAccessor(Field, boolean) line: 25
> ReflectionFactory.newFieldAccessor(Field, boolean) line: 122
> Field.acquireFieldAccessor(boolean) line: 918
> Field.getFieldAccessor(Object) line: 899
> Field.get(Object) line: 358
> RegistryReader$EPackageDescriptor.getEPackage() line: 274
> EPackageRegistryImpl.getEPackage(String) line: 133
> MyPackageImpl.init() line: 714
> MyPackage.<clinit>() line: 77
>
>
> If this is performed not only for three packages (as listed above) but
> for 150 the 64K of stack size are not sufficient anymore.
>
>
>
> SOLUTION PROPOSALS & QUESTIONS
> ------------------------------
>
> A possible solution would be to simply increase the stack size via the
> Xss VM argument. Unfortunately, this does not work for Java 1.5 and I
> need to support Java 1.5.
Surely there must be a way to increase the stack size on all JVMs. That
seems like a pretty basic thing.
>
> see also: http://bugs.sun.com/view_bug.do?bug_id=6316197
>
>
> I thought of some options for solving this issue. Unfortunately, my
> knowledge of EMF internals is too little to decide if these approaches
> are reasonable or not.
>
> 1. Reducing the number of interdependencies
> The algorithm for calculating the set of inter-depending EPackages
> could be optimized.
> - Is this a reasonable approach?
Certainly we make assumptions that packages all generated from the same
GenModel are interdependent. We could compute that in more detail...
> - Or is it necessary to always initialize all EPackages as soon as one
> EPackage is initialized?
Only if they are mutually dependent.
> - What is the interdependency initialization required for?
So that the metadata itself can be hooked up properly. Imagine each
package with a class with a feature of a type from the other package.
You'd need to create each package, each class, and each feature, and
then hook up the cross references between them.
>
> 2. Make the Interdependency Initialization Non-Recursive
You need to initialize the things on which you depend before can can
initialize. Each package knows it's own dependencies...
> It could be possible to set a "inDependencyInitialization" flag which
> is set by the first EPackage initialized. Subsequent calls to init()
> in other EPackages could skip their interdependency initialization.
> - Again, is this reasonable?
I'm not sure I follow, but I'd be very reluctant to change a process
that's proven to be a hot spot for unusual bugs.
> - Would this approach lead to concurrency problems?
Without a doubt it would lead to some unanticipated problem...
>
> 3. Reduce the number of method-calls per initialization
> As the EPackageDescriptor accesses the eINSTANCE field within its
> getEPackage() method via reflection each EPackage initialization
> requires 10 method calls. This number could be reduced by providing a
> public getInstance() method for accessing the EPackage instance.
Again, this is scary code the relies on how classes are loaded lazily by
the JVM. The stack size doesn't depend on the size of the method, only
the size of the stack frames which is related to the number of variables....
> - Why was this complicated way of accessing the EPackage instance via
> the eINSTANCE field chosen?
You could look through the bugzilla history for the template to see how
this has evolved based on subtle problems.
> - Could this be substituted by a getInstance() method or would this
> introduce concurrency problems?
>
> I would really like to better understand the rational behind the
> design decisions made for the EPackage initialization and would
> appreciate any feedback on the above proposed solutions and their
> corresponding questions.
> Of course if anyone has a better idea on how to solve this
> StackOverflow problem, it is more than welcome.
>
> Thanks and best regards,
>
> Paul
Are you using nested packages? Is that necessary? How are your packages
separated across GenModels? Do you have three different GenModels?
Previous Topic:StackOverflowError on EPackage Initialization
Next Topic:Eclipse Modeling GMF Files
Goto Forum:
  


Current Time: Tue Sep 16 23:52:00 GMT 2014

Powered by FUDForum. Page generated in 0.09400 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software